blob: ec1e47826710e2aa50f03ac80ab38b2cf9996b77 [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
Maxdefb6c92017-05-15 10:29:54 +0200442static inline bool handle_attr(struct gsm_bts *bts, enum bts_attribute id, uint8_t *val, uint8_t len)
443{
444 switch (id) {
445 case BTS_TYPE_VARIANT:
446 LOGP(DNM, LOGL_ERROR, "BTS reported variant: %s\n", val);
447 break;
448 case BTS_SUB_MODEL:
449 LOGP(DNM, LOGL_ERROR, "BTS reported submodel: %s\n", val);
450 break;
451 default:
452 return false;
453 }
454 return true;
455}
456
457/* Handle 3GPP TS 52.021 §9.4.64 Get Attribute Response Info */
458static int abis_nm_rx_get_attr_resp(struct msgb *mb, struct gsm_bts *bts)
459{
460 struct abis_om_hdr *oh = msgb_l2(mb);
461 struct abis_om_fom_hdr *foh = msgb_l3(mb);
462 struct e1inp_sign_link *sign_link = mb->dst;
463 struct tlv_parsed tp;
464 const uint8_t *ari;
465 uint8_t unreported, i;
466 uint16_t ari_len;
467 int rc;
468 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
469
470 abis_nm_debugp_foh(DNM, foh);
471
472 DEBUGPC(DNM, "Get Attributes Response\n");
473
474 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
475
476 if (!TLVP_PRESENT(&tp, NM_ATT_GET_ARI)) {
477 LOGP(DNM, LOGL_ERROR, "Get Attributes Response without Response Info?!\n");
478 return -EINVAL;
479 }
480
481 ari = TLVP_VAL(&tp, NM_ATT_GET_ARI);
482 ari_len = TLVP_LEN(&tp, NM_ATT_GET_ARI);
483 /* Attributes Response Info has peculiar structure - first the number of unreported attributes */
484 unreported = ari[0];
485 DEBUGP(DNM, "Found Get Attributes Response Info: %u bytes total with %u unreported attributes\n",
486 ari_len, unreported);
487
488 /* than the list of unreported attributes */
489 for (i = 0; i < unreported; i++)
490 LOGP(DNM, LOGL_ERROR, "Attribute %s is unreported\n", /* +1 because we have to account for number of */
491 get_value_string(abis_nm_att_names, ari[i + 1])); /* unreported attributes, prefixing the list. */
492
493 /* after that there's finally list of replies in form of sw-conf structure:
494 it starts right after the list of unreported attributes + space for length of that list */
495 rc = abis_nm_get_sw_conf(ari + unreported + 1, ari_len - (unreported + 2), &sw_descr[0], ARRAY_SIZE(sw_descr));
496 if (rc > 0) {
497 for (i = 0; i < rc; i++) {
498 if (!handle_attr(bts, str2btsattr((const char *)sw_descr[i].file_id), sw_descr[i].file_version,
499 sw_descr[i].file_version_len))
500 LOGP(DNM, LOGL_NOTICE, "ARI reported sw[%d/%d]: %s is %s\n",
501 i, rc, sw_descr[i].file_id, sw_descr[i].file_version);
502 }
503 } else
504 LOGP(DNM, LOGL_ERROR, "Failed to parse SW-Config part of Get Attribute Response Info: %s\n",
505 strerror(-rc));
506
507 return 0;
508}
509
Max1ebf23b2017-05-10 12:21:17 +0200510/* 3GPP TS 52.021 §6.2.5 */
Harald Welte34a99682009-02-13 02:41:40 +0000511static int abis_nm_rx_sw_act_req(struct msgb *mb)
512{
513 struct abis_om_hdr *oh = msgb_l2(mb);
514 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200515 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200516 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200517 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100518 int ret, sw_config_len, len;
Max1ebf23b2017-05-10 12:21:17 +0200519 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
Harald Welte34a99682009-02-13 02:41:40 +0000520
Harald Welte15c61722011-05-22 22:45:37 +0200521 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200522
523 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000524
Harald Welte97a282b2010-03-14 15:37:43 +0800525 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000526
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200527 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000528 foh->obj_inst.bts_nr,
529 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800530 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000531 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100532 if (ret != 0) {
533 LOGP(DNM, LOGL_ERROR,
534 "Sending SW ActReq ACK failed: %d\n", ret);
535 return ret;
536 }
Harald Welte34a99682009-02-13 02:41:40 +0000537
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200538 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200539 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
540 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
541 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100542 LOGP(DNM, LOGL_ERROR,
543 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200544 return -EINVAL;
545 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200546 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200547 }
548
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100549 /* Parse up to two sw descriptions from the data */
Maxfd2c1f92017-03-24 21:04:57 +0100550 len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
551 ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100552 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100553 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100554 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100555 }
Mike Habena03f9772009-10-01 14:56:13 +0200556
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100557 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
558 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
559
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200560 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000561 foh->obj_inst.bts_nr,
562 foh->obj_inst.trx_nr,
563 foh->obj_inst.ts_nr,
Maxfd2c1f92017-03-24 21:04:57 +0100564 &sw_descr[ret]);
Harald Welte34a99682009-02-13 02:41:40 +0000565}
566
Harald Weltee0590df2009-02-15 03:34:15 +0000567/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
568static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
569{
570 struct abis_om_hdr *oh = msgb_l2(mb);
571 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200572 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000573 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200574 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000575
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200576 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000577 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
578 return -EINVAL;
579
580 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
581
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200582 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000583}
584
Harald Welteee670472009-02-22 21:58:49 +0000585static int abis_nm_rx_lmt_event(struct msgb *mb)
586{
587 struct abis_om_hdr *oh = msgb_l2(mb);
588 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200589 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000590 struct tlv_parsed tp;
591
592 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200593 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000594 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
595 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200596 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000597 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
598 }
599 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
600 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200601 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000602 DEBUGPC(DNM, "Level=%u ", level);
603 }
604 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
605 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
606 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
607 DEBUGPC(DNM, "Username=%s ", name);
608 }
609 DEBUGPC(DNM, "\n");
610 /* FIXME: parse LMT LOGON TIME */
611 return 0;
612}
613
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200614void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100615{
616 int wait = 0;
617 struct msgb *msg;
618 /* the queue is empty */
619 while (!llist_empty(&bts->abis_queue)) {
620 msg = msgb_dequeue(&bts->abis_queue);
621 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200622 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100623
624 if (wait)
625 break;
626 }
627
628 bts->abis_nm_pend = wait;
629}
630
Harald Welte52b1f982008-12-23 20:25:15 +0000631/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000632static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000633{
Harald Welte6c96ba52009-05-01 13:03:40 +0000634 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000635 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200636 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200637 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100638 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
639 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100640 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000641
642 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000643 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100644 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000645
Harald Welte15c61722011-05-22 22:45:37 +0200646 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000647 return abis_nm_rcvmsg_sw(mb);
648
Harald Welte15c61722011-05-22 22:45:37 +0200649 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800650 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000651 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200652
Harald Welte15c61722011-05-22 22:45:37 +0200653 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200654
Harald Welte15c61722011-05-22 22:45:37 +0200655 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000656
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100657 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000658 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200659 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200660 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000661 else
662 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200663
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800664 nack_data.msg = mb;
665 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100666 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200667 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100668 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200669 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000670 }
Harald Weltead384642008-12-26 10:20:07 +0000671#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000672 /* check if last message is to be acked */
673 if (is_ack_nack(nmh->last_msgtype)) {
674 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100675 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000676 /* we got our ACK, continue sending the next msg */
677 } else if (mt == MT_NACK(nmh->last_msgtype)) {
678 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100679 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000680 /* FIXME: somehow signal this to the caller */
681 } else {
682 /* really strange things happen */
683 return -EINVAL;
684 }
685 }
Harald Weltead384642008-12-26 10:20:07 +0000686#endif
687
Harald Welte97ed1e72009-02-06 13:38:02 +0000688 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000689 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100690 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000691 break;
Harald Welte34a99682009-02-13 02:41:40 +0000692 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100693 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000694 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000695 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100696 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000697 break;
Max689e7e52017-04-04 19:21:24 +0200698 case NM_MT_OPSTART_ACK:
699 abis_nm_debugp_foh(DNM, foh);
700 DEBUGPC(DNM, "Opstart ACK\n");
701 break;
702 case NM_MT_SET_CHAN_ATTR_ACK:
703 abis_nm_debugp_foh(DNM, foh);
704 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
705 break;
706 case NM_MT_SET_RADIO_ATTR_ACK:
707 abis_nm_debugp_foh(DNM, foh);
708 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
709 break;
Harald Welte1989c082009-08-06 17:58:31 +0200710 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200711 abis_nm_debugp_foh(DNM, foh);
712 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200713 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100714 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200715 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100716 break;
717 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200718 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100719 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100720 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100721 break;
Maxdefb6c92017-05-15 10:29:54 +0200722 case NM_MT_GET_ATTR_RESP:
723 ret = abis_nm_rx_get_attr_resp(mb, bts);
724 break;
Max689e7e52017-04-04 19:21:24 +0200725 default:
726 abis_nm_debugp_foh(DNM, foh);
727 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
728 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000729 }
730
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100731 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100732 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000733}
734
Harald Welte677c21f2009-02-17 13:22:23 +0000735static int abis_nm_rx_ipacc(struct msgb *mb);
736
737static int abis_nm_rcvmsg_manuf(struct msgb *mb)
738{
739 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200740 struct e1inp_sign_link *sign_link = mb->dst;
741 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000742
743 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100744 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100745 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000746 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200747 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000748 break;
749 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100750 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
751 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000752 rc = 0;
753 break;
754 }
755
756 return rc;
757}
758
Harald Welte52b1f982008-12-23 20:25:15 +0000759/* High-Level API */
760/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000761int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000762{
Harald Welte52b1f982008-12-23 20:25:15 +0000763 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000764 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000765
766 /* Various consistency checks */
767 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100768 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000769 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200770 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
771 rc = -EINVAL;
772 goto err;
773 }
Harald Welte52b1f982008-12-23 20:25:15 +0000774 }
775 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100776 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000777 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200778 rc = -EINVAL;
779 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000780 }
Harald Welte702d8702008-12-26 20:25:35 +0000781#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200782 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000783 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000784 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100785 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000786 oh->length + sizeof(*oh), l2_len);
787 return -EINVAL;
788 }
Harald Welte702d8702008-12-26 20:25:35 +0000789 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100790 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 +0000791#endif
Harald Weltead384642008-12-26 10:20:07 +0000792 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000793
794 switch (oh->mdisc) {
795 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000796 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000797 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000798 case ABIS_OM_MDISC_MANUF:
799 rc = abis_nm_rcvmsg_manuf(msg);
800 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000801 case ABIS_OM_MDISC_MMI:
802 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100803 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000804 oh->mdisc);
805 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000806 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100807 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000808 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200809 rc = -EINVAL;
810 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000811 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200812err:
Harald Weltead384642008-12-26 10:20:07 +0000813 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000814 return rc;
815}
816
817#if 0
818/* initialized all resources */
819struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
820{
821 struct abis_nm_h *nmh;
822
823 nmh = malloc(sizeof(*nmh));
824 if (!nmh)
825 return NULL;
826
827 nmh->cfg = cfg;
828
829 return nmh;
830}
831
832/* free all resources */
833void abis_nm_fini(struct abis_nm_h *nmh)
834{
835 free(nmh);
836}
837#endif
838
839/* Here we are trying to define a high-level API that can be used by
840 * the actual BSC implementation. However, the architecture is currently
841 * still under design. Ideally the calls to this API would be synchronous,
842 * while the underlying stack behind the APi runs in a traditional select
843 * based state machine.
844 */
845
Harald Welte4724f992009-01-18 18:01:49 +0000846/* 6.2 Software Load: */
847enum sw_state {
848 SW_STATE_NONE,
849 SW_STATE_WAIT_INITACK,
850 SW_STATE_WAIT_SEGACK,
851 SW_STATE_WAIT_ENDACK,
852 SW_STATE_WAIT_ACTACK,
853 SW_STATE_ERROR,
854};
Harald Welte52b1f982008-12-23 20:25:15 +0000855
Harald Welte52b1f982008-12-23 20:25:15 +0000856struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000857 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800858 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000859 gsm_cbfn *cbfn;
860 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000861 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000862
Harald Welte52b1f982008-12-23 20:25:15 +0000863 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200864 uint8_t obj_class;
865 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000866
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200867 uint8_t file_id[255];
868 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000869
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200870 uint8_t file_version[255];
871 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000872
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200873 uint8_t window_size;
874 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000875
876 int fd;
877 FILE *stream;
878 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000879 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000880};
881
Harald Welte4724f992009-01-18 18:01:49 +0000882static struct abis_nm_sw g_sw;
883
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100884static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
885{
886 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
887 msgb_v_put(msg, NM_ATT_SW_DESCR);
888 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
889 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
890 sw->file_version);
891 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
892 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
893 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
894 sw->file_version);
895 } else {
896 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
897 }
898}
899
Harald Welte4724f992009-01-18 18:01:49 +0000900/* 6.2.1 / 8.3.1: Load Data Initiate */
901static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000902{
Harald Welte4724f992009-01-18 18:01:49 +0000903 struct abis_om_hdr *oh;
904 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200905 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000906
907 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
908 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
909 sw->obj_instance[0], sw->obj_instance[1],
910 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100911
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100912 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000913 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
914
915 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000916}
917
Harald Welte1602ade2009-01-29 21:12:39 +0000918static int is_last_line(FILE *stream)
919{
920 char next_seg_buf[256];
921 long pos;
922
923 /* check if we're sending the last line */
924 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200925
926 /* Did ftell fail? Then we are at the end for sure */
927 if (pos < 0)
928 return 1;
929
Harald Welte1602ade2009-01-29 21:12:39 +0000930 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +0100931 int rc = fseek(stream, pos, SEEK_SET);
932 if (rc < 0)
933 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000934 return 1;
935 }
936
937 fseek(stream, pos, SEEK_SET);
938 return 0;
939}
940
Harald Welte4724f992009-01-18 18:01:49 +0000941/* 6.2.2 / 8.3.2 Load Data Segment */
942static int sw_load_segment(struct abis_nm_sw *sw)
943{
944 struct abis_om_hdr *oh;
945 struct msgb *msg = nm_msgb_alloc();
946 char seg_buf[256];
947 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000948 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200949 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000950
951 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000952
953 switch (sw->bts->type) {
954 case GSM_BTS_TYPE_BS11:
955 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
956 perror("fgets reading segment");
957 return -EINVAL;
958 }
959 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000960
961 /* check if we're sending the last line */
962 sw->last_seg = is_last_line(sw->stream);
963 if (sw->last_seg)
964 seg_buf[1] = 0;
965 else
966 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000967
968 len = strlen(line_buf) + 2;
969 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200970 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000971 /* BS11 wants CR + LF in excess of the TLV length !?! */
972 tlv[1] -= 2;
973
974 /* we only now know the exact length for the OM hdr */
975 len = strlen(line_buf)+2;
976 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100977 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200978 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100979 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
980 if (len < 0) {
981 perror("read failed");
982 return -EINVAL;
983 }
984
985 if (len != IPACC_SEGMENT_SIZE)
986 sw->last_seg = 1;
987
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100988 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200989 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100990 len += 3;
991 break;
992 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000993 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100994 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000995 /* FIXME: Other BTS types */
996 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000997 }
Harald Welte4724f992009-01-18 18:01:49 +0000998
Harald Welte4724f992009-01-18 18:01:49 +0000999 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1000 sw->obj_instance[0], sw->obj_instance[1],
1001 sw->obj_instance[2]);
1002
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001003 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001004}
1005
1006/* 6.2.4 / 8.3.4 Load Data End */
1007static int sw_load_end(struct abis_nm_sw *sw)
1008{
1009 struct abis_om_hdr *oh;
1010 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001011 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001012
1013 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1014 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1015 sw->obj_instance[0], sw->obj_instance[1],
1016 sw->obj_instance[2]);
1017
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001018 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001019 return abis_nm_sendmsg(sw->bts, msg);
1020}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001021
Harald Welte52b1f982008-12-23 20:25:15 +00001022/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001023static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001024{
Harald Welte4724f992009-01-18 18:01:49 +00001025 struct abis_om_hdr *oh;
1026 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001027 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001028
Harald Welte4724f992009-01-18 18:01:49 +00001029 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1030 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1031 sw->obj_instance[0], sw->obj_instance[1],
1032 sw->obj_instance[2]);
1033
1034 /* FIXME: this is BS11 specific format */
1035 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1036 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1037 sw->file_version);
1038
1039 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001040}
Harald Welte4724f992009-01-18 18:01:49 +00001041
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001042struct sdp_firmware {
1043 char magic[4];
1044 char more_magic[4];
1045 unsigned int header_length;
1046 unsigned int file_length;
1047} __attribute__ ((packed));
1048
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001049static int parse_sdp_header(struct abis_nm_sw *sw)
1050{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001051 struct sdp_firmware firmware_header;
1052 int rc;
1053 struct stat stat;
1054
1055 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1056 if (rc != sizeof(firmware_header)) {
1057 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1058 return -1;
1059 }
1060
1061 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1062 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1063 return -1;
1064 }
1065
1066 if (firmware_header.more_magic[0] != 0x10 ||
1067 firmware_header.more_magic[1] != 0x02 ||
1068 firmware_header.more_magic[2] != 0x00 ||
1069 firmware_header.more_magic[3] != 0x00) {
1070 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1071 return -1;
1072 }
1073
1074
1075 if (fstat(sw->fd, &stat) == -1) {
1076 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1077 return -1;
1078 }
1079
1080 if (ntohl(firmware_header.file_length) != stat.st_size) {
1081 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1082 return -1;
1083 }
1084
1085 /* go back to the start as we checked the whole filesize.. */
1086 lseek(sw->fd, 0l, SEEK_SET);
1087 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1088 "There might be checksums in the file that are not\n"
1089 "verified and incomplete firmware might be flashed.\n"
1090 "There is absolutely no WARRANTY that flashing will\n"
1091 "work.\n");
1092 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001093}
1094
Harald Welte4724f992009-01-18 18:01:49 +00001095static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1096{
1097 char file_id[12+1];
1098 char file_version[80+1];
1099 int rc;
1100
1101 sw->fd = open(fname, O_RDONLY);
1102 if (sw->fd < 0)
1103 return sw->fd;
1104
1105 switch (sw->bts->type) {
1106 case GSM_BTS_TYPE_BS11:
1107 sw->stream = fdopen(sw->fd, "r");
1108 if (!sw->stream) {
1109 perror("fdopen");
1110 return -1;
1111 }
1112 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001113 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001114 file_id, file_version);
1115 if (rc != 2) {
1116 perror("parsing header line of software file");
1117 return -1;
1118 }
1119 strcpy((char *)sw->file_id, file_id);
1120 sw->file_id_len = strlen(file_id);
1121 strcpy((char *)sw->file_version, file_version);
1122 sw->file_version_len = strlen(file_version);
1123 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001124 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001125 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001126 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001127 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001128 rc = parse_sdp_header(sw);
1129 if (rc < 0) {
1130 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1131 return -1;
1132 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001133
1134 strcpy((char *)sw->file_id, "id");
1135 sw->file_id_len = 3;
1136 strcpy((char *)sw->file_version, "version");
1137 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001138 break;
Harald Welte4724f992009-01-18 18:01:49 +00001139 default:
1140 /* We don't know how to treat them yet */
1141 close(sw->fd);
1142 return -EINVAL;
1143 }
1144
1145 return 0;
1146}
1147
1148static void sw_close_file(struct abis_nm_sw *sw)
1149{
1150 switch (sw->bts->type) {
1151 case GSM_BTS_TYPE_BS11:
1152 fclose(sw->stream);
1153 break;
1154 default:
1155 close(sw->fd);
1156 break;
1157 }
1158}
1159
1160/* Fill the window */
1161static int sw_fill_window(struct abis_nm_sw *sw)
1162{
1163 int rc;
1164
1165 while (sw->seg_in_window < sw->window_size) {
1166 rc = sw_load_segment(sw);
1167 if (rc < 0)
1168 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001169 if (sw->last_seg)
1170 break;
Harald Welte4724f992009-01-18 18:01:49 +00001171 }
1172 return 0;
1173}
1174
1175/* callback function from abis_nm_rcvmsg() handler */
1176static int abis_nm_rcvmsg_sw(struct msgb *mb)
1177{
1178 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001179 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001180 int rc = -1;
1181 struct abis_nm_sw *sw = &g_sw;
1182 enum sw_state old_state = sw->state;
1183
Harald Welte3ffd1372009-02-01 22:15:49 +00001184 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001185
1186 switch (sw->state) {
1187 case SW_STATE_WAIT_INITACK:
1188 switch (foh->msg_type) {
1189 case NM_MT_LOAD_INIT_ACK:
1190 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001191 if (sw->cbfn)
1192 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1193 NM_MT_LOAD_INIT_ACK, mb,
1194 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001195 rc = sw_fill_window(sw);
1196 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001197 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001198 break;
1199 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001200 if (sw->forced) {
1201 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1202 "Init NACK\n");
1203 if (sw->cbfn)
1204 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1205 NM_MT_LOAD_INIT_ACK, mb,
1206 sw->cb_data, NULL);
1207 rc = sw_fill_window(sw);
1208 sw->state = SW_STATE_WAIT_SEGACK;
1209 } else {
1210 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001211 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001212 if (sw->cbfn)
1213 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1214 NM_MT_LOAD_INIT_NACK, mb,
1215 sw->cb_data, NULL);
1216 sw->state = SW_STATE_ERROR;
1217 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001218 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001219 break;
1220 }
1221 break;
1222 case SW_STATE_WAIT_SEGACK:
1223 switch (foh->msg_type) {
1224 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001225 if (sw->cbfn)
1226 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1227 NM_MT_LOAD_SEG_ACK, mb,
1228 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001229 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001230 if (!sw->last_seg) {
1231 /* fill window with more segments */
1232 rc = sw_fill_window(sw);
1233 sw->state = SW_STATE_WAIT_SEGACK;
1234 } else {
1235 /* end the transfer */
1236 sw->state = SW_STATE_WAIT_ENDACK;
1237 rc = sw_load_end(sw);
1238 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001239 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001240 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001241 case NM_MT_LOAD_ABORT:
1242 if (sw->cbfn)
1243 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1244 NM_MT_LOAD_ABORT, mb,
1245 sw->cb_data, NULL);
1246 break;
Harald Welte4724f992009-01-18 18:01:49 +00001247 }
1248 break;
1249 case SW_STATE_WAIT_ENDACK:
1250 switch (foh->msg_type) {
1251 case NM_MT_LOAD_END_ACK:
1252 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001253 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1254 sw->bts->nr);
1255 sw->state = SW_STATE_NONE;
1256 if (sw->cbfn)
1257 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1258 NM_MT_LOAD_END_ACK, mb,
1259 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001260 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001261 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001262 break;
1263 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001264 if (sw->forced) {
1265 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1266 "End NACK\n");
1267 sw->state = SW_STATE_NONE;
1268 if (sw->cbfn)
1269 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1270 NM_MT_LOAD_END_ACK, mb,
1271 sw->cb_data, NULL);
1272 } else {
1273 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001274 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001275 sw->state = SW_STATE_ERROR;
1276 if (sw->cbfn)
1277 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1278 NM_MT_LOAD_END_NACK, mb,
1279 sw->cb_data, NULL);
1280 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001281 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001282 break;
1283 }
1284 case SW_STATE_WAIT_ACTACK:
1285 switch (foh->msg_type) {
1286 case NM_MT_ACTIVATE_SW_ACK:
1287 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001288 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001289 sw->state = SW_STATE_NONE;
1290 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001291 if (sw->cbfn)
1292 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1293 NM_MT_ACTIVATE_SW_ACK, mb,
1294 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001295 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001296 break;
1297 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001298 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001299 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001300 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001301 if (sw->cbfn)
1302 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1303 NM_MT_ACTIVATE_SW_NACK, mb,
1304 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001305 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001306 break;
1307 }
1308 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001309 switch (foh->msg_type) {
1310 case NM_MT_ACTIVATE_SW_ACK:
1311 rc = 0;
1312 break;
1313 }
1314 break;
Harald Welte4724f992009-01-18 18:01:49 +00001315 case SW_STATE_ERROR:
1316 break;
1317 }
1318
1319 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001320 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001321 foh->msg_type, old_state, sw->state);
1322
1323 return rc;
1324}
1325
1326/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001327int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001328 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001329 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001330{
1331 struct abis_nm_sw *sw = &g_sw;
1332 int rc;
1333
Harald Welte5e4d1b32009-02-01 13:36:56 +00001334 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1335 bts->nr, fname);
1336
Harald Welte4724f992009-01-18 18:01:49 +00001337 if (sw->state != SW_STATE_NONE)
1338 return -EBUSY;
1339
1340 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001341 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001342
1343 switch (bts->type) {
1344 case GSM_BTS_TYPE_BS11:
1345 sw->obj_class = NM_OC_SITE_MANAGER;
1346 sw->obj_instance[0] = 0xff;
1347 sw->obj_instance[1] = 0xff;
1348 sw->obj_instance[2] = 0xff;
1349 break;
1350 case GSM_BTS_TYPE_NANOBTS:
1351 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001352 sw->obj_instance[0] = sw->bts->nr;
1353 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001354 sw->obj_instance[2] = 0xff;
1355 break;
1356 case GSM_BTS_TYPE_UNKNOWN:
1357 default:
1358 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1359 return -1;
1360 break;
1361 }
Harald Welte4724f992009-01-18 18:01:49 +00001362 sw->window_size = win_size;
1363 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001364 sw->cbfn = cbfn;
1365 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001366 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001367
1368 rc = sw_open_file(sw, fname);
1369 if (rc < 0) {
1370 sw->state = SW_STATE_NONE;
1371 return rc;
1372 }
1373
1374 return sw_load_init(sw);
1375}
Harald Welte52b1f982008-12-23 20:25:15 +00001376
Harald Welte1602ade2009-01-29 21:12:39 +00001377int abis_nm_software_load_status(struct gsm_bts *bts)
1378{
1379 struct abis_nm_sw *sw = &g_sw;
1380 struct stat st;
1381 int rc, percent;
1382
1383 rc = fstat(sw->fd, &st);
1384 if (rc < 0) {
1385 perror("ERROR during stat");
1386 return rc;
1387 }
1388
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001389 if (sw->stream)
1390 percent = (ftell(sw->stream) * 100) / st.st_size;
1391 else
1392 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001393 return percent;
1394}
1395
Harald Welte5e4d1b32009-02-01 13:36:56 +00001396/* Activate the specified software into the BTS */
1397int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1398 gsm_cbfn *cbfn, void *cb_data)
1399{
1400 struct abis_nm_sw *sw = &g_sw;
1401 int rc;
1402
1403 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1404 bts->nr, fname);
1405
1406 if (sw->state != SW_STATE_NONE)
1407 return -EBUSY;
1408
1409 sw->bts = bts;
1410 sw->obj_class = NM_OC_SITE_MANAGER;
1411 sw->obj_instance[0] = 0xff;
1412 sw->obj_instance[1] = 0xff;
1413 sw->obj_instance[2] = 0xff;
1414 sw->state = SW_STATE_WAIT_ACTACK;
1415 sw->cbfn = cbfn;
1416 sw->cb_data = cb_data;
1417
1418 /* Open the file in order to fill some sw struct members */
1419 rc = sw_open_file(sw, fname);
1420 if (rc < 0) {
1421 sw->state = SW_STATE_NONE;
1422 return rc;
1423 }
1424 sw_close_file(sw);
1425
1426 return sw_activate(sw);
1427}
1428
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001429static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1430 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001431{
Harald Welteadaf08b2009-01-18 11:08:10 +00001432 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001433 ch->bts_port = bts_port;
1434 ch->timeslot = ts_nr;
1435 ch->subslot = subslot_nr;
1436}
1437
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001438int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1439 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1440 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001441{
1442 struct abis_om_hdr *oh;
1443 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001444 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001445 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001446
1447 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1448 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1449 bts->bts_nr, trx_nr, 0xff);
1450
Harald Welte8470bf22008-12-25 23:28:35 +00001451 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001452
1453 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1454 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1455
1456 return abis_nm_sendmsg(bts, msg);
1457}
1458
1459/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1460int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001461 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001462{
Harald Welte8470bf22008-12-25 23:28:35 +00001463 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001464 struct abis_om_hdr *oh;
1465 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001466 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001467
1468 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001469 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001470 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1471
1472 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1473 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1474
1475 return abis_nm_sendmsg(bts, msg);
1476}
1477
1478#if 0
1479int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1480 struct abis_nm_abis_channel *chan)
1481{
1482}
1483#endif
1484
1485int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001486 uint8_t e1_port, uint8_t e1_timeslot,
1487 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001488{
1489 struct gsm_bts *bts = ts->trx->bts;
1490 struct abis_om_hdr *oh;
1491 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001492 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001493
1494 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1495 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001496 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001497
1498 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1499 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1500
Harald Weltef325eb42009-02-19 17:07:39 +00001501 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1502 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001503 e1_port, e1_timeslot, e1_subslot);
1504
Harald Welte52b1f982008-12-23 20:25:15 +00001505 return abis_nm_sendmsg(bts, msg);
1506}
1507
1508#if 0
1509int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1510 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001511 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001512{
1513}
1514#endif
1515
Max1ebf23b2017-05-10 12:21:17 +02001516/* 3GPP TS 52.021 § 8.11.1 */
1517int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1518 const uint8_t *attr, uint8_t attr_len)
Harald Weltefe568f22012-08-14 19:15:57 +02001519{
1520 struct abis_om_hdr *oh;
1521 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001522
1523 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1524
1525 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1526 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1527 bts_nr, trx_nr, ts_nr);
1528 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1529
1530 return abis_nm_sendmsg(bts, msg);
1531}
1532
Harald Welte22af0db2009-02-14 15:41:08 +00001533/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001534int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001535{
1536 struct abis_om_hdr *oh;
1537 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001538 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001539
1540 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1541
1542 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001543 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 +00001544 cur = msgb_put(msg, attr_len);
1545 memcpy(cur, attr, attr_len);
1546
1547 return abis_nm_sendmsg(bts, msg);
1548}
1549
1550/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001551int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001552{
1553 struct abis_om_hdr *oh;
1554 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001555 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001556
1557 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1558
1559 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1560 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001561 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001562 cur = msgb_put(msg, attr_len);
1563 memcpy(cur, attr, attr_len);
1564
1565 return abis_nm_sendmsg(trx->bts, msg);
1566}
1567
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001568int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1569{
1570 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1571 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1572}
1573
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001574static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1575 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001576{
1577 int i;
1578
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001579 *reason = "Reason unknown";
1580
Harald Welte39c7deb2009-08-09 21:49:48 +02001581 /* As it turns out, the BS-11 has some very peculiar restrictions
1582 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301583 switch (ts->trx->bts->type) {
1584 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001585 switch (chan_comb) {
1586 case NM_CHANC_TCHHalf:
1587 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001588 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001589 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001590 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001591 return -EINVAL;
1592 case NM_CHANC_SDCCH:
1593 /* only one SDCCH/8 per TRX */
1594 for (i = 0; i < TRX_NR_TS; i++) {
1595 if (i == ts->nr)
1596 continue;
1597 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001598 NM_CHANC_SDCCH) {
1599 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001600 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001601 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001602 }
1603 /* not allowed for TS0 of BCCH-TRX */
1604 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001605 ts->nr == 0) {
1606 *reason = "SDCCH/8 must be on TS0.";
1607 return -EINVAL;
1608 }
1609
Harald Welte39c7deb2009-08-09 21:49:48 +02001610 /* not on the same TRX that has a BCCH+SDCCH4
1611 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001612 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001613 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001614 ts->trx->ts[0].nm_chan_comb == 8)) {
1615 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1616 return -EINVAL;
1617 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001618 break;
1619 case NM_CHANC_mainBCCH:
1620 case NM_CHANC_BCCHComb:
1621 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001622 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1623 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001624 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001625 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001626 break;
1627 case NM_CHANC_BCCH:
1628 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001629 if (ts->trx != ts->trx->bts->c0) {
1630 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001631 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001632 }
1633 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1634 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001635 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001636 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001637 break;
1638 case 8: /* this is not like 08.58, but in fact
1639 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1640 /* FIXME: only one CBCH allowed per cell */
1641 break;
1642 }
Harald Welted6575f92009-12-02 02:45:23 +05301643 break;
1644 case GSM_BTS_TYPE_NANOBTS:
1645 switch (ts->nr) {
1646 case 0:
1647 if (ts->trx->nr == 0) {
1648 /* only on TRX0 */
1649 switch (chan_comb) {
1650 case NM_CHANC_BCCH:
1651 case NM_CHANC_mainBCCH:
1652 case NM_CHANC_BCCHComb:
1653 return 0;
1654 break;
1655 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001656 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301657 return -EINVAL;
1658 }
1659 } else {
1660 switch (chan_comb) {
1661 case NM_CHANC_TCHFull:
1662 case NM_CHANC_TCHHalf:
1663 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1664 return 0;
1665 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001666 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301667 return -EINVAL;
1668 }
1669 }
1670 break;
1671 case 1:
1672 if (ts->trx->nr == 0) {
1673 switch (chan_comb) {
1674 case NM_CHANC_SDCCH_CBCH:
1675 if (ts->trx->ts[0].nm_chan_comb ==
1676 NM_CHANC_mainBCCH)
1677 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001678 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301679 return -EINVAL;
1680 case NM_CHANC_SDCCH:
1681 case NM_CHANC_TCHFull:
1682 case NM_CHANC_TCHHalf:
1683 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1684 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001685 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301686 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001687 default:
1688 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1689 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301690 }
1691 } else {
1692 switch (chan_comb) {
1693 case NM_CHANC_SDCCH:
1694 case NM_CHANC_TCHFull:
1695 case NM_CHANC_TCHHalf:
1696 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1697 return 0;
1698 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001699 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301700 return -EINVAL;
1701 }
1702 }
1703 break;
1704 case 2:
1705 case 3:
1706 case 4:
1707 case 5:
1708 case 6:
1709 case 7:
1710 switch (chan_comb) {
1711 case NM_CHANC_TCHFull:
1712 case NM_CHANC_TCHHalf:
1713 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1714 return 0;
1715 case NM_CHANC_IPAC_PDCH:
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 if (ts->trx->nr == 0)
1719 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001720 else {
1721 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301722 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001723 }
Harald Welted6575f92009-12-02 02:45:23 +05301724 }
1725 break;
1726 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001727 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301728 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001729 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001730 /* no known restrictions */
1731 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301732 default:
1733 /* unknown BTS type */
1734 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001735 }
1736 return 0;
1737}
1738
Harald Welte22af0db2009-02-14 15:41:08 +00001739/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001740int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001741{
1742 struct gsm_bts *bts = ts->trx->bts;
1743 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001744 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001745 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001746 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001747 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001748
1749 if (bts->type == GSM_BTS_TYPE_BS11)
1750 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001751
Harald Weltef325eb42009-02-19 17:07:39 +00001752 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001753 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001754 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001755 LOGP(DNM, LOGL_ERROR,
1756 "Invalid Channel Combination %d on %s. Reason: %s\n",
1757 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001758 return -EINVAL;
1759 }
1760 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001761
Harald Welte52b1f982008-12-23 20:25:15 +00001762 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001763 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001764 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001765 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001766 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001767 if (ts->hopping.enabled) {
1768 unsigned int i;
1769 uint8_t *len;
1770
Harald Welte6e0cd042009-09-12 13:05:33 +02001771 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1772 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001773
1774 /* build the ARFCN list */
1775 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1776 len = msgb_put(msg, 1);
1777 *len = 0;
1778 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1779 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1780 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001781 /* At least BS-11 wants a TLV16 here */
1782 if (bts->type == GSM_BTS_TYPE_BS11)
1783 *len += 1;
1784 else
1785 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001786 }
1787 }
Harald Weltee0590df2009-02-15 03:34:15 +00001788 }
Harald Welte1fe24122014-01-19 17:18:21 +01001789 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001790 if (bts->type == GSM_BTS_TYPE_BS11)
1791 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001792
1793 return abis_nm_sendmsg(bts, msg);
1794}
1795
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001796int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1797 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001798{
1799 struct abis_om_hdr *oh;
1800 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001801 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1802 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001803
1804 if (nack) {
1805 len += 2;
1806 msgtype = NM_MT_SW_ACT_REQ_NACK;
1807 }
Harald Welte34a99682009-02-13 02:41:40 +00001808
1809 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001810 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1811
Harald Welte34a99682009-02-13 02:41:40 +00001812 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001813 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001814 memcpy(ptr, attr, att_len);
1815 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001816 if (nack)
1817 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001818
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001819 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001820}
1821
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001822int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001823{
Harald Welte8470bf22008-12-25 23:28:35 +00001824 struct msgb *msg = nm_msgb_alloc();
1825 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001826 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001827
1828 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1829 fill_om_hdr(oh, len);
1830 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001831 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001832
1833 return abis_nm_sendmsg(bts, msg);
1834}
1835
1836/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001837static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001838{
1839 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001840 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001841
1842 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001843 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001844 0xff, 0xff, 0xff);
1845
1846 return abis_nm_sendmsg(bts, msg);
1847}
1848
Harald Welte34a99682009-02-13 02:41:40 +00001849/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001850int 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 +00001851{
1852 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001853 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001854 struct msgb *msg = nm_msgb_alloc();
1855
1856 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001857 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001858
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001859 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001860 DEBUGPC(DNM, "Sending OPSTART\n");
1861
Harald Welte34a99682009-02-13 02:41:40 +00001862 return abis_nm_sendmsg(bts, msg);
1863}
1864
1865/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001866int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1867 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001868{
1869 struct abis_om_hdr *oh;
1870 struct msgb *msg = nm_msgb_alloc();
1871
1872 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1873 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1874 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1875
1876 return abis_nm_sendmsg(bts, msg);
1877}
1878
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001879int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1880 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001881{
1882 struct abis_om_hdr *oh;
1883 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001884 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001885
1886 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1887 e1_port0, ts0, e1_port1, ts1);
1888
1889 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1890 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1891 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1892
1893 attr = msgb_put(msg, 3);
1894 attr[0] = NM_ATT_MDROP_LINK;
1895 attr[1] = e1_port0;
1896 attr[2] = ts0;
1897
1898 attr = msgb_put(msg, 3);
1899 attr[0] = NM_ATT_MDROP_NEXT;
1900 attr[1] = e1_port1;
1901 attr[2] = ts1;
1902
1903 return abis_nm_sendmsg(bts, msg);
1904}
Harald Welte34a99682009-02-13 02:41:40 +00001905
Harald Weltec7310382009-08-08 00:02:36 +02001906/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001907int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1908 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1909 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001910{
1911 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001912
Harald Welte15c61722011-05-22 22:45:37 +02001913 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001914
1915 if (!msg)
1916 msg = nm_msgb_alloc();
1917
1918 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1919 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1920 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1921 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001922 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001923
1924 return abis_nm_sendmsg(bts, msg);
1925}
1926
Harald Welte52b1f982008-12-23 20:25:15 +00001927int abis_nm_event_reports(struct gsm_bts *bts, int on)
1928{
1929 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001930 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001931 else
Harald Welte227d4072009-01-03 08:16:25 +00001932 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001933}
1934
Harald Welte47d88ae2009-01-04 12:02:08 +00001935/* Siemens (or BS-11) specific commands */
1936
Harald Welte3ffd1372009-02-01 22:15:49 +00001937int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1938{
1939 if (reconnect == 0)
1940 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1941 else
1942 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1943}
1944
Harald Welteb8427972009-02-05 19:27:17 +00001945int abis_nm_bs11_restart(struct gsm_bts *bts)
1946{
1947 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1948}
1949
1950
Harald Welte268bb402009-02-01 19:11:56 +00001951struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001952 uint16_t year;
1953 uint8_t month;
1954 uint8_t day;
1955 uint8_t hour;
1956 uint8_t min;
1957 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001958} __attribute__((packed));
1959
1960
1961void get_bs11_date_time(struct bs11_date_time *aet)
1962{
1963 time_t t;
1964 struct tm *tm;
1965
1966 t = time(NULL);
1967 tm = localtime(&t);
1968 aet->sec = tm->tm_sec;
1969 aet->min = tm->tm_min;
1970 aet->hour = tm->tm_hour;
1971 aet->day = tm->tm_mday;
1972 aet->month = tm->tm_mon;
1973 aet->year = htons(1900 + tm->tm_year);
1974}
1975
Harald Welte05188ee2009-01-18 11:39:08 +00001976int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001977{
Harald Welte4668fda2009-01-03 08:19:29 +00001978 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001979}
1980
Harald Welte05188ee2009-01-18 11:39:08 +00001981int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001982{
1983 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001984 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001985 else
Harald Welte4668fda2009-01-03 08:19:29 +00001986 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001987}
Harald Welte47d88ae2009-01-04 12:02:08 +00001988
Harald Welte05188ee2009-01-18 11:39:08 +00001989int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001990 enum abis_bs11_objtype type, uint8_t idx,
1991 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001992{
1993 struct abis_om_hdr *oh;
1994 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001995 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001996
1997 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001998 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001999 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002000 cur = msgb_put(msg, attr_len);
2001 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002002
2003 return abis_nm_sendmsg(bts, msg);
2004}
2005
Harald Welte78fc0d42009-02-19 02:50:57 +00002006int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002007 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002008{
2009 struct abis_om_hdr *oh;
2010 struct msgb *msg = nm_msgb_alloc();
2011
2012 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2013 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2014 NM_OC_BS11, type, 0, idx);
2015
2016 return abis_nm_sendmsg(bts, msg);
2017}
2018
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002019int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002020{
2021 struct abis_om_hdr *oh;
2022 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002023 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002024
2025 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002026 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002027 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2028 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002029
2030 return abis_nm_sendmsg(bts, msg);
2031}
2032
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002033int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002034{
2035 struct abis_om_hdr *oh;
2036 struct msgb *msg = nm_msgb_alloc();
2037
2038 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2039 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002040 idx, 0xff, 0xff);
2041
2042 return abis_nm_sendmsg(bts, msg);
2043}
2044
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002045int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002046{
2047 struct abis_om_hdr *oh;
2048 struct msgb *msg = nm_msgb_alloc();
2049
2050 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2051 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2052 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002053
2054 return abis_nm_sendmsg(bts, msg);
2055}
Harald Welte05188ee2009-01-18 11:39:08 +00002056
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002057static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002058int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2059{
2060 struct abis_om_hdr *oh;
2061 struct msgb *msg = nm_msgb_alloc();
2062
2063 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2064 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2065 0xff, 0xff, 0xff);
2066 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2067
2068 return abis_nm_sendmsg(bts, msg);
2069}
2070
Harald Welteb6c92ae2009-02-21 20:15:32 +00002071/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002072int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2073 uint8_t e1_timeslot, uint8_t e1_subslot,
2074 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002075{
2076 struct abis_om_hdr *oh;
2077 struct abis_nm_channel *ch;
2078 struct msgb *msg = nm_msgb_alloc();
2079
2080 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002081 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002082 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2083
2084 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2085 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002086 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002087
2088 return abis_nm_sendmsg(bts, msg);
2089}
2090
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002091int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002092{
2093 struct abis_om_hdr *oh;
2094 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002095
2096 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002097 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002098 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2099 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2100
2101 return abis_nm_sendmsg(trx->bts, msg);
2102}
2103
Harald Welte78fc0d42009-02-19 02:50:57 +00002104int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2105{
2106 struct abis_om_hdr *oh;
2107 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002108 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002109
2110 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2111 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2112 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2113 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2114
2115 return abis_nm_sendmsg(trx->bts, msg);
2116}
2117
Harald Welteaaf02d92009-04-29 13:25:57 +00002118int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2119{
2120 struct abis_om_hdr *oh;
2121 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002122 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002123
2124 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2125 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2126 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002127 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002128
2129 return abis_nm_sendmsg(bts, msg);
2130}
2131
Harald Welteef061952009-05-17 12:43:42 +00002132int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2133{
2134 struct abis_om_hdr *oh;
2135 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002136 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002137 NM_ATT_BS11_CCLK_TYPE };
2138
2139 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2140 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2141 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2142 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2143
2144 return abis_nm_sendmsg(bts, msg);
2145
2146}
Harald Welteaaf02d92009-04-29 13:25:57 +00002147
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002148//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002149
Harald Welte1bc09062009-01-18 14:17:52 +00002150int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002151{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002152 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2153}
2154
Daniel Willmann4b054c82010-01-07 00:46:26 +01002155int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2156{
2157 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2158}
2159
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002160int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002161{
Harald Welte05188ee2009-01-18 11:39:08 +00002162 struct abis_om_hdr *oh;
2163 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002164 struct bs11_date_time bdt;
2165
2166 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002167
2168 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002169 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002170 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002171 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002172 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002173 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002174 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002175 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002176 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002177 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002178 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002179 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002180 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002181 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002182 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002183 }
Harald Welte05188ee2009-01-18 11:39:08 +00002184
2185 return abis_nm_sendmsg(bts, msg);
2186}
Harald Welte1bc09062009-01-18 14:17:52 +00002187
2188int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2189{
2190 struct abis_om_hdr *oh;
2191 struct msgb *msg;
2192
2193 if (strlen(password) != 10)
2194 return -EINVAL;
2195
2196 msg = nm_msgb_alloc();
2197 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002198 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002199 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002200 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002201
2202 return abis_nm_sendmsg(bts, msg);
2203}
2204
Harald Weltee69f5fb2009-04-28 16:31:38 +00002205/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2206int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2207{
2208 struct abis_om_hdr *oh;
2209 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002210 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002211
2212 msg = nm_msgb_alloc();
2213 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2214 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2215 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002216
2217 if (locked)
2218 tlv_value = BS11_LI_PLL_LOCKED;
2219 else
2220 tlv_value = BS11_LI_PLL_STANDALONE;
2221
2222 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002223
2224 return abis_nm_sendmsg(bts, msg);
2225}
2226
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002227/* Set the calibration value of the PLL (work value/set value)
2228 * It depends on the login which one is changed */
2229int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2230{
2231 struct abis_om_hdr *oh;
2232 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002233 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002234
2235 msg = nm_msgb_alloc();
2236 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2237 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2238 BS11_OBJ_TRX1, 0x00, 0x00);
2239
2240 tlv_value[0] = value>>8;
2241 tlv_value[1] = value&0xff;
2242
2243 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2244
2245 return abis_nm_sendmsg(bts, msg);
2246}
2247
Harald Welte1bc09062009-01-18 14:17:52 +00002248int abis_nm_bs11_get_state(struct gsm_bts *bts)
2249{
2250 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2251}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002252
2253/* BS11 SWL */
2254
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002255void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002256
Harald Welte5e4d1b32009-02-01 13:36:56 +00002257struct abis_nm_bs11_sw {
2258 struct gsm_bts *bts;
2259 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002260 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002261 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002262 struct llist_head file_list;
2263 gsm_cbfn *user_cb; /* specified by the user */
2264};
2265static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2266
2267struct file_list_entry {
2268 struct llist_head list;
2269 char fname[PATH_MAX];
2270};
2271
2272struct file_list_entry *fl_dequeue(struct llist_head *queue)
2273{
2274 struct llist_head *lh;
2275
2276 if (llist_empty(queue))
2277 return NULL;
2278
2279 lh = queue->next;
2280 llist_del(lh);
2281
2282 return llist_entry(lh, struct file_list_entry, list);
2283}
2284
2285static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2286{
2287 char linebuf[255];
2288 struct llist_head *lh, *lh2;
2289 FILE *swl;
2290 int rc = 0;
2291
2292 swl = fopen(bs11_sw->swl_fname, "r");
2293 if (!swl)
2294 return -ENODEV;
2295
2296 /* zero the stale file list, if any */
2297 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2298 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002299 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002300 }
2301
2302 while (fgets(linebuf, sizeof(linebuf), swl)) {
2303 char file_id[12+1];
2304 char file_version[80+1];
2305 struct file_list_entry *fle;
2306 static char dir[PATH_MAX];
2307
2308 if (strlen(linebuf) < 4)
2309 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002310
Harald Welte5e4d1b32009-02-01 13:36:56 +00002311 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2312 if (rc < 0) {
2313 perror("ERR parsing SWL file");
2314 rc = -EINVAL;
2315 goto out;
2316 }
2317 if (rc < 2)
2318 continue;
2319
Harald Welte470ec292009-06-26 20:25:23 +02002320 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002321 if (!fle) {
2322 rc = -ENOMEM;
2323 goto out;
2324 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002325
2326 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002327 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002328 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2329 strcat(fle->fname, "/");
2330 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002331
2332 llist_add_tail(&fle->list, &bs11_sw->file_list);
2333 }
2334
2335out:
2336 fclose(swl);
2337 return rc;
2338}
2339
2340/* bs11 swload specific callback, passed to abis_nm core swload */
2341static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2342 struct msgb *msg, void *data, void *param)
2343{
2344 struct abis_nm_bs11_sw *bs11_sw = data;
2345 struct file_list_entry *fle;
2346 int rc = 0;
2347
Harald Welte5e4d1b32009-02-01 13:36:56 +00002348 switch (event) {
2349 case NM_MT_LOAD_END_ACK:
2350 fle = fl_dequeue(&bs11_sw->file_list);
2351 if (fle) {
2352 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002353 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002354 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002355 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002356 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002357 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002358 } else {
2359 /* activate the SWL */
2360 rc = abis_nm_software_activate(bs11_sw->bts,
2361 bs11_sw->swl_fname,
2362 bs11_swload_cbfn,
2363 bs11_sw);
2364 }
2365 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002366 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002367 case NM_MT_LOAD_END_NACK:
2368 case NM_MT_LOAD_INIT_ACK:
2369 case NM_MT_LOAD_INIT_NACK:
2370 case NM_MT_ACTIVATE_SW_NACK:
2371 case NM_MT_ACTIVATE_SW_ACK:
2372 default:
2373 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002374 if (bs11_sw->user_cb)
2375 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002376 break;
2377 }
2378
2379 return rc;
2380}
2381
2382/* Siemens provides a SWL file that is a mere listing of all the other
2383 * files that are part of a software release. We need to upload first
2384 * the list file, and then each file that is listed in the list file */
2385int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002386 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002387{
2388 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2389 struct file_list_entry *fle;
2390 int rc = 0;
2391
2392 INIT_LLIST_HEAD(&bs11_sw->file_list);
2393 bs11_sw->bts = bts;
2394 bs11_sw->win_size = win_size;
2395 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002396 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002397
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002398 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002399 rc = bs11_read_swl_file(bs11_sw);
2400 if (rc < 0)
2401 return rc;
2402
2403 /* dequeue next item in file list */
2404 fle = fl_dequeue(&bs11_sw->file_list);
2405 if (!fle)
2406 return -EINVAL;
2407
2408 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002409 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002410 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002411 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002412 return rc;
2413}
2414
Harald Welte5083b0b2009-02-02 19:20:52 +00002415#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002416static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002417 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2418 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2419 NM_ATT_BS11_LMT_USER_NAME,
2420
2421 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2422
2423 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2424
2425 NM_ATT_BS11_SW_LOAD_STORED };
2426
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002427static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002428 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2429 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2430 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2431 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002432#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002433
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002434static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002435 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2436 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002437 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002438
2439int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2440{
2441 struct abis_om_hdr *oh;
2442 struct msgb *msg = nm_msgb_alloc();
2443
2444 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2445 /* SiemensHW CCTRL object */
2446 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2447 0x03, 0x00, 0x00);
2448 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2449
2450 return abis_nm_sendmsg(bts, msg);
2451}
Harald Welte268bb402009-02-01 19:11:56 +00002452
2453int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2454{
2455 struct abis_om_hdr *oh;
2456 struct msgb *msg = nm_msgb_alloc();
2457 struct bs11_date_time aet;
2458
2459 get_bs11_date_time(&aet);
2460 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2461 /* SiemensHW CCTRL object */
2462 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2463 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002464 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002465
2466 return abis_nm_sendmsg(bts, msg);
2467}
Harald Welte5c1e4582009-02-15 11:57:29 +00002468
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002469int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002470{
2471 struct abis_om_hdr *oh;
2472 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002473 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002474
2475 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2476 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2477 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2478 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2479
2480 return abis_nm_sendmsg(bts, msg);
2481}
2482
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002483int 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 +02002484{
2485 struct abis_om_hdr *oh;
2486 struct msgb *msg = nm_msgb_alloc();
2487 struct bs11_date_time aet;
2488
2489 get_bs11_date_time(&aet);
2490 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2491 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2492 bport, 0xff, 0x02);
2493 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2494
2495 return abis_nm_sendmsg(bts, msg);
2496}
2497
Harald Welte5c1e4582009-02-15 11:57:29 +00002498/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002499static const char ipaccess_magic[] = "com.ipaccess";
2500
Harald Welte677c21f2009-02-17 13:22:23 +00002501
2502static int abis_nm_rx_ipacc(struct msgb *msg)
2503{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002504 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002505 struct abis_om_hdr *oh = msgb_l2(msg);
2506 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002507 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002508 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002509 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002510 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002511
2512 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002513 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002514 return -EINVAL;
2515 }
2516
Harald Welte193fefc2009-04-30 15:16:27 +00002517 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002518 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002519
Harald Welte15c61722011-05-22 22:45:37 +02002520 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002521
Harald Welte746d6092009-10-19 22:11:11 +02002522 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002523
Harald Welte677c21f2009-02-17 13:22:23 +00002524 switch (foh->msg_type) {
2525 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002526 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002527 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2528 memcpy(&addr,
2529 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2530
2531 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2532 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002533 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002534 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002535 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002536 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002537 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2538 DEBUGPC(DNM, "STREAM=0x%02x ",
2539 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002540 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002541 break;
2542 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002543 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002544 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002545 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002546 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002547 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002548 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002549 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002550 case NM_MT_IPACC_SET_NVATTR_ACK:
2551 DEBUGPC(DNM, "SET NVATTR ACK\n");
2552 /* FIXME: decode and show the actual attributes */
2553 break;
2554 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002555 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002556 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002557 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002558 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002559 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002560 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002561 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002562 case NM_MT_IPACC_GET_NVATTR_ACK:
2563 DEBUGPC(DNM, "GET NVATTR ACK\n");
2564 /* FIXME: decode and show the actual attributes */
2565 break;
2566 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002567 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002568 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002569 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002570 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002571 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002572 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002573 break;
Harald Welte15c44172009-10-08 20:15:24 +02002574 case NM_MT_IPACC_SET_ATTR_ACK:
2575 DEBUGPC(DNM, "SET ATTR ACK\n");
2576 break;
2577 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002578 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002579 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002580 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002581 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002582 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002583 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002584 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002585 default:
2586 DEBUGPC(DNM, "unknown\n");
2587 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002588 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002589
2590 /* signal handling */
2591 switch (foh->msg_type) {
2592 case NM_MT_IPACC_RSL_CONNECT_NACK:
2593 case NM_MT_IPACC_SET_NVATTR_NACK:
2594 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002595 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 +01002596 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002597 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002598 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002599 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002600 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 +01002601 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002602 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002603 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002604 default:
2605 break;
2606 }
2607
Harald Welte677c21f2009-02-17 13:22:23 +00002608 return 0;
2609}
2610
Harald Welte193fefc2009-04-30 15:16:27 +00002611/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002612int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2613 uint8_t obj_class, uint8_t bts_nr,
2614 uint8_t trx_nr, uint8_t ts_nr,
2615 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002616{
2617 struct msgb *msg = nm_msgb_alloc();
2618 struct abis_om_hdr *oh;
2619 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002620 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002621
2622 /* construct the 12.21 OM header, observe the erroneous length */
2623 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2624 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2625 oh->mdisc = ABIS_OM_MDISC_MANUF;
2626
2627 /* add the ip.access magic */
2628 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2629 *data++ = sizeof(ipaccess_magic);
2630 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2631
2632 /* fill the 12.21 FOM header */
2633 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2634 foh->msg_type = msg_type;
2635 foh->obj_class = obj_class;
2636 foh->obj_inst.bts_nr = bts_nr;
2637 foh->obj_inst.trx_nr = trx_nr;
2638 foh->obj_inst.ts_nr = ts_nr;
2639
2640 if (attr && attr_len) {
2641 data = msgb_put(msg, attr_len);
2642 memcpy(data, attr, attr_len);
2643 }
2644
2645 return abis_nm_sendmsg(bts, msg);
2646}
Harald Welte677c21f2009-02-17 13:22:23 +00002647
Harald Welte193fefc2009-04-30 15:16:27 +00002648/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002649int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002650 int attr_len)
2651{
Harald Welte2ef156d2010-01-07 20:39:42 +01002652 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2653 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002654 attr_len);
2655}
2656
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002657int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002658 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002659{
2660 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002661 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002662 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2663 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2664
2665 int attr_len = sizeof(attr);
2666
2667 ia.s_addr = htonl(ip);
2668 attr[1] = stream;
2669 attr[3] = port >> 8;
2670 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002671 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002672
2673 /* if ip == 0, we use the default IP */
2674 if (ip == 0)
2675 attr_len -= 5;
2676
2677 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002678 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002679
2680 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2681 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2682 trx->nr, 0xff, attr, attr_len);
2683}
2684
Harald Welte193fefc2009-04-30 15:16:27 +00002685/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002686int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002687{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002688 struct abis_om_hdr *oh;
2689 struct msgb *msg = nm_msgb_alloc();
2690
2691 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2692 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2693 trx->bts->nr, trx->nr, 0xff);
2694
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002695 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002696}
Harald Weltedaef5212009-10-24 10:20:41 +02002697
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002698int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2699 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2700 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002701{
2702 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2703 obj_class, bts_nr, trx_nr, ts_nr,
2704 attr, attr_len);
2705}
Harald Welte0f255852009-11-12 14:48:42 +01002706
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002707void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002708{
2709 /* we simply reuse the GSM48 function and overwrite the RAC
2710 * with the Cell ID */
2711 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002712 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002713}
2714
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002715void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2716{
2717 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2718
Harald Welted64c0bc2011-05-30 12:07:53 +02002719 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002720 if (!trx->bts || !trx->bts->oml_link)
2721 return;
2722
2723 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2724 trx->bts->bts_nr, trx->nr, 0xff,
2725 new_state);
2726}
2727
Harald Welte92b1fe42010-03-25 11:45:30 +08002728static const struct value_string ipacc_testres_names[] = {
2729 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2730 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2731 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2732 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2733 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2734 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002735};
2736
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002737const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002738{
Harald Welte92b1fe42010-03-25 11:45:30 +08002739 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002740}
2741
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002742void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002743{
2744 cid->mcc = (buf[0] & 0xf) * 100;
2745 cid->mcc += (buf[0] >> 4) * 10;
2746 cid->mcc += (buf[1] & 0xf) * 1;
2747
2748 if (buf[1] >> 4 == 0xf) {
2749 cid->mnc = (buf[2] & 0xf) * 10;
2750 cid->mnc += (buf[2] >> 4) * 1;
2751 } else {
2752 cid->mnc = (buf[2] & 0xf) * 100;
2753 cid->mnc += (buf[2] >> 4) * 10;
2754 cid->mnc += (buf[1] >> 4) * 1;
2755 }
2756
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002757 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2758 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002759}
2760
Harald Welte0f255852009-11-12 14:48:42 +01002761/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002762int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002763{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002764 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002765 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002766
Harald Welteaf109b92010-07-22 18:14:36 +02002767 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002768
2769 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2770 return -EINVAL;
2771 cur++;
2772
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002773 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002774 cur += 2;
2775
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002776 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002777 cur += 2;
2778
2779 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2780 binf->freq_qual = *cur >> 2;
2781
Harald Welteaf109b92010-07-22 18:14:36 +02002782 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002783 binf->arfcn |= *cur++;
2784
2785 if (binf->info_type & IPAC_BINF_RXLEV)
2786 binf->rx_lev = *cur & 0x3f;
2787 cur++;
2788
2789 if (binf->info_type & IPAC_BINF_RXQUAL)
2790 binf->rx_qual = *cur & 0x7;
2791 cur++;
2792
2793 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002794 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002795 cur += 2;
2796
2797 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002798 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002799 cur += 2;
2800
2801 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002802 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002803 cur += 4;
2804
Harald Weltea780a3d2010-07-30 22:34:42 +02002805#if 0
2806 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002807 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002808#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002809 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002810 cur++;
2811
Harald Welteb40a38f2009-11-13 11:56:05 +01002812 ipac_parse_cgi(&binf->cgi, cur);
2813 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002814
2815 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2816 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2817 cur += sizeof(binf->ba_list_si2);
2818 }
2819
2820 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2821 memcpy(binf->ba_list_si2bis, cur,
2822 sizeof(binf->ba_list_si2bis));
2823 cur += sizeof(binf->ba_list_si2bis);
2824 }
2825
2826 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2827 memcpy(binf->ba_list_si2ter, cur,
2828 sizeof(binf->ba_list_si2ter));
2829 cur += sizeof(binf->ba_list_si2ter);
2830 }
2831
2832 return 0;
2833}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002834
2835void abis_nm_clear_queue(struct gsm_bts *bts)
2836{
2837 struct msgb *msg;
2838
2839 while (!llist_empty(&bts->abis_queue)) {
2840 msg = msgb_dequeue(&bts->abis_queue);
2841 msgb_free(msg);
2842 }
2843
2844 bts->abis_nm_pend = 0;
2845}