blob: 38c47a3253d29560d1bd84ae4c76cbaa62f81c5b [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
Maxa5e36932017-01-11 11:51:28 +010040#include <osmocom/gsm/protocol/gsm_12_21.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010041#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020042#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010043#include <osmocom/core/talloc.h>
Neels Hofmeyr93bafb62017-01-13 03:12:08 +010044#include <osmocom/core/utils.h>
Harald Welte8470bf22008-12-25 23:28:35 +000045#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000046#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000047#include <openbsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020048#include <osmocom/abis/e1_input.h>
Harald Welte52b1f982008-12-23 20:25:15 +000049
Harald Welte8470bf22008-12-25 23:28:35 +000050#define OM_ALLOC_SIZE 1024
51#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010052#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000053
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020054int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +000055{
Harald Welte39315c42010-01-10 18:01:52 +010056 if (!bts->model)
57 return -EIO;
58 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000059}
Harald Weltee0590df2009-02-15 03:34:15 +000060
Harald Welte52b1f982008-12-23 20:25:15 +000061static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
62{
63 int i;
64
65 for (i = 0; i < size; i++) {
66 if (arr[i] == mt)
67 return 1;
68 }
69
70 return 0;
71}
72
Holger Freytherca362a62009-01-04 21:05:01 +000073#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000074/* is this msgtype the usual ACK/NACK type ? */
75static int is_ack_nack(enum abis_nm_msgtype mt)
76{
77 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
78}
Holger Freytherca362a62009-01-04 21:05:01 +000079#endif
Harald Welte52b1f982008-12-23 20:25:15 +000080
81/* is this msgtype a report ? */
82static int is_report(enum abis_nm_msgtype mt)
83{
Harald Welte15c61722011-05-22 22:45:37 +020084 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000085}
86
87#define MT_ACK(x) (x+1)
88#define MT_NACK(x) (x+2)
89
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020090static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000091{
92 oh->mdisc = ABIS_OM_MDISC_FOM;
93 oh->placement = ABIS_OM_PLACEMENT_ONLY;
94 oh->sequence = 0;
95 oh->length = len;
96}
97
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +020098static struct abis_om_fom_hdr *fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020099 uint8_t msg_type, uint8_t obj_class,
100 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000101{
102 struct abis_om_fom_hdr *foh =
103 (struct abis_om_fom_hdr *) oh->data;
104
Harald Welte702d8702008-12-26 20:25:35 +0000105 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000106 foh->msg_type = msg_type;
107 foh->obj_class = obj_class;
108 foh->obj_inst.bts_nr = bts_nr;
109 foh->obj_inst.trx_nr = trx_nr;
110 foh->obj_inst.ts_nr = ts_nr;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200111 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000112}
113
Harald Welte8470bf22008-12-25 23:28:35 +0000114static struct msgb *nm_msgb_alloc(void)
115{
Harald Welte966636f2009-06-26 19:39:35 +0200116 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
117 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000118}
119
Harald Welte15eae8d2011-09-26 23:43:23 +0200120int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200121{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200122 msg->l2h = msg->data;
123
124 if (!msg->dst) {
125 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
126 return -EINVAL;
127 }
128
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200129 return abis_sendmsg(msg);
130}
131
Harald Welte52b1f982008-12-23 20:25:15 +0000132/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100133static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000134{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200135 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000136
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100137 /* queue OML messages */
138 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
139 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200140 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100141 } else {
142 msgb_enqueue(&bts->abis_queue, msg);
143 return 0;
144 }
145
146}
147
148int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
149{
150 OBSC_NM_W_ACK_CB(msg) = 1;
151 return abis_nm_queue_msg(bts, msg);
152}
153
154static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
155{
156 OBSC_NM_W_ACK_CB(msg) = 0;
157 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000158}
159
Harald Welte4724f992009-01-18 18:01:49 +0000160static int abis_nm_rcvmsg_sw(struct msgb *mb);
161
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100162int nm_is_running(struct gsm_nm_state *s) {
163 return (s->operational == NM_OPSTATE_ENABLED) && (
164 (s->availability == NM_AVSTATE_OK) ||
165 (s->availability == 0xff)
166 );
167}
168
Harald Weltee0590df2009-02-15 03:34:15 +0000169/* Update the administrative state of a given object in our in-memory data
170 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200171static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
172 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000173{
Harald Welteaeedeb42009-05-01 13:08:14 +0000174 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100175 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000176
Harald Welteaf9b8102011-03-06 21:20:38 +0100177 memset(&nsd, 0, sizeof(nsd));
178
Harald Welte978714d2011-06-06 18:31:20 +0200179 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100180 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100181 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200182 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000183 if (!nm_state)
184 return -1;
185
186 new_state = *nm_state;
187 new_state.administrative = adm_state;
188
Harald Weltef38ca9a2011-03-06 22:11:32 +0100189 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100190 nsd.obj_class = obj_class;
191 nsd.old_state = nm_state;
192 nsd.new_state = &new_state;
193 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200194 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000195
196 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000197
Harald Weltef338a032011-01-14 15:55:42 +0100198 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000199}
200
Harald Welte97ed1e72009-02-06 13:38:02 +0000201static int abis_nm_rx_statechg_rep(struct msgb *mb)
202{
Harald Weltee0590df2009-02-15 03:34:15 +0000203 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000204 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200205 struct e1inp_sign_link *sign_link = mb->dst;
206 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000207 struct tlv_parsed tp;
208 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000209
Harald Welte23897662009-05-01 14:52:51 +0000210 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000211
Harald Welte8b697c72009-06-05 19:18:45 +0000212 memset(&new_state, 0, sizeof(new_state));
213
Harald Welte978714d2011-06-06 18:31:20 +0200214 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000215 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100216 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000217 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000218 }
Harald Weltee0590df2009-02-15 03:34:15 +0000219
220 new_state = *nm_state;
221
Harald Welte39315c42010-01-10 18:01:52 +0100222 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000223 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
224 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200225 DEBUGPC(DNM, "OP_STATE=%s ",
226 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000227 }
228 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000229 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
230 new_state.availability = 0xff;
231 else
232 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200233 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
234 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000235 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100236 } else
237 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000238 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
239 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200240 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200241 get_value_string(abis_nm_adm_state_names,
242 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000243 }
244 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000245
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100246 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
247 new_state.operational != nm_state->operational ||
248 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000249 /* Update the operational state of a given object in our in-memory data
250 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100251 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200252 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100253 nsd.obj_class = foh->obj_class;
254 nsd.old_state = nm_state;
255 nsd.new_state = &new_state;
256 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100257 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200258 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100259 nm_state->operational = new_state.operational;
260 nm_state->availability = new_state.availability;
261 if (nm_state->administrative == 0)
262 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000263 }
264#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000265 if (op_state == 1) {
266 /* try to enable objects that are disabled */
267 abis_nm_opstart(bts, foh->obj_class,
268 foh->obj_inst.bts_nr,
269 foh->obj_inst.trx_nr,
270 foh->obj_inst.ts_nr);
271 }
Harald Weltee0590df2009-02-15 03:34:15 +0000272#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000273 return 0;
274}
275
Maxb1e6b372017-03-15 14:30:21 +0100276static inline void log_oml_fail_rep(const struct gsm_bts *bts, const char *type,
277 const char *severity, const uint8_t *p_val,
278 const char *text)
279{
280 enum abis_nm_pcause_type pcause = p_val[0];
281 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
282
283 LOGPC(DNM, LOGL_ERROR, "BTS %u: Failure Event Report: ", bts->nr);
284 if (type)
285 LOGPC(DNM, LOGL_ERROR, "Type=%s, ", type);
286 if (severity)
287 LOGPC(DNM, LOGL_ERROR, "Severity=%s, ", severity);
288
289 LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ",
290 get_value_string(abis_nm_pcause_type_names, pcause));
291
292 if (pcause == NM_PCAUSE_T_MANUF)
293 LOGPC(DNM, LOGL_ERROR, "%s, ",
294 get_value_string(abis_mm_event_cause_names, cause));
295 else
296 LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]);
297
298 if (text) {
299 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", text);
300 }
301
302 LOGPC(DNM, LOGL_ERROR, "\n");
303}
304
Maxa18001d2017-04-10 16:47:17 +0200305static inline void handle_manufact_report(struct gsm_bts *bts, const uint8_t *p_val, const char *type,
Maxb1e6b372017-03-15 14:30:21 +0100306 const char *severity, const char *text)
307{
308 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
309
310 switch (cause) {
311 case OSMO_EVT_PCU_VERS:
Maxa18001d2017-04-10 16:47:17 +0200312 if (text) {
313 LOGPC(DNM, LOGL_NOTICE, "BTS %u reported connected PCU version %s\n", bts->nr, text);
314 osmo_strlcpy(bts->pcu_version, text, sizeof(bts->pcu_version));
315 } else {
316 LOGPC(DNM, LOGL_ERROR, "BTS %u reported PCU disconnection.\n", bts->nr);
317 bts->pcu_version[0] = '\0';
318 }
Maxb1e6b372017-03-15 14:30:21 +0100319 break;
320 default:
321 log_oml_fail_rep(bts, type, severity, p_val, text);
322 };
323}
324
Maxa18001d2017-04-10 16:47:17 +0200325static int rx_fail_evt_rep(struct msgb *mb, struct gsm_bts *bts)
Harald Welte0db97b22009-05-01 17:22:47 +0000326{
327 struct abis_om_hdr *oh = msgb_l2(mb);
328 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200329 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000330 struct tlv_parsed tp;
Maxb1e6b372017-03-15 14:30:21 +0100331 int rc = 0;
332 const uint8_t *p_val = NULL;
333 char *p_text = NULL;
334 const char *e_type = NULL, *severity = NULL;
Harald Welte0db97b22009-05-01 17:22:47 +0000335
Maxb1e6b372017-03-15 14:30:21 +0100336 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data,
337 oh->length-sizeof(*foh));
Maxa5e36932017-01-11 11:51:28 +0100338
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100339 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
340 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
Maxb1e6b372017-03-15 14:30:21 +0100341 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val,
342 TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100343 }
Harald Welte0db97b22009-05-01 17:22:47 +0000344
Maxb1e6b372017-03-15 14:30:21 +0100345 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
346 e_type = abis_nm_event_type_name(*TLVP_VAL(&tp,
347 NM_ATT_EVENT_TYPE));
Harald Welte0db97b22009-05-01 17:22:47 +0000348
Maxb1e6b372017-03-15 14:30:21 +0100349 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
350 severity = abis_nm_severity_name(*TLVP_VAL(&tp,
351 NM_ATT_SEVERITY));
352
353 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
354 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
355
356 switch (p_val[0]) {
357 case NM_PCAUSE_T_MANUF:
358 handle_manufact_report(bts, p_val, e_type, severity,
359 p_text);
360 break;
361 default:
362 log_oml_fail_rep(bts, e_type, severity, p_val, p_text);
363 };
364 } else {
365 LOGPC(DNM, LOGL_ERROR, "BTS%u: Failure Event Report without "
366 "Probable Cause?!\n", bts->nr);
367 rc = -EINVAL;
368 }
369
370 if (p_text)
371 talloc_free(p_text);
372
373 return rc;
Harald Welte0db97b22009-05-01 17:22:47 +0000374}
375
Maxb1e6b372017-03-15 14:30:21 +0100376static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts)
Harald Welte97ed1e72009-02-06 13:38:02 +0000377{
378 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200379 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000380
Harald Welte15c61722011-05-22 22:45:37 +0200381 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000382
Harald Welte97ed1e72009-02-06 13:38:02 +0000383 //nmh->cfg->report_cb(mb, foh);
384
385 switch (mt) {
386 case NM_MT_STATECHG_EVENT_REP:
387 return abis_nm_rx_statechg_rep(mb);
388 break;
Harald Welte34a99682009-02-13 02:41:40 +0000389 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000390 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200391 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000392 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000393 case NM_MT_FAILURE_EVENT_REP:
Maxb1e6b372017-03-15 14:30:21 +0100394 rx_fail_evt_rep(mb, bts);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200395 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000396 break;
Harald Weltec7310382009-08-08 00:02:36 +0200397 case NM_MT_TEST_REP:
398 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200399 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200400 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000401 default:
Harald Welte23897662009-05-01 14:52:51 +0000402 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000403 break;
404
Harald Welte97ed1e72009-02-06 13:38:02 +0000405 };
406
Harald Welte97ed1e72009-02-06 13:38:02 +0000407 return 0;
408}
409
Harald Welte34a99682009-02-13 02:41:40 +0000410/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200411static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
Maxfd2c1f92017-03-24 21:04:57 +0100412 uint8_t i2, const struct abis_nm_sw_desc *sw_desc)
Harald Welte34a99682009-02-13 02:41:40 +0000413{
414 struct abis_om_hdr *oh;
415 struct msgb *msg = nm_msgb_alloc();
Maxfd2c1f92017-03-24 21:04:57 +0100416 uint16_t len = abis_nm_sw_desc_len(sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000417
418 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
419 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
Maxfd2c1f92017-03-24 21:04:57 +0100420 abis_nm_put_sw_desc(msg, sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000421
422 return abis_nm_sendmsg(bts, msg);
423}
424
Maxfd2c1f92017-03-24 21:04:57 +0100425int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw_descr,
426 const size_t size)
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100427{
428 int res = 0;
429 int i;
430
431 for (i = 1; i < size; ++i) {
Maxfd2c1f92017-03-24 21:04:57 +0100432 if (memcmp(sw_descr[res].file_version, sw_descr[i].file_version,
433 OSMO_MIN(sw_descr[i].file_version_len,
434 sw_descr[res].file_version_len)) < 0) {
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100435 res = i;
436 }
437 }
438
439 return res;
440}
441
Max33e13572017-05-29 11:48:29 +0200442static inline bool handle_attr(const struct gsm_bts *bts, enum bts_attribute id, uint8_t *val, uint8_t len)
Maxdefb6c92017-05-15 10:29:54 +0200443{
444 switch (id) {
445 case BTS_TYPE_VARIANT:
Max33e13572017-05-29 11:48:29 +0200446 LOGP(DNM, LOGL_NOTICE, "BTS%u reported variant: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200447 break;
448 case BTS_SUB_MODEL:
Max33e13572017-05-29 11:48:29 +0200449 LOGP(DNM, LOGL_NOTICE, "BTS%u reported submodel: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200450 break;
451 default:
452 return false;
453 }
454 return true;
455}
456
Max33e13572017-05-29 11:48:29 +0200457/* Parse Attribute Response Info - return pointer to the actual content */
458static inline uint8_t *parse_attr_resp_info_unreported(uint8_t bts_nr, uint8_t *ari, uint16_t ari_len, uint16_t *out_len)
459{
460 uint8_t num_unreported = ari[0], i;
461
462 DEBUGP(DNM, "BTS%u Get Attributes Response Info: %u bytes total with %u unreported attributes\n",
463 bts_nr, ari_len, num_unreported);
464
465 /* +1 because we have to account for number of unreported attributes, prefixing the list: */
466 for (i = 0; i < num_unreported; i++)
467 LOGP(DNM, LOGL_ERROR, "BTS%u Attribute %s is unreported\n",
468 bts_nr, get_value_string(abis_nm_att_names, ari[i + 1]));
469
470 /* the data starts right after the list of unreported attributes + space for length of that list */
471 *out_len = ari_len - (num_unreported + 2);
472
473 return ari + num_unreported + 1; /* we have to account for 1st byte with number of unreported attributes */
474}
475
476/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.28 Manufacturer Dependent State */
477static inline uint8_t *parse_attr_resp_info_manuf_state(const struct gsm_bts_trx *trx, uint8_t *data, uint16_t *data_len)
478{
479 struct tlv_parsed tp;
480 const uint8_t *power;
481 uint8_t adjust = 0;
482
483 if (!trx) /* this attribute does not make sense on BTS level, only on TRX level */
484 return data;
485
486 abis_nm_tlv_parse(&tp, trx->bts, data, *data_len);
487 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_STATE, 1)) {
488 power = TLVP_VAL(&tp, NM_ATT_MANUF_STATE);
489 LOGP(DNM, LOGL_NOTICE, "%s Get Attributes Response: nominal power is %u\n", gsm_trx_name(trx), *power);
490 adjust = 2; /* adjust for parsed TV struct */
491 }
492
493 *data_len -= adjust;
494
495 return data + adjust;
496}
497
Maxdefb6c92017-05-15 10:29:54 +0200498/* Handle 3GPP TS 52.021 §9.4.64 Get Attribute Response Info */
Max33e13572017-05-29 11:48:29 +0200499static int abis_nm_rx_get_attr_resp(struct msgb *mb, const struct gsm_bts_trx *trx)
Maxdefb6c92017-05-15 10:29:54 +0200500{
501 struct abis_om_hdr *oh = msgb_l2(mb);
502 struct abis_om_fom_hdr *foh = msgb_l3(mb);
503 struct e1inp_sign_link *sign_link = mb->dst;
Max33e13572017-05-29 11:48:29 +0200504 struct gsm_bts *bts = trx ? trx->bts : sign_link->trx->bts;
Maxdefb6c92017-05-15 10:29:54 +0200505 struct tlv_parsed tp;
Max33e13572017-05-29 11:48:29 +0200506 uint8_t *data, i;
507 uint16_t data_len;
Maxdefb6c92017-05-15 10:29:54 +0200508 int rc;
509 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
510
511 abis_nm_debugp_foh(DNM, foh);
512
Max33e13572017-05-29 11:48:29 +0200513 DEBUGPC(DNM, "Get Attributes Response for BTS%u\n", bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200514
Max33e13572017-05-29 11:48:29 +0200515 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
516 if (!TLVP_PRES_LEN(&tp, NM_ATT_GET_ARI, 1)) {
517 LOGP(DNM, LOGL_ERROR, "BTS%u: Get Attributes Response without Response Info?!\n", bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200518 return -EINVAL;
519 }
520
Max33e13572017-05-29 11:48:29 +0200521 data = parse_attr_resp_info_unreported(bts->nr, TLVP_VAL(&tp, NM_ATT_GET_ARI), TLVP_LEN(&tp, NM_ATT_GET_ARI),
522 &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200523
Max33e13572017-05-29 11:48:29 +0200524 data = parse_attr_resp_info_manuf_state(trx, data, &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200525
Max33e13572017-05-29 11:48:29 +0200526 /* after parsing manufacturer-specific attributes there's list of replies in form of sw-conf structure: */
527 rc = abis_nm_get_sw_conf(data, data_len, &sw_descr[0], ARRAY_SIZE(sw_descr));
Maxdefb6c92017-05-15 10:29:54 +0200528 if (rc > 0) {
529 for (i = 0; i < rc; i++) {
Max33e13572017-05-29 11:48:29 +0200530 if (!handle_attr(bts, str2btsattr((const char *)sw_descr[i].file_id),
531 sw_descr[i].file_version, sw_descr[i].file_version_len))
532 LOGP(DNM, LOGL_NOTICE, "BTS%u: ARI reported sw[%d/%d]: %s is %s\n",
533 bts->nr, i, rc, sw_descr[i].file_id, sw_descr[i].file_version);
Maxdefb6c92017-05-15 10:29:54 +0200534 }
535 } else
Max33e13572017-05-29 11:48:29 +0200536 LOGP(DNM, LOGL_ERROR, "BTS%u: failed to parse SW-Config part of Get Attribute Response Info: %s\n",
537 bts->nr, strerror(-rc));
Maxdefb6c92017-05-15 10:29:54 +0200538
539 return 0;
540}
541
Max1ebf23b2017-05-10 12:21:17 +0200542/* 3GPP TS 52.021 §6.2.5 */
Harald Welte34a99682009-02-13 02:41:40 +0000543static int abis_nm_rx_sw_act_req(struct msgb *mb)
544{
545 struct abis_om_hdr *oh = msgb_l2(mb);
546 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200547 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200548 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200549 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100550 int ret, sw_config_len, len;
Max1ebf23b2017-05-10 12:21:17 +0200551 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
Harald Welte34a99682009-02-13 02:41:40 +0000552
Harald Welte15c61722011-05-22 22:45:37 +0200553 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200554
555 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000556
Harald Welte97a282b2010-03-14 15:37:43 +0800557 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000558
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200559 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000560 foh->obj_inst.bts_nr,
561 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800562 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000563 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100564 if (ret != 0) {
565 LOGP(DNM, LOGL_ERROR,
566 "Sending SW ActReq ACK failed: %d\n", ret);
567 return ret;
568 }
Harald Welte34a99682009-02-13 02:41:40 +0000569
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200570 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200571 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
572 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
573 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100574 LOGP(DNM, LOGL_ERROR,
575 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200576 return -EINVAL;
577 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200578 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200579 }
580
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100581 /* Parse up to two sw descriptions from the data */
Maxfd2c1f92017-03-24 21:04:57 +0100582 len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
583 ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100584 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100585 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100586 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100587 }
Mike Habena03f9772009-10-01 14:56:13 +0200588
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100589 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
590 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
591
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200592 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000593 foh->obj_inst.bts_nr,
594 foh->obj_inst.trx_nr,
595 foh->obj_inst.ts_nr,
Maxfd2c1f92017-03-24 21:04:57 +0100596 &sw_descr[ret]);
Harald Welte34a99682009-02-13 02:41:40 +0000597}
598
Harald Weltee0590df2009-02-15 03:34:15 +0000599/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
600static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
601{
602 struct abis_om_hdr *oh = msgb_l2(mb);
603 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200604 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000605 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200606 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000607
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200608 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000609 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
610 return -EINVAL;
611
612 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
613
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200614 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000615}
616
Harald Welteee670472009-02-22 21:58:49 +0000617static int abis_nm_rx_lmt_event(struct msgb *mb)
618{
619 struct abis_om_hdr *oh = msgb_l2(mb);
620 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200621 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000622 struct tlv_parsed tp;
623
624 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200625 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000626 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
627 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200628 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000629 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
630 }
631 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
632 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200633 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000634 DEBUGPC(DNM, "Level=%u ", level);
635 }
636 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
637 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
638 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
639 DEBUGPC(DNM, "Username=%s ", name);
640 }
641 DEBUGPC(DNM, "\n");
642 /* FIXME: parse LMT LOGON TIME */
643 return 0;
644}
645
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200646void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100647{
648 int wait = 0;
649 struct msgb *msg;
650 /* the queue is empty */
651 while (!llist_empty(&bts->abis_queue)) {
652 msg = msgb_dequeue(&bts->abis_queue);
653 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200654 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100655
656 if (wait)
657 break;
658 }
659
660 bts->abis_nm_pend = wait;
661}
662
Harald Welte52b1f982008-12-23 20:25:15 +0000663/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000664static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000665{
Harald Welte6c96ba52009-05-01 13:03:40 +0000666 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000667 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200668 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200669 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100670 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
671 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100672 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000673
674 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000675 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100676 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000677
Harald Welte15c61722011-05-22 22:45:37 +0200678 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000679 return abis_nm_rcvmsg_sw(mb);
680
Harald Welte15c61722011-05-22 22:45:37 +0200681 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800682 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000683 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200684
Harald Welte15c61722011-05-22 22:45:37 +0200685 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200686
Harald Welte15c61722011-05-22 22:45:37 +0200687 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000688
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100689 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000690 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200691 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200692 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000693 else
694 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200695
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800696 nack_data.msg = mb;
697 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100698 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200699 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100700 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200701 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000702 }
Harald Weltead384642008-12-26 10:20:07 +0000703#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000704 /* check if last message is to be acked */
705 if (is_ack_nack(nmh->last_msgtype)) {
706 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100707 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000708 /* we got our ACK, continue sending the next msg */
709 } else if (mt == MT_NACK(nmh->last_msgtype)) {
710 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100711 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000712 /* FIXME: somehow signal this to the caller */
713 } else {
714 /* really strange things happen */
715 return -EINVAL;
716 }
717 }
Harald Weltead384642008-12-26 10:20:07 +0000718#endif
719
Harald Welte97ed1e72009-02-06 13:38:02 +0000720 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000721 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100722 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000723 break;
Harald Welte34a99682009-02-13 02:41:40 +0000724 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100725 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000726 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000727 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100728 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000729 break;
Max689e7e52017-04-04 19:21:24 +0200730 case NM_MT_OPSTART_ACK:
731 abis_nm_debugp_foh(DNM, foh);
732 DEBUGPC(DNM, "Opstart ACK\n");
733 break;
734 case NM_MT_SET_CHAN_ATTR_ACK:
735 abis_nm_debugp_foh(DNM, foh);
736 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
737 break;
738 case NM_MT_SET_RADIO_ATTR_ACK:
739 abis_nm_debugp_foh(DNM, foh);
740 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
741 break;
Harald Welte1989c082009-08-06 17:58:31 +0200742 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200743 abis_nm_debugp_foh(DNM, foh);
744 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200745 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100746 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200747 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100748 break;
749 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200750 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100751 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100752 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100753 break;
Maxdefb6c92017-05-15 10:29:54 +0200754 case NM_MT_GET_ATTR_RESP:
Max33e13572017-05-29 11:48:29 +0200755 ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
Maxdefb6c92017-05-15 10:29:54 +0200756 break;
Max689e7e52017-04-04 19:21:24 +0200757 default:
758 abis_nm_debugp_foh(DNM, foh);
759 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
760 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000761 }
762
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100763 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100764 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000765}
766
Harald Welte677c21f2009-02-17 13:22:23 +0000767static int abis_nm_rx_ipacc(struct msgb *mb);
768
769static int abis_nm_rcvmsg_manuf(struct msgb *mb)
770{
771 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200772 struct e1inp_sign_link *sign_link = mb->dst;
773 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000774
775 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100776 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100777 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000778 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200779 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000780 break;
781 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100782 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
783 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000784 rc = 0;
785 break;
786 }
787
788 return rc;
789}
790
Harald Welte52b1f982008-12-23 20:25:15 +0000791/* High-Level API */
792/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000793int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000794{
Harald Welte52b1f982008-12-23 20:25:15 +0000795 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000796 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000797
798 /* Various consistency checks */
799 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100800 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000801 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200802 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
803 rc = -EINVAL;
804 goto err;
805 }
Harald Welte52b1f982008-12-23 20:25:15 +0000806 }
807 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100808 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000809 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200810 rc = -EINVAL;
811 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000812 }
Harald Welte702d8702008-12-26 20:25:35 +0000813#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200814 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000815 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000816 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100817 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000818 oh->length + sizeof(*oh), l2_len);
819 return -EINVAL;
820 }
Harald Welte702d8702008-12-26 20:25:35 +0000821 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100822 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 +0000823#endif
Harald Weltead384642008-12-26 10:20:07 +0000824 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000825
826 switch (oh->mdisc) {
827 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000828 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000829 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000830 case ABIS_OM_MDISC_MANUF:
831 rc = abis_nm_rcvmsg_manuf(msg);
832 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000833 case ABIS_OM_MDISC_MMI:
834 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100835 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000836 oh->mdisc);
837 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000838 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100839 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000840 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200841 rc = -EINVAL;
842 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000843 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200844err:
Harald Weltead384642008-12-26 10:20:07 +0000845 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000846 return rc;
847}
848
849#if 0
850/* initialized all resources */
851struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
852{
853 struct abis_nm_h *nmh;
854
855 nmh = malloc(sizeof(*nmh));
856 if (!nmh)
857 return NULL;
858
859 nmh->cfg = cfg;
860
861 return nmh;
862}
863
864/* free all resources */
865void abis_nm_fini(struct abis_nm_h *nmh)
866{
867 free(nmh);
868}
869#endif
870
871/* Here we are trying to define a high-level API that can be used by
872 * the actual BSC implementation. However, the architecture is currently
873 * still under design. Ideally the calls to this API would be synchronous,
874 * while the underlying stack behind the APi runs in a traditional select
875 * based state machine.
876 */
877
Harald Welte4724f992009-01-18 18:01:49 +0000878/* 6.2 Software Load: */
879enum sw_state {
880 SW_STATE_NONE,
881 SW_STATE_WAIT_INITACK,
882 SW_STATE_WAIT_SEGACK,
883 SW_STATE_WAIT_ENDACK,
884 SW_STATE_WAIT_ACTACK,
885 SW_STATE_ERROR,
886};
Harald Welte52b1f982008-12-23 20:25:15 +0000887
Harald Welte52b1f982008-12-23 20:25:15 +0000888struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000889 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800890 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000891 gsm_cbfn *cbfn;
892 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000893 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000894
Harald Welte52b1f982008-12-23 20:25:15 +0000895 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200896 uint8_t obj_class;
897 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000898
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200899 uint8_t file_id[255];
900 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000901
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200902 uint8_t file_version[255];
903 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000904
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200905 uint8_t window_size;
906 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000907
908 int fd;
909 FILE *stream;
910 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000911 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000912};
913
Harald Welte4724f992009-01-18 18:01:49 +0000914static struct abis_nm_sw g_sw;
915
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100916static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
917{
918 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
919 msgb_v_put(msg, NM_ATT_SW_DESCR);
920 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
921 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
922 sw->file_version);
923 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
924 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
925 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
926 sw->file_version);
927 } else {
928 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
929 }
930}
931
Harald Welte4724f992009-01-18 18:01:49 +0000932/* 6.2.1 / 8.3.1: Load Data Initiate */
933static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000934{
Harald Welte4724f992009-01-18 18:01:49 +0000935 struct abis_om_hdr *oh;
936 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200937 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000938
939 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
940 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
941 sw->obj_instance[0], sw->obj_instance[1],
942 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100943
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100944 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000945 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
946
947 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000948}
949
Harald Welte1602ade2009-01-29 21:12:39 +0000950static int is_last_line(FILE *stream)
951{
952 char next_seg_buf[256];
953 long pos;
954
955 /* check if we're sending the last line */
956 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200957
958 /* Did ftell fail? Then we are at the end for sure */
959 if (pos < 0)
960 return 1;
961
Harald Welte1602ade2009-01-29 21:12:39 +0000962 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +0100963 int rc = fseek(stream, pos, SEEK_SET);
964 if (rc < 0)
965 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000966 return 1;
967 }
968
969 fseek(stream, pos, SEEK_SET);
970 return 0;
971}
972
Harald Welte4724f992009-01-18 18:01:49 +0000973/* 6.2.2 / 8.3.2 Load Data Segment */
974static int sw_load_segment(struct abis_nm_sw *sw)
975{
976 struct abis_om_hdr *oh;
977 struct msgb *msg = nm_msgb_alloc();
978 char seg_buf[256];
979 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000980 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200981 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000982
983 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000984
985 switch (sw->bts->type) {
986 case GSM_BTS_TYPE_BS11:
987 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
988 perror("fgets reading segment");
989 return -EINVAL;
990 }
991 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000992
993 /* check if we're sending the last line */
994 sw->last_seg = is_last_line(sw->stream);
995 if (sw->last_seg)
996 seg_buf[1] = 0;
997 else
998 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000999
1000 len = strlen(line_buf) + 2;
1001 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001002 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001003 /* BS11 wants CR + LF in excess of the TLV length !?! */
1004 tlv[1] -= 2;
1005
1006 /* we only now know the exact length for the OM hdr */
1007 len = strlen(line_buf)+2;
1008 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001009 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001010 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001011 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1012 if (len < 0) {
1013 perror("read failed");
1014 return -EINVAL;
1015 }
1016
1017 if (len != IPACC_SEGMENT_SIZE)
1018 sw->last_seg = 1;
1019
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001020 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001021 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001022 len += 3;
1023 break;
1024 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001025 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001026 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001027 /* FIXME: Other BTS types */
1028 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001029 }
Harald Welte4724f992009-01-18 18:01:49 +00001030
Harald Welte4724f992009-01-18 18:01:49 +00001031 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1032 sw->obj_instance[0], sw->obj_instance[1],
1033 sw->obj_instance[2]);
1034
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001035 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001036}
1037
1038/* 6.2.4 / 8.3.4 Load Data End */
1039static int sw_load_end(struct abis_nm_sw *sw)
1040{
1041 struct abis_om_hdr *oh;
1042 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001043 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001044
1045 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1046 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1047 sw->obj_instance[0], sw->obj_instance[1],
1048 sw->obj_instance[2]);
1049
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001050 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001051 return abis_nm_sendmsg(sw->bts, msg);
1052}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001053
Harald Welte52b1f982008-12-23 20:25:15 +00001054/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001055static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001056{
Harald Welte4724f992009-01-18 18:01:49 +00001057 struct abis_om_hdr *oh;
1058 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001059 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001060
Harald Welte4724f992009-01-18 18:01:49 +00001061 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1062 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1063 sw->obj_instance[0], sw->obj_instance[1],
1064 sw->obj_instance[2]);
1065
1066 /* FIXME: this is BS11 specific format */
1067 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1068 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1069 sw->file_version);
1070
1071 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001072}
Harald Welte4724f992009-01-18 18:01:49 +00001073
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001074struct sdp_firmware {
1075 char magic[4];
1076 char more_magic[4];
1077 unsigned int header_length;
1078 unsigned int file_length;
1079} __attribute__ ((packed));
1080
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001081static int parse_sdp_header(struct abis_nm_sw *sw)
1082{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001083 struct sdp_firmware firmware_header;
1084 int rc;
1085 struct stat stat;
1086
1087 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1088 if (rc != sizeof(firmware_header)) {
1089 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1090 return -1;
1091 }
1092
1093 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1094 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1095 return -1;
1096 }
1097
1098 if (firmware_header.more_magic[0] != 0x10 ||
1099 firmware_header.more_magic[1] != 0x02 ||
1100 firmware_header.more_magic[2] != 0x00 ||
1101 firmware_header.more_magic[3] != 0x00) {
1102 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1103 return -1;
1104 }
1105
1106
1107 if (fstat(sw->fd, &stat) == -1) {
1108 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1109 return -1;
1110 }
1111
1112 if (ntohl(firmware_header.file_length) != stat.st_size) {
1113 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1114 return -1;
1115 }
1116
1117 /* go back to the start as we checked the whole filesize.. */
1118 lseek(sw->fd, 0l, SEEK_SET);
1119 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1120 "There might be checksums in the file that are not\n"
1121 "verified and incomplete firmware might be flashed.\n"
1122 "There is absolutely no WARRANTY that flashing will\n"
1123 "work.\n");
1124 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001125}
1126
Harald Welte4724f992009-01-18 18:01:49 +00001127static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1128{
1129 char file_id[12+1];
1130 char file_version[80+1];
1131 int rc;
1132
1133 sw->fd = open(fname, O_RDONLY);
1134 if (sw->fd < 0)
1135 return sw->fd;
1136
1137 switch (sw->bts->type) {
1138 case GSM_BTS_TYPE_BS11:
1139 sw->stream = fdopen(sw->fd, "r");
1140 if (!sw->stream) {
1141 perror("fdopen");
1142 return -1;
1143 }
1144 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001145 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001146 file_id, file_version);
1147 if (rc != 2) {
1148 perror("parsing header line of software file");
1149 return -1;
1150 }
1151 strcpy((char *)sw->file_id, file_id);
1152 sw->file_id_len = strlen(file_id);
1153 strcpy((char *)sw->file_version, file_version);
1154 sw->file_version_len = strlen(file_version);
1155 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001156 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001157 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001158 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001159 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001160 rc = parse_sdp_header(sw);
1161 if (rc < 0) {
1162 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1163 return -1;
1164 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001165
1166 strcpy((char *)sw->file_id, "id");
1167 sw->file_id_len = 3;
1168 strcpy((char *)sw->file_version, "version");
1169 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001170 break;
Harald Welte4724f992009-01-18 18:01:49 +00001171 default:
1172 /* We don't know how to treat them yet */
1173 close(sw->fd);
1174 return -EINVAL;
1175 }
1176
1177 return 0;
1178}
1179
1180static void sw_close_file(struct abis_nm_sw *sw)
1181{
1182 switch (sw->bts->type) {
1183 case GSM_BTS_TYPE_BS11:
1184 fclose(sw->stream);
1185 break;
1186 default:
1187 close(sw->fd);
1188 break;
1189 }
1190}
1191
1192/* Fill the window */
1193static int sw_fill_window(struct abis_nm_sw *sw)
1194{
1195 int rc;
1196
1197 while (sw->seg_in_window < sw->window_size) {
1198 rc = sw_load_segment(sw);
1199 if (rc < 0)
1200 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001201 if (sw->last_seg)
1202 break;
Harald Welte4724f992009-01-18 18:01:49 +00001203 }
1204 return 0;
1205}
1206
1207/* callback function from abis_nm_rcvmsg() handler */
1208static int abis_nm_rcvmsg_sw(struct msgb *mb)
1209{
1210 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001211 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001212 int rc = -1;
1213 struct abis_nm_sw *sw = &g_sw;
1214 enum sw_state old_state = sw->state;
1215
Harald Welte3ffd1372009-02-01 22:15:49 +00001216 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001217
1218 switch (sw->state) {
1219 case SW_STATE_WAIT_INITACK:
1220 switch (foh->msg_type) {
1221 case NM_MT_LOAD_INIT_ACK:
1222 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001223 if (sw->cbfn)
1224 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1225 NM_MT_LOAD_INIT_ACK, mb,
1226 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001227 rc = sw_fill_window(sw);
1228 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001229 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001230 break;
1231 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001232 if (sw->forced) {
1233 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1234 "Init NACK\n");
1235 if (sw->cbfn)
1236 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1237 NM_MT_LOAD_INIT_ACK, mb,
1238 sw->cb_data, NULL);
1239 rc = sw_fill_window(sw);
1240 sw->state = SW_STATE_WAIT_SEGACK;
1241 } else {
1242 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001243 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001244 if (sw->cbfn)
1245 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1246 NM_MT_LOAD_INIT_NACK, mb,
1247 sw->cb_data, NULL);
1248 sw->state = SW_STATE_ERROR;
1249 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001250 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001251 break;
1252 }
1253 break;
1254 case SW_STATE_WAIT_SEGACK:
1255 switch (foh->msg_type) {
1256 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001257 if (sw->cbfn)
1258 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1259 NM_MT_LOAD_SEG_ACK, mb,
1260 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001261 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001262 if (!sw->last_seg) {
1263 /* fill window with more segments */
1264 rc = sw_fill_window(sw);
1265 sw->state = SW_STATE_WAIT_SEGACK;
1266 } else {
1267 /* end the transfer */
1268 sw->state = SW_STATE_WAIT_ENDACK;
1269 rc = sw_load_end(sw);
1270 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001271 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001272 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001273 case NM_MT_LOAD_ABORT:
1274 if (sw->cbfn)
1275 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1276 NM_MT_LOAD_ABORT, mb,
1277 sw->cb_data, NULL);
1278 break;
Harald Welte4724f992009-01-18 18:01:49 +00001279 }
1280 break;
1281 case SW_STATE_WAIT_ENDACK:
1282 switch (foh->msg_type) {
1283 case NM_MT_LOAD_END_ACK:
1284 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001285 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1286 sw->bts->nr);
1287 sw->state = SW_STATE_NONE;
1288 if (sw->cbfn)
1289 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1290 NM_MT_LOAD_END_ACK, mb,
1291 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001292 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001293 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001294 break;
1295 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001296 if (sw->forced) {
1297 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1298 "End NACK\n");
1299 sw->state = SW_STATE_NONE;
1300 if (sw->cbfn)
1301 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1302 NM_MT_LOAD_END_ACK, mb,
1303 sw->cb_data, NULL);
1304 } else {
1305 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001306 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001307 sw->state = SW_STATE_ERROR;
1308 if (sw->cbfn)
1309 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1310 NM_MT_LOAD_END_NACK, mb,
1311 sw->cb_data, NULL);
1312 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001313 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001314 break;
1315 }
1316 case SW_STATE_WAIT_ACTACK:
1317 switch (foh->msg_type) {
1318 case NM_MT_ACTIVATE_SW_ACK:
1319 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001320 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001321 sw->state = SW_STATE_NONE;
1322 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001323 if (sw->cbfn)
1324 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1325 NM_MT_ACTIVATE_SW_ACK, mb,
1326 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001327 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001328 break;
1329 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001330 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001331 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001332 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001333 if (sw->cbfn)
1334 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1335 NM_MT_ACTIVATE_SW_NACK, mb,
1336 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001337 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001338 break;
1339 }
1340 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001341 switch (foh->msg_type) {
1342 case NM_MT_ACTIVATE_SW_ACK:
1343 rc = 0;
1344 break;
1345 }
1346 break;
Harald Welte4724f992009-01-18 18:01:49 +00001347 case SW_STATE_ERROR:
1348 break;
1349 }
1350
1351 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001352 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001353 foh->msg_type, old_state, sw->state);
1354
1355 return rc;
1356}
1357
1358/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001359int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001360 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001361 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001362{
1363 struct abis_nm_sw *sw = &g_sw;
1364 int rc;
1365
Harald Welte5e4d1b32009-02-01 13:36:56 +00001366 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1367 bts->nr, fname);
1368
Harald Welte4724f992009-01-18 18:01:49 +00001369 if (sw->state != SW_STATE_NONE)
1370 return -EBUSY;
1371
1372 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001373 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001374
1375 switch (bts->type) {
1376 case GSM_BTS_TYPE_BS11:
1377 sw->obj_class = NM_OC_SITE_MANAGER;
1378 sw->obj_instance[0] = 0xff;
1379 sw->obj_instance[1] = 0xff;
1380 sw->obj_instance[2] = 0xff;
1381 break;
1382 case GSM_BTS_TYPE_NANOBTS:
1383 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001384 sw->obj_instance[0] = sw->bts->nr;
1385 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001386 sw->obj_instance[2] = 0xff;
1387 break;
1388 case GSM_BTS_TYPE_UNKNOWN:
1389 default:
1390 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1391 return -1;
1392 break;
1393 }
Harald Welte4724f992009-01-18 18:01:49 +00001394 sw->window_size = win_size;
1395 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001396 sw->cbfn = cbfn;
1397 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001398 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001399
1400 rc = sw_open_file(sw, fname);
1401 if (rc < 0) {
1402 sw->state = SW_STATE_NONE;
1403 return rc;
1404 }
1405
1406 return sw_load_init(sw);
1407}
Harald Welte52b1f982008-12-23 20:25:15 +00001408
Harald Welte1602ade2009-01-29 21:12:39 +00001409int abis_nm_software_load_status(struct gsm_bts *bts)
1410{
1411 struct abis_nm_sw *sw = &g_sw;
1412 struct stat st;
1413 int rc, percent;
1414
1415 rc = fstat(sw->fd, &st);
1416 if (rc < 0) {
1417 perror("ERROR during stat");
1418 return rc;
1419 }
1420
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001421 if (sw->stream)
1422 percent = (ftell(sw->stream) * 100) / st.st_size;
1423 else
1424 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001425 return percent;
1426}
1427
Harald Welte5e4d1b32009-02-01 13:36:56 +00001428/* Activate the specified software into the BTS */
1429int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1430 gsm_cbfn *cbfn, void *cb_data)
1431{
1432 struct abis_nm_sw *sw = &g_sw;
1433 int rc;
1434
1435 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1436 bts->nr, fname);
1437
1438 if (sw->state != SW_STATE_NONE)
1439 return -EBUSY;
1440
1441 sw->bts = bts;
1442 sw->obj_class = NM_OC_SITE_MANAGER;
1443 sw->obj_instance[0] = 0xff;
1444 sw->obj_instance[1] = 0xff;
1445 sw->obj_instance[2] = 0xff;
1446 sw->state = SW_STATE_WAIT_ACTACK;
1447 sw->cbfn = cbfn;
1448 sw->cb_data = cb_data;
1449
1450 /* Open the file in order to fill some sw struct members */
1451 rc = sw_open_file(sw, fname);
1452 if (rc < 0) {
1453 sw->state = SW_STATE_NONE;
1454 return rc;
1455 }
1456 sw_close_file(sw);
1457
1458 return sw_activate(sw);
1459}
1460
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001461static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1462 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001463{
Harald Welteadaf08b2009-01-18 11:08:10 +00001464 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001465 ch->bts_port = bts_port;
1466 ch->timeslot = ts_nr;
1467 ch->subslot = subslot_nr;
1468}
1469
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001470int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1471 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1472 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001473{
1474 struct abis_om_hdr *oh;
1475 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001476 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001477 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001478
1479 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1480 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1481 bts->bts_nr, trx_nr, 0xff);
1482
Harald Welte8470bf22008-12-25 23:28:35 +00001483 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001484
1485 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1486 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1487
1488 return abis_nm_sendmsg(bts, msg);
1489}
1490
1491/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1492int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001493 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001494{
Harald Welte8470bf22008-12-25 23:28:35 +00001495 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001496 struct abis_om_hdr *oh;
1497 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001498 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001499
1500 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001501 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001502 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1503
1504 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1505 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1506
1507 return abis_nm_sendmsg(bts, msg);
1508}
1509
1510#if 0
1511int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1512 struct abis_nm_abis_channel *chan)
1513{
1514}
1515#endif
1516
1517int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001518 uint8_t e1_port, uint8_t e1_timeslot,
1519 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001520{
1521 struct gsm_bts *bts = ts->trx->bts;
1522 struct abis_om_hdr *oh;
1523 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001524 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001525
1526 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1527 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001528 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001529
1530 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1531 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1532
Harald Weltef325eb42009-02-19 17:07:39 +00001533 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1534 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001535 e1_port, e1_timeslot, e1_subslot);
1536
Harald Welte52b1f982008-12-23 20:25:15 +00001537 return abis_nm_sendmsg(bts, msg);
1538}
1539
1540#if 0
1541int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1542 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001543 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001544{
1545}
1546#endif
1547
Max1ebf23b2017-05-10 12:21:17 +02001548/* 3GPP TS 52.021 § 8.11.1 */
1549int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1550 const uint8_t *attr, uint8_t attr_len)
Harald Weltefe568f22012-08-14 19:15:57 +02001551{
1552 struct abis_om_hdr *oh;
1553 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001554
1555 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1556
1557 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1558 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1559 bts_nr, trx_nr, ts_nr);
1560 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1561
1562 return abis_nm_sendmsg(bts, msg);
1563}
1564
Harald Welte22af0db2009-02-14 15:41:08 +00001565/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001566int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001567{
1568 struct abis_om_hdr *oh;
1569 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001570 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001571
1572 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1573
1574 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001575 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 +00001576 cur = msgb_put(msg, attr_len);
1577 memcpy(cur, attr, attr_len);
1578
1579 return abis_nm_sendmsg(bts, msg);
1580}
1581
1582/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001583int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001584{
1585 struct abis_om_hdr *oh;
1586 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001587 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001588
1589 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1590
1591 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1592 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001593 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001594 cur = msgb_put(msg, attr_len);
1595 memcpy(cur, attr, attr_len);
1596
1597 return abis_nm_sendmsg(trx->bts, msg);
1598}
1599
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001600int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1601{
1602 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1603 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1604}
1605
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001606static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1607 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001608{
1609 int i;
1610
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001611 *reason = "Reason unknown";
1612
Harald Welte39c7deb2009-08-09 21:49:48 +02001613 /* As it turns out, the BS-11 has some very peculiar restrictions
1614 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301615 switch (ts->trx->bts->type) {
1616 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001617 switch (chan_comb) {
1618 case NM_CHANC_TCHHalf:
1619 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001620 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001621 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001622 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001623 return -EINVAL;
1624 case NM_CHANC_SDCCH:
1625 /* only one SDCCH/8 per TRX */
1626 for (i = 0; i < TRX_NR_TS; i++) {
1627 if (i == ts->nr)
1628 continue;
1629 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001630 NM_CHANC_SDCCH) {
1631 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001632 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001633 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001634 }
1635 /* not allowed for TS0 of BCCH-TRX */
1636 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001637 ts->nr == 0) {
1638 *reason = "SDCCH/8 must be on TS0.";
1639 return -EINVAL;
1640 }
1641
Harald Welte39c7deb2009-08-09 21:49:48 +02001642 /* not on the same TRX that has a BCCH+SDCCH4
1643 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001644 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001645 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001646 ts->trx->ts[0].nm_chan_comb == 8)) {
1647 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1648 return -EINVAL;
1649 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001650 break;
1651 case NM_CHANC_mainBCCH:
1652 case NM_CHANC_BCCHComb:
1653 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001654 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1655 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001656 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001657 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001658 break;
1659 case NM_CHANC_BCCH:
1660 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001661 if (ts->trx != ts->trx->bts->c0) {
1662 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001663 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001664 }
1665 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1666 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001667 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001668 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001669 break;
1670 case 8: /* this is not like 08.58, but in fact
1671 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1672 /* FIXME: only one CBCH allowed per cell */
1673 break;
1674 }
Harald Welted6575f92009-12-02 02:45:23 +05301675 break;
1676 case GSM_BTS_TYPE_NANOBTS:
1677 switch (ts->nr) {
1678 case 0:
1679 if (ts->trx->nr == 0) {
1680 /* only on TRX0 */
1681 switch (chan_comb) {
1682 case NM_CHANC_BCCH:
1683 case NM_CHANC_mainBCCH:
1684 case NM_CHANC_BCCHComb:
1685 return 0;
1686 break;
1687 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001688 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301689 return -EINVAL;
1690 }
1691 } else {
1692 switch (chan_comb) {
1693 case NM_CHANC_TCHFull:
1694 case NM_CHANC_TCHHalf:
1695 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1696 return 0;
1697 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001698 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301699 return -EINVAL;
1700 }
1701 }
1702 break;
1703 case 1:
1704 if (ts->trx->nr == 0) {
1705 switch (chan_comb) {
1706 case NM_CHANC_SDCCH_CBCH:
1707 if (ts->trx->ts[0].nm_chan_comb ==
1708 NM_CHANC_mainBCCH)
1709 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001710 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301711 return -EINVAL;
1712 case NM_CHANC_SDCCH:
1713 case NM_CHANC_TCHFull:
1714 case NM_CHANC_TCHHalf:
1715 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1716 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001717 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301718 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001719 default:
1720 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1721 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301722 }
1723 } else {
1724 switch (chan_comb) {
1725 case NM_CHANC_SDCCH:
1726 case NM_CHANC_TCHFull:
1727 case NM_CHANC_TCHHalf:
1728 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1729 return 0;
1730 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001731 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301732 return -EINVAL;
1733 }
1734 }
1735 break;
1736 case 2:
1737 case 3:
1738 case 4:
1739 case 5:
1740 case 6:
1741 case 7:
1742 switch (chan_comb) {
1743 case NM_CHANC_TCHFull:
1744 case NM_CHANC_TCHHalf:
1745 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1746 return 0;
1747 case NM_CHANC_IPAC_PDCH:
1748 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001749 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301750 if (ts->trx->nr == 0)
1751 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001752 else {
1753 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301754 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001755 }
Harald Welted6575f92009-12-02 02:45:23 +05301756 }
1757 break;
1758 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001759 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301760 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001761 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001762 /* no known restrictions */
1763 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301764 default:
1765 /* unknown BTS type */
1766 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001767 }
1768 return 0;
1769}
1770
Harald Welte22af0db2009-02-14 15:41:08 +00001771/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001772int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001773{
1774 struct gsm_bts *bts = ts->trx->bts;
1775 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001776 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001777 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001778 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001779 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001780
1781 if (bts->type == GSM_BTS_TYPE_BS11)
1782 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001783
Harald Weltef325eb42009-02-19 17:07:39 +00001784 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001785 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001786 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001787 LOGP(DNM, LOGL_ERROR,
1788 "Invalid Channel Combination %d on %s. Reason: %s\n",
1789 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001790 return -EINVAL;
1791 }
1792 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001793
Harald Welte52b1f982008-12-23 20:25:15 +00001794 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001795 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001796 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001797 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001798 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001799 if (ts->hopping.enabled) {
1800 unsigned int i;
1801 uint8_t *len;
1802
Harald Welte6e0cd042009-09-12 13:05:33 +02001803 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1804 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001805
1806 /* build the ARFCN list */
1807 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1808 len = msgb_put(msg, 1);
1809 *len = 0;
1810 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1811 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1812 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001813 /* At least BS-11 wants a TLV16 here */
1814 if (bts->type == GSM_BTS_TYPE_BS11)
1815 *len += 1;
1816 else
1817 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001818 }
1819 }
Harald Weltee0590df2009-02-15 03:34:15 +00001820 }
Harald Welte1fe24122014-01-19 17:18:21 +01001821 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001822 if (bts->type == GSM_BTS_TYPE_BS11)
1823 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001824
1825 return abis_nm_sendmsg(bts, msg);
1826}
1827
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001828int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1829 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001830{
1831 struct abis_om_hdr *oh;
1832 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001833 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1834 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001835
1836 if (nack) {
1837 len += 2;
1838 msgtype = NM_MT_SW_ACT_REQ_NACK;
1839 }
Harald Welte34a99682009-02-13 02:41:40 +00001840
1841 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001842 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1843
Harald Welte34a99682009-02-13 02:41:40 +00001844 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001845 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001846 memcpy(ptr, attr, att_len);
1847 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001848 if (nack)
1849 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001850
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001851 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001852}
1853
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001854int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001855{
Harald Welte8470bf22008-12-25 23:28:35 +00001856 struct msgb *msg = nm_msgb_alloc();
1857 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001858 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001859
1860 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1861 fill_om_hdr(oh, len);
1862 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001863 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001864
1865 return abis_nm_sendmsg(bts, msg);
1866}
1867
1868/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001869static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001870{
1871 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001872 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001873
1874 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001875 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001876 0xff, 0xff, 0xff);
1877
1878 return abis_nm_sendmsg(bts, msg);
1879}
1880
Harald Welte34a99682009-02-13 02:41:40 +00001881/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001882int 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 +00001883{
1884 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001885 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001886 struct msgb *msg = nm_msgb_alloc();
1887
1888 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001889 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001890
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001891 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001892 DEBUGPC(DNM, "Sending OPSTART\n");
1893
Harald Welte34a99682009-02-13 02:41:40 +00001894 return abis_nm_sendmsg(bts, msg);
1895}
1896
1897/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001898int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1899 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001900{
1901 struct abis_om_hdr *oh;
1902 struct msgb *msg = nm_msgb_alloc();
1903
1904 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1905 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1906 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1907
1908 return abis_nm_sendmsg(bts, msg);
1909}
1910
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001911int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1912 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001913{
1914 struct abis_om_hdr *oh;
1915 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001916 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001917
1918 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1919 e1_port0, ts0, e1_port1, ts1);
1920
1921 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1922 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1923 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1924
1925 attr = msgb_put(msg, 3);
1926 attr[0] = NM_ATT_MDROP_LINK;
1927 attr[1] = e1_port0;
1928 attr[2] = ts0;
1929
1930 attr = msgb_put(msg, 3);
1931 attr[0] = NM_ATT_MDROP_NEXT;
1932 attr[1] = e1_port1;
1933 attr[2] = ts1;
1934
1935 return abis_nm_sendmsg(bts, msg);
1936}
Harald Welte34a99682009-02-13 02:41:40 +00001937
Harald Weltec7310382009-08-08 00:02:36 +02001938/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001939int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1940 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1941 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001942{
1943 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001944
Harald Welte15c61722011-05-22 22:45:37 +02001945 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001946
1947 if (!msg)
1948 msg = nm_msgb_alloc();
1949
1950 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1951 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1952 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1953 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001954 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001955
1956 return abis_nm_sendmsg(bts, msg);
1957}
1958
Harald Welte52b1f982008-12-23 20:25:15 +00001959int abis_nm_event_reports(struct gsm_bts *bts, int on)
1960{
1961 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001962 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001963 else
Harald Welte227d4072009-01-03 08:16:25 +00001964 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001965}
1966
Harald Welte47d88ae2009-01-04 12:02:08 +00001967/* Siemens (or BS-11) specific commands */
1968
Harald Welte3ffd1372009-02-01 22:15:49 +00001969int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1970{
1971 if (reconnect == 0)
1972 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1973 else
1974 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1975}
1976
Harald Welteb8427972009-02-05 19:27:17 +00001977int abis_nm_bs11_restart(struct gsm_bts *bts)
1978{
1979 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1980}
1981
1982
Harald Welte268bb402009-02-01 19:11:56 +00001983struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001984 uint16_t year;
1985 uint8_t month;
1986 uint8_t day;
1987 uint8_t hour;
1988 uint8_t min;
1989 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001990} __attribute__((packed));
1991
1992
1993void get_bs11_date_time(struct bs11_date_time *aet)
1994{
1995 time_t t;
1996 struct tm *tm;
1997
1998 t = time(NULL);
1999 tm = localtime(&t);
2000 aet->sec = tm->tm_sec;
2001 aet->min = tm->tm_min;
2002 aet->hour = tm->tm_hour;
2003 aet->day = tm->tm_mday;
2004 aet->month = tm->tm_mon;
2005 aet->year = htons(1900 + tm->tm_year);
2006}
2007
Harald Welte05188ee2009-01-18 11:39:08 +00002008int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002009{
Harald Welte4668fda2009-01-03 08:19:29 +00002010 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002011}
2012
Harald Welte05188ee2009-01-18 11:39:08 +00002013int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002014{
2015 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002016 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002017 else
Harald Welte4668fda2009-01-03 08:19:29 +00002018 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002019}
Harald Welte47d88ae2009-01-04 12:02:08 +00002020
Harald Welte05188ee2009-01-18 11:39:08 +00002021int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002022 enum abis_bs11_objtype type, uint8_t idx,
2023 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002024{
2025 struct abis_om_hdr *oh;
2026 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002027 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002028
2029 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002030 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002031 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002032 cur = msgb_put(msg, attr_len);
2033 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002034
2035 return abis_nm_sendmsg(bts, msg);
2036}
2037
Harald Welte78fc0d42009-02-19 02:50:57 +00002038int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002039 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002040{
2041 struct abis_om_hdr *oh;
2042 struct msgb *msg = nm_msgb_alloc();
2043
2044 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2045 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2046 NM_OC_BS11, type, 0, idx);
2047
2048 return abis_nm_sendmsg(bts, msg);
2049}
2050
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002051int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002052{
2053 struct abis_om_hdr *oh;
2054 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002055 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002056
2057 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002058 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002059 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2060 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002061
2062 return abis_nm_sendmsg(bts, msg);
2063}
2064
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002065int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002066{
2067 struct abis_om_hdr *oh;
2068 struct msgb *msg = nm_msgb_alloc();
2069
2070 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2071 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002072 idx, 0xff, 0xff);
2073
2074 return abis_nm_sendmsg(bts, msg);
2075}
2076
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002077int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002078{
2079 struct abis_om_hdr *oh;
2080 struct msgb *msg = nm_msgb_alloc();
2081
2082 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2083 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2084 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002085
2086 return abis_nm_sendmsg(bts, msg);
2087}
Harald Welte05188ee2009-01-18 11:39:08 +00002088
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002089static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002090int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2091{
2092 struct abis_om_hdr *oh;
2093 struct msgb *msg = nm_msgb_alloc();
2094
2095 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2096 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2097 0xff, 0xff, 0xff);
2098 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2099
2100 return abis_nm_sendmsg(bts, msg);
2101}
2102
Harald Welteb6c92ae2009-02-21 20:15:32 +00002103/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002104int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2105 uint8_t e1_timeslot, uint8_t e1_subslot,
2106 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002107{
2108 struct abis_om_hdr *oh;
2109 struct abis_nm_channel *ch;
2110 struct msgb *msg = nm_msgb_alloc();
2111
2112 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002113 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002114 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2115
2116 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2117 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002118 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002119
2120 return abis_nm_sendmsg(bts, msg);
2121}
2122
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002123int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002124{
2125 struct abis_om_hdr *oh;
2126 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002127
2128 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002129 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002130 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2131 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2132
2133 return abis_nm_sendmsg(trx->bts, msg);
2134}
2135
Harald Welte78fc0d42009-02-19 02:50:57 +00002136int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2137{
2138 struct abis_om_hdr *oh;
2139 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002140 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002141
2142 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2143 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2144 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2145 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2146
2147 return abis_nm_sendmsg(trx->bts, msg);
2148}
2149
Harald Welteaaf02d92009-04-29 13:25:57 +00002150int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2151{
2152 struct abis_om_hdr *oh;
2153 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002154 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002155
2156 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2157 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2158 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002159 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002160
2161 return abis_nm_sendmsg(bts, msg);
2162}
2163
Harald Welteef061952009-05-17 12:43:42 +00002164int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2165{
2166 struct abis_om_hdr *oh;
2167 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002168 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002169 NM_ATT_BS11_CCLK_TYPE };
2170
2171 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2172 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2173 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2174 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2175
2176 return abis_nm_sendmsg(bts, msg);
2177
2178}
Harald Welteaaf02d92009-04-29 13:25:57 +00002179
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002180//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002181
Harald Welte1bc09062009-01-18 14:17:52 +00002182int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002183{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002184 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2185}
2186
Daniel Willmann4b054c82010-01-07 00:46:26 +01002187int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2188{
2189 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2190}
2191
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002192int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002193{
Harald Welte05188ee2009-01-18 11:39:08 +00002194 struct abis_om_hdr *oh;
2195 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002196 struct bs11_date_time bdt;
2197
2198 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002199
2200 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002201 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002202 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002203 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002204 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002205 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002206 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002207 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002208 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002209 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002210 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002211 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002212 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002213 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002214 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002215 }
Harald Welte05188ee2009-01-18 11:39:08 +00002216
2217 return abis_nm_sendmsg(bts, msg);
2218}
Harald Welte1bc09062009-01-18 14:17:52 +00002219
2220int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2221{
2222 struct abis_om_hdr *oh;
2223 struct msgb *msg;
2224
2225 if (strlen(password) != 10)
2226 return -EINVAL;
2227
2228 msg = nm_msgb_alloc();
2229 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002230 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002231 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002232 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002233
2234 return abis_nm_sendmsg(bts, msg);
2235}
2236
Harald Weltee69f5fb2009-04-28 16:31:38 +00002237/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2238int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2239{
2240 struct abis_om_hdr *oh;
2241 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002242 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002243
2244 msg = nm_msgb_alloc();
2245 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2246 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2247 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002248
2249 if (locked)
2250 tlv_value = BS11_LI_PLL_LOCKED;
2251 else
2252 tlv_value = BS11_LI_PLL_STANDALONE;
2253
2254 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002255
2256 return abis_nm_sendmsg(bts, msg);
2257}
2258
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002259/* Set the calibration value of the PLL (work value/set value)
2260 * It depends on the login which one is changed */
2261int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2262{
2263 struct abis_om_hdr *oh;
2264 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002265 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002266
2267 msg = nm_msgb_alloc();
2268 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2269 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2270 BS11_OBJ_TRX1, 0x00, 0x00);
2271
2272 tlv_value[0] = value>>8;
2273 tlv_value[1] = value&0xff;
2274
2275 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2276
2277 return abis_nm_sendmsg(bts, msg);
2278}
2279
Harald Welte1bc09062009-01-18 14:17:52 +00002280int abis_nm_bs11_get_state(struct gsm_bts *bts)
2281{
2282 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2283}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002284
2285/* BS11 SWL */
2286
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002287void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002288
Harald Welte5e4d1b32009-02-01 13:36:56 +00002289struct abis_nm_bs11_sw {
2290 struct gsm_bts *bts;
2291 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002292 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002293 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002294 struct llist_head file_list;
2295 gsm_cbfn *user_cb; /* specified by the user */
2296};
2297static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2298
2299struct file_list_entry {
2300 struct llist_head list;
2301 char fname[PATH_MAX];
2302};
2303
2304struct file_list_entry *fl_dequeue(struct llist_head *queue)
2305{
2306 struct llist_head *lh;
2307
2308 if (llist_empty(queue))
2309 return NULL;
2310
2311 lh = queue->next;
2312 llist_del(lh);
2313
2314 return llist_entry(lh, struct file_list_entry, list);
2315}
2316
2317static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2318{
2319 char linebuf[255];
2320 struct llist_head *lh, *lh2;
2321 FILE *swl;
2322 int rc = 0;
2323
2324 swl = fopen(bs11_sw->swl_fname, "r");
2325 if (!swl)
2326 return -ENODEV;
2327
2328 /* zero the stale file list, if any */
2329 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2330 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002331 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002332 }
2333
2334 while (fgets(linebuf, sizeof(linebuf), swl)) {
2335 char file_id[12+1];
2336 char file_version[80+1];
2337 struct file_list_entry *fle;
2338 static char dir[PATH_MAX];
2339
2340 if (strlen(linebuf) < 4)
2341 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002342
Harald Welte5e4d1b32009-02-01 13:36:56 +00002343 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2344 if (rc < 0) {
2345 perror("ERR parsing SWL file");
2346 rc = -EINVAL;
2347 goto out;
2348 }
2349 if (rc < 2)
2350 continue;
2351
Harald Welte470ec292009-06-26 20:25:23 +02002352 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002353 if (!fle) {
2354 rc = -ENOMEM;
2355 goto out;
2356 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002357
2358 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002359 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002360 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2361 strcat(fle->fname, "/");
2362 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002363
2364 llist_add_tail(&fle->list, &bs11_sw->file_list);
2365 }
2366
2367out:
2368 fclose(swl);
2369 return rc;
2370}
2371
2372/* bs11 swload specific callback, passed to abis_nm core swload */
2373static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2374 struct msgb *msg, void *data, void *param)
2375{
2376 struct abis_nm_bs11_sw *bs11_sw = data;
2377 struct file_list_entry *fle;
2378 int rc = 0;
2379
Harald Welte5e4d1b32009-02-01 13:36:56 +00002380 switch (event) {
2381 case NM_MT_LOAD_END_ACK:
2382 fle = fl_dequeue(&bs11_sw->file_list);
2383 if (fle) {
2384 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002385 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002386 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002387 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002388 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002389 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002390 } else {
2391 /* activate the SWL */
2392 rc = abis_nm_software_activate(bs11_sw->bts,
2393 bs11_sw->swl_fname,
2394 bs11_swload_cbfn,
2395 bs11_sw);
2396 }
2397 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002398 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002399 case NM_MT_LOAD_END_NACK:
2400 case NM_MT_LOAD_INIT_ACK:
2401 case NM_MT_LOAD_INIT_NACK:
2402 case NM_MT_ACTIVATE_SW_NACK:
2403 case NM_MT_ACTIVATE_SW_ACK:
2404 default:
2405 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002406 if (bs11_sw->user_cb)
2407 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002408 break;
2409 }
2410
2411 return rc;
2412}
2413
2414/* Siemens provides a SWL file that is a mere listing of all the other
2415 * files that are part of a software release. We need to upload first
2416 * the list file, and then each file that is listed in the list file */
2417int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002418 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002419{
2420 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2421 struct file_list_entry *fle;
2422 int rc = 0;
2423
2424 INIT_LLIST_HEAD(&bs11_sw->file_list);
2425 bs11_sw->bts = bts;
2426 bs11_sw->win_size = win_size;
2427 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002428 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002429
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002430 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002431 rc = bs11_read_swl_file(bs11_sw);
2432 if (rc < 0)
2433 return rc;
2434
2435 /* dequeue next item in file list */
2436 fle = fl_dequeue(&bs11_sw->file_list);
2437 if (!fle)
2438 return -EINVAL;
2439
2440 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002441 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002442 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002443 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002444 return rc;
2445}
2446
Harald Welte5083b0b2009-02-02 19:20:52 +00002447#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002448static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002449 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2450 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2451 NM_ATT_BS11_LMT_USER_NAME,
2452
2453 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2454
2455 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2456
2457 NM_ATT_BS11_SW_LOAD_STORED };
2458
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002459static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002460 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2461 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2462 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2463 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002464#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002465
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002466static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002467 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2468 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002469 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002470
2471int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2472{
2473 struct abis_om_hdr *oh;
2474 struct msgb *msg = nm_msgb_alloc();
2475
2476 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2477 /* SiemensHW CCTRL object */
2478 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2479 0x03, 0x00, 0x00);
2480 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2481
2482 return abis_nm_sendmsg(bts, msg);
2483}
Harald Welte268bb402009-02-01 19:11:56 +00002484
2485int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2486{
2487 struct abis_om_hdr *oh;
2488 struct msgb *msg = nm_msgb_alloc();
2489 struct bs11_date_time aet;
2490
2491 get_bs11_date_time(&aet);
2492 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2493 /* SiemensHW CCTRL object */
2494 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2495 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002496 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002497
2498 return abis_nm_sendmsg(bts, msg);
2499}
Harald Welte5c1e4582009-02-15 11:57:29 +00002500
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002501int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002502{
2503 struct abis_om_hdr *oh;
2504 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002505 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002506
2507 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2508 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2509 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2510 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2511
2512 return abis_nm_sendmsg(bts, msg);
2513}
2514
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002515int 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 +02002516{
2517 struct abis_om_hdr *oh;
2518 struct msgb *msg = nm_msgb_alloc();
2519 struct bs11_date_time aet;
2520
2521 get_bs11_date_time(&aet);
2522 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2523 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2524 bport, 0xff, 0x02);
2525 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2526
2527 return abis_nm_sendmsg(bts, msg);
2528}
2529
Harald Welte5c1e4582009-02-15 11:57:29 +00002530/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002531static const char ipaccess_magic[] = "com.ipaccess";
2532
Harald Welte677c21f2009-02-17 13:22:23 +00002533
2534static int abis_nm_rx_ipacc(struct msgb *msg)
2535{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002536 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002537 struct abis_om_hdr *oh = msgb_l2(msg);
2538 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002539 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002540 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002541 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002542 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002543
2544 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002545 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002546 return -EINVAL;
2547 }
2548
Harald Welte193fefc2009-04-30 15:16:27 +00002549 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002550 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002551
Harald Welte15c61722011-05-22 22:45:37 +02002552 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002553
Harald Welte746d6092009-10-19 22:11:11 +02002554 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002555
Harald Welte677c21f2009-02-17 13:22:23 +00002556 switch (foh->msg_type) {
2557 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002558 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002559 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2560 memcpy(&addr,
2561 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2562
2563 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2564 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002565 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002566 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002567 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002568 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002569 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2570 DEBUGPC(DNM, "STREAM=0x%02x ",
2571 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002572 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002573 break;
2574 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002575 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002576 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002577 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002578 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002579 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002580 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002581 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002582 case NM_MT_IPACC_SET_NVATTR_ACK:
2583 DEBUGPC(DNM, "SET NVATTR ACK\n");
2584 /* FIXME: decode and show the actual attributes */
2585 break;
2586 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002587 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002588 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002589 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002590 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002591 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002592 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002593 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002594 case NM_MT_IPACC_GET_NVATTR_ACK:
2595 DEBUGPC(DNM, "GET NVATTR ACK\n");
2596 /* FIXME: decode and show the actual attributes */
2597 break;
2598 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002599 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002600 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002601 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002602 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002603 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002604 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002605 break;
Harald Welte15c44172009-10-08 20:15:24 +02002606 case NM_MT_IPACC_SET_ATTR_ACK:
2607 DEBUGPC(DNM, "SET ATTR ACK\n");
2608 break;
2609 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002610 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002611 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002612 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002613 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002614 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002615 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002616 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002617 default:
2618 DEBUGPC(DNM, "unknown\n");
2619 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002620 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002621
2622 /* signal handling */
2623 switch (foh->msg_type) {
2624 case NM_MT_IPACC_RSL_CONNECT_NACK:
2625 case NM_MT_IPACC_SET_NVATTR_NACK:
2626 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002627 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 +01002628 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002629 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002630 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002631 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002632 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 +01002633 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002634 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002635 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002636 default:
2637 break;
2638 }
2639
Harald Welte677c21f2009-02-17 13:22:23 +00002640 return 0;
2641}
2642
Harald Welte193fefc2009-04-30 15:16:27 +00002643/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002644int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2645 uint8_t obj_class, uint8_t bts_nr,
2646 uint8_t trx_nr, uint8_t ts_nr,
2647 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002648{
2649 struct msgb *msg = nm_msgb_alloc();
2650 struct abis_om_hdr *oh;
2651 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002652 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002653
2654 /* construct the 12.21 OM header, observe the erroneous length */
2655 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2656 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2657 oh->mdisc = ABIS_OM_MDISC_MANUF;
2658
2659 /* add the ip.access magic */
2660 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2661 *data++ = sizeof(ipaccess_magic);
2662 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2663
2664 /* fill the 12.21 FOM header */
2665 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2666 foh->msg_type = msg_type;
2667 foh->obj_class = obj_class;
2668 foh->obj_inst.bts_nr = bts_nr;
2669 foh->obj_inst.trx_nr = trx_nr;
2670 foh->obj_inst.ts_nr = ts_nr;
2671
2672 if (attr && attr_len) {
2673 data = msgb_put(msg, attr_len);
2674 memcpy(data, attr, attr_len);
2675 }
2676
2677 return abis_nm_sendmsg(bts, msg);
2678}
Harald Welte677c21f2009-02-17 13:22:23 +00002679
Harald Welte193fefc2009-04-30 15:16:27 +00002680/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002681int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002682 int attr_len)
2683{
Harald Welte2ef156d2010-01-07 20:39:42 +01002684 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2685 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002686 attr_len);
2687}
2688
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002689int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002690 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002691{
2692 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002693 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002694 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2695 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2696
2697 int attr_len = sizeof(attr);
2698
2699 ia.s_addr = htonl(ip);
2700 attr[1] = stream;
2701 attr[3] = port >> 8;
2702 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002703 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002704
2705 /* if ip == 0, we use the default IP */
2706 if (ip == 0)
2707 attr_len -= 5;
2708
2709 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002710 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002711
2712 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2713 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2714 trx->nr, 0xff, attr, attr_len);
2715}
2716
Harald Welte193fefc2009-04-30 15:16:27 +00002717/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002718int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002719{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002720 struct abis_om_hdr *oh;
2721 struct msgb *msg = nm_msgb_alloc();
2722
2723 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2724 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2725 trx->bts->nr, trx->nr, 0xff);
2726
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002727 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002728}
Harald Weltedaef5212009-10-24 10:20:41 +02002729
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002730int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2731 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2732 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002733{
2734 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2735 obj_class, bts_nr, trx_nr, ts_nr,
2736 attr, attr_len);
2737}
Harald Welte0f255852009-11-12 14:48:42 +01002738
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002739void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002740{
2741 /* we simply reuse the GSM48 function and overwrite the RAC
2742 * with the Cell ID */
2743 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002744 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002745}
2746
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002747void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2748{
2749 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2750
Harald Welted64c0bc2011-05-30 12:07:53 +02002751 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002752 if (!trx->bts || !trx->bts->oml_link)
2753 return;
2754
2755 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2756 trx->bts->bts_nr, trx->nr, 0xff,
2757 new_state);
2758}
2759
Harald Welte92b1fe42010-03-25 11:45:30 +08002760static const struct value_string ipacc_testres_names[] = {
2761 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2762 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2763 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2764 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2765 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2766 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002767};
2768
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002769const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002770{
Harald Welte92b1fe42010-03-25 11:45:30 +08002771 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002772}
2773
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002774void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002775{
2776 cid->mcc = (buf[0] & 0xf) * 100;
2777 cid->mcc += (buf[0] >> 4) * 10;
2778 cid->mcc += (buf[1] & 0xf) * 1;
2779
2780 if (buf[1] >> 4 == 0xf) {
2781 cid->mnc = (buf[2] & 0xf) * 10;
2782 cid->mnc += (buf[2] >> 4) * 1;
2783 } else {
2784 cid->mnc = (buf[2] & 0xf) * 100;
2785 cid->mnc += (buf[2] >> 4) * 10;
2786 cid->mnc += (buf[1] >> 4) * 1;
2787 }
2788
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002789 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2790 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002791}
2792
Harald Welte0f255852009-11-12 14:48:42 +01002793/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002794int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002795{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002796 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002797 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002798
Harald Welteaf109b92010-07-22 18:14:36 +02002799 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002800
2801 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2802 return -EINVAL;
2803 cur++;
2804
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002805 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002806 cur += 2;
2807
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002808 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002809 cur += 2;
2810
2811 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2812 binf->freq_qual = *cur >> 2;
2813
Harald Welteaf109b92010-07-22 18:14:36 +02002814 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002815 binf->arfcn |= *cur++;
2816
2817 if (binf->info_type & IPAC_BINF_RXLEV)
2818 binf->rx_lev = *cur & 0x3f;
2819 cur++;
2820
2821 if (binf->info_type & IPAC_BINF_RXQUAL)
2822 binf->rx_qual = *cur & 0x7;
2823 cur++;
2824
2825 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002826 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002827 cur += 2;
2828
2829 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002830 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002831 cur += 2;
2832
2833 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002834 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002835 cur += 4;
2836
Harald Weltea780a3d2010-07-30 22:34:42 +02002837#if 0
2838 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002839 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002840#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002841 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002842 cur++;
2843
Harald Welteb40a38f2009-11-13 11:56:05 +01002844 ipac_parse_cgi(&binf->cgi, cur);
2845 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002846
2847 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2848 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2849 cur += sizeof(binf->ba_list_si2);
2850 }
2851
2852 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2853 memcpy(binf->ba_list_si2bis, cur,
2854 sizeof(binf->ba_list_si2bis));
2855 cur += sizeof(binf->ba_list_si2bis);
2856 }
2857
2858 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2859 memcpy(binf->ba_list_si2ter, cur,
2860 sizeof(binf->ba_list_si2ter));
2861 cur += sizeof(binf->ba_list_si2ter);
2862 }
2863
2864 return 0;
2865}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002866
2867void abis_nm_clear_queue(struct gsm_bts *bts)
2868{
2869 struct msgb *msg;
2870
2871 while (!llist_empty(&bts->abis_queue)) {
2872 msg = msgb_dequeue(&bts->abis_queue);
2873 msgb_free(msg);
2874 }
2875
2876 bts->abis_nm_pend = 0;
2877}