blob: 8b0eec2ee6426eb266c3585d9a3226487c07173b [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
Harald Welte0db97b22009-05-01 17:22:47 +0000276static int rx_fail_evt_rep(struct msgb *mb)
277{
278 struct abis_om_hdr *oh = msgb_l2(mb);
279 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200280 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000281 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100282 const uint8_t *p_val;
283 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000284
Maxa5e36932017-01-11 11:51:28 +0100285 LOGPC(DNM, LOGL_ERROR, "Failure Event Report: ");
286
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200287 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000288
289 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Maxa5e36932017-01-11 11:51:28 +0100290 LOGPC(DNM, LOGL_ERROR, "Type=%s, ",
Harald Welte15c61722011-05-22 22:45:37 +0200291 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000292 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Maxa5e36932017-01-11 11:51:28 +0100293 LOGPC(DNM, LOGL_ERROR, "Severity=%s, ",
Harald Welte15c61722011-05-22 22:45:37 +0200294 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100295 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
296 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Maxa5e36932017-01-11 11:51:28 +0100297 LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ",
298 get_value_string(abis_nm_pcause_type_names, p_val[0]));
299 if (p_val[0] == NM_PCAUSE_T_MANUF)
300 LOGPC(DNM, LOGL_ERROR, "%s, ",
301 get_value_string(abis_mm_event_cause_names,
302 osmo_load16be(p_val + 1)));
303 else
304 LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100305 }
306 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
307 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
308 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
309 if (p_text) {
Maxa5e36932017-01-11 11:51:28 +0100310 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100311 talloc_free(p_text);
312 }
313 }
Harald Welte0db97b22009-05-01 17:22:47 +0000314
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200315 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000316
317 return 0;
318}
319
Harald Welte97ed1e72009-02-06 13:38:02 +0000320static int abis_nm_rcvmsg_report(struct msgb *mb)
321{
322 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200323 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000324
Harald Welte15c61722011-05-22 22:45:37 +0200325 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000326
Harald Welte97ed1e72009-02-06 13:38:02 +0000327 //nmh->cfg->report_cb(mb, foh);
328
329 switch (mt) {
330 case NM_MT_STATECHG_EVENT_REP:
331 return abis_nm_rx_statechg_rep(mb);
332 break;
Harald Welte34a99682009-02-13 02:41:40 +0000333 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000334 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200335 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000336 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000337 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000338 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200339 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000340 break;
Harald Weltec7310382009-08-08 00:02:36 +0200341 case NM_MT_TEST_REP:
342 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200343 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200344 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000345 default:
Harald Welte23897662009-05-01 14:52:51 +0000346 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000347 break;
348
Harald Welte97ed1e72009-02-06 13:38:02 +0000349 };
350
Harald Welte97ed1e72009-02-06 13:38:02 +0000351 return 0;
352}
353
Harald Welte34a99682009-02-13 02:41:40 +0000354/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200355static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
356 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000357{
358 struct abis_om_hdr *oh;
359 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200360 uint8_t len = swdesc_len;
361 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000362
363 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
364 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
365
366 trailer = msgb_put(msg, swdesc_len);
367 memcpy(trailer, sw_desc, swdesc_len);
368
369 return abis_nm_sendmsg(bts, msg);
370}
371
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100372int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
373 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100374{
375 static const struct tlv_definition sw_descr_def = {
376 .def = {
377 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
378 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
379 },
380 };
381
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100382 size_t pos = 0;
383 int desc_pos = 0;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100384
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100385 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
386 uint8_t tag;
387 uint16_t tag_len;
388 const uint8_t *val;
389 int len;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100390
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100391 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
392 desc[desc_pos].start = &sw_descr[pos];
393
394 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
395 * nested nature and the fact you have to assume it contains only two sub
396 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
397 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
398 LOGP(DNM, LOGL_ERROR,
399 "SW_DESCR attribute identifier not found!\n");
400 return -1;
401 }
402
403 pos += 1;
404 len = tlv_parse_one(&tag, &tag_len, &val,
405 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
406 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
407 LOGP(DNM, LOGL_ERROR,
408 "FILE_ID attribute identifier not found!\n");
409 return -2;
410 }
411 desc[desc_pos].file_id = val;
412 desc[desc_pos].file_id_len = tag_len;
413 pos += len;
414
415
416 len = tlv_parse_one(&tag, &tag_len, &val,
417 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
418 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
419 LOGP(DNM, LOGL_ERROR,
420 "FILE_VERSION attribute identifier not found!\n");
421 return -3;
422 }
423 desc[desc_pos].file_ver = val;
424 desc[desc_pos].file_ver_len = tag_len;
425 pos += len;
426
427 /* final size */
428 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100429 }
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100430
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100431 return desc_pos;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100432}
433
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100434int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
435 const size_t size)
436{
437 int res = 0;
438 int i;
439
440 for (i = 1; i < size; ++i) {
441 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
442 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
443 res = i;
444 }
445 }
446
447 return res;
448}
449
Harald Welte34a99682009-02-13 02:41:40 +0000450static int abis_nm_rx_sw_act_req(struct msgb *mb)
451{
452 struct abis_om_hdr *oh = msgb_l2(mb);
453 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200454 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200455 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200456 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100457 int ret, sw_config_len, len;
458 struct abis_nm_sw_descr sw_descr[5];
Harald Welte34a99682009-02-13 02:41:40 +0000459
Harald Welte15c61722011-05-22 22:45:37 +0200460 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200461
462 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000463
Harald Welte97a282b2010-03-14 15:37:43 +0800464 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000465
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200466 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000467 foh->obj_inst.bts_nr,
468 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800469 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000470 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100471 if (ret != 0) {
472 LOGP(DNM, LOGL_ERROR,
473 "Sending SW ActReq ACK failed: %d\n", ret);
474 return ret;
475 }
Harald Welte34a99682009-02-13 02:41:40 +0000476
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200477 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200478 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
479 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
480 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100481 LOGP(DNM, LOGL_ERROR,
482 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200483 return -EINVAL;
484 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200485 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200486 }
487
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100488 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100489 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100490 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100491 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100492 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100493 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100494 }
Mike Habena03f9772009-10-01 14:56:13 +0200495
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100496 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
497 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
498
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200499 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000500 foh->obj_inst.bts_nr,
501 foh->obj_inst.trx_nr,
502 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100503 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte34a99682009-02-13 02:41:40 +0000504}
505
Harald Weltee0590df2009-02-15 03:34:15 +0000506/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
507static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
508{
509 struct abis_om_hdr *oh = msgb_l2(mb);
510 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200511 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000512 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200513 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000514
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200515 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000516 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
517 return -EINVAL;
518
519 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
520
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200521 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000522}
523
Harald Welteee670472009-02-22 21:58:49 +0000524static int abis_nm_rx_lmt_event(struct msgb *mb)
525{
526 struct abis_om_hdr *oh = msgb_l2(mb);
527 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200528 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000529 struct tlv_parsed tp;
530
531 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200532 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000533 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
534 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200535 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000536 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
537 }
538 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
539 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200540 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000541 DEBUGPC(DNM, "Level=%u ", level);
542 }
543 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
544 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
545 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
546 DEBUGPC(DNM, "Username=%s ", name);
547 }
548 DEBUGPC(DNM, "\n");
549 /* FIXME: parse LMT LOGON TIME */
550 return 0;
551}
552
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200553void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100554{
555 int wait = 0;
556 struct msgb *msg;
557 /* the queue is empty */
558 while (!llist_empty(&bts->abis_queue)) {
559 msg = msgb_dequeue(&bts->abis_queue);
560 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200561 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100562
563 if (wait)
564 break;
565 }
566
567 bts->abis_nm_pend = wait;
568}
569
Harald Welte52b1f982008-12-23 20:25:15 +0000570/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000571static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000572{
Harald Welte6c96ba52009-05-01 13:03:40 +0000573 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000574 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200575 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200576 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100577 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
578 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100579 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000580
581 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000582 if (is_report(mt))
583 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000584
Harald Welte15c61722011-05-22 22:45:37 +0200585 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000586 return abis_nm_rcvmsg_sw(mb);
587
Harald Welte15c61722011-05-22 22:45:37 +0200588 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800589 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000590 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200591
Harald Welte15c61722011-05-22 22:45:37 +0200592 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200593
Harald Welte15c61722011-05-22 22:45:37 +0200594 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000595
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100596 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000597 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200598 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200599 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000600 else
601 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200602
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800603 nack_data.msg = mb;
604 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100605 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200606 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100607 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200608 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000609 }
Harald Weltead384642008-12-26 10:20:07 +0000610#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000611 /* check if last message is to be acked */
612 if (is_ack_nack(nmh->last_msgtype)) {
613 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100614 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000615 /* we got our ACK, continue sending the next msg */
616 } else if (mt == MT_NACK(nmh->last_msgtype)) {
617 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100618 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000619 /* FIXME: somehow signal this to the caller */
620 } else {
621 /* really strange things happen */
622 return -EINVAL;
623 }
624 }
Harald Weltead384642008-12-26 10:20:07 +0000625#endif
626
Harald Welte97ed1e72009-02-06 13:38:02 +0000627 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000628 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100629 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000630 break;
Harald Welte34a99682009-02-13 02:41:40 +0000631 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100632 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000633 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000634 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100635 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000636 break;
Harald Welte1989c082009-08-06 17:58:31 +0200637 case NM_MT_CONN_MDROP_LINK_ACK:
638 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
639 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100640 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200641 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100642 break;
643 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200644 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100645 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100646 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100647 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000648 }
649
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100650 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100651 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000652}
653
Harald Welte677c21f2009-02-17 13:22:23 +0000654static int abis_nm_rx_ipacc(struct msgb *mb);
655
656static int abis_nm_rcvmsg_manuf(struct msgb *mb)
657{
658 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200659 struct e1inp_sign_link *sign_link = mb->dst;
660 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000661
662 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100663 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200664 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000665 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200666 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000667 break;
668 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100669 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
670 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000671 rc = 0;
672 break;
673 }
674
675 return rc;
676}
677
Harald Welte52b1f982008-12-23 20:25:15 +0000678/* High-Level API */
679/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000680int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000681{
Harald Welte52b1f982008-12-23 20:25:15 +0000682 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000683 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000684
685 /* Various consistency checks */
686 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100687 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000688 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200689 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
690 rc = -EINVAL;
691 goto err;
692 }
Harald Welte52b1f982008-12-23 20:25:15 +0000693 }
694 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100695 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000696 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200697 rc = -EINVAL;
698 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000699 }
Harald Welte702d8702008-12-26 20:25:35 +0000700#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200701 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000702 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000703 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100704 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000705 oh->length + sizeof(*oh), l2_len);
706 return -EINVAL;
707 }
Harald Welte702d8702008-12-26 20:25:35 +0000708 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100709 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 +0000710#endif
Harald Weltead384642008-12-26 10:20:07 +0000711 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000712
713 switch (oh->mdisc) {
714 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000715 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000716 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000717 case ABIS_OM_MDISC_MANUF:
718 rc = abis_nm_rcvmsg_manuf(msg);
719 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000720 case ABIS_OM_MDISC_MMI:
721 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100722 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000723 oh->mdisc);
724 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000725 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100726 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000727 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200728 rc = -EINVAL;
729 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000730 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200731err:
Harald Weltead384642008-12-26 10:20:07 +0000732 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000733 return rc;
734}
735
736#if 0
737/* initialized all resources */
738struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
739{
740 struct abis_nm_h *nmh;
741
742 nmh = malloc(sizeof(*nmh));
743 if (!nmh)
744 return NULL;
745
746 nmh->cfg = cfg;
747
748 return nmh;
749}
750
751/* free all resources */
752void abis_nm_fini(struct abis_nm_h *nmh)
753{
754 free(nmh);
755}
756#endif
757
758/* Here we are trying to define a high-level API that can be used by
759 * the actual BSC implementation. However, the architecture is currently
760 * still under design. Ideally the calls to this API would be synchronous,
761 * while the underlying stack behind the APi runs in a traditional select
762 * based state machine.
763 */
764
Harald Welte4724f992009-01-18 18:01:49 +0000765/* 6.2 Software Load: */
766enum sw_state {
767 SW_STATE_NONE,
768 SW_STATE_WAIT_INITACK,
769 SW_STATE_WAIT_SEGACK,
770 SW_STATE_WAIT_ENDACK,
771 SW_STATE_WAIT_ACTACK,
772 SW_STATE_ERROR,
773};
Harald Welte52b1f982008-12-23 20:25:15 +0000774
Harald Welte52b1f982008-12-23 20:25:15 +0000775struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000776 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800777 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000778 gsm_cbfn *cbfn;
779 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000780 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000781
Harald Welte52b1f982008-12-23 20:25:15 +0000782 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200783 uint8_t obj_class;
784 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000785
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200786 uint8_t file_id[255];
787 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000788
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200789 uint8_t file_version[255];
790 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000791
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200792 uint8_t window_size;
793 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000794
795 int fd;
796 FILE *stream;
797 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000798 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000799};
800
Harald Welte4724f992009-01-18 18:01:49 +0000801static struct abis_nm_sw g_sw;
802
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100803static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
804{
805 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
806 msgb_v_put(msg, NM_ATT_SW_DESCR);
807 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
808 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
809 sw->file_version);
810 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
811 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
812 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
813 sw->file_version);
814 } else {
815 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
816 }
817}
818
Harald Welte4724f992009-01-18 18:01:49 +0000819/* 6.2.1 / 8.3.1: Load Data Initiate */
820static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000821{
Harald Welte4724f992009-01-18 18:01:49 +0000822 struct abis_om_hdr *oh;
823 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200824 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000825
826 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
827 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
828 sw->obj_instance[0], sw->obj_instance[1],
829 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100830
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100831 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000832 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
833
834 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000835}
836
Harald Welte1602ade2009-01-29 21:12:39 +0000837static int is_last_line(FILE *stream)
838{
839 char next_seg_buf[256];
840 long pos;
841
842 /* check if we're sending the last line */
843 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200844
845 /* Did ftell fail? Then we are at the end for sure */
846 if (pos < 0)
847 return 1;
848
Harald Welte1602ade2009-01-29 21:12:39 +0000849 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +0100850 int rc = fseek(stream, pos, SEEK_SET);
851 if (rc < 0)
852 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000853 return 1;
854 }
855
856 fseek(stream, pos, SEEK_SET);
857 return 0;
858}
859
Harald Welte4724f992009-01-18 18:01:49 +0000860/* 6.2.2 / 8.3.2 Load Data Segment */
861static int sw_load_segment(struct abis_nm_sw *sw)
862{
863 struct abis_om_hdr *oh;
864 struct msgb *msg = nm_msgb_alloc();
865 char seg_buf[256];
866 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000867 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200868 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000869
870 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000871
872 switch (sw->bts->type) {
873 case GSM_BTS_TYPE_BS11:
874 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
875 perror("fgets reading segment");
876 return -EINVAL;
877 }
878 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000879
880 /* check if we're sending the last line */
881 sw->last_seg = is_last_line(sw->stream);
882 if (sw->last_seg)
883 seg_buf[1] = 0;
884 else
885 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000886
887 len = strlen(line_buf) + 2;
888 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200889 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000890 /* BS11 wants CR + LF in excess of the TLV length !?! */
891 tlv[1] -= 2;
892
893 /* we only now know the exact length for the OM hdr */
894 len = strlen(line_buf)+2;
895 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100896 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200897 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100898 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
899 if (len < 0) {
900 perror("read failed");
901 return -EINVAL;
902 }
903
904 if (len != IPACC_SEGMENT_SIZE)
905 sw->last_seg = 1;
906
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100907 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200908 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100909 len += 3;
910 break;
911 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000912 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100913 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000914 /* FIXME: Other BTS types */
915 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000916 }
Harald Welte4724f992009-01-18 18:01:49 +0000917
Harald Welte4724f992009-01-18 18:01:49 +0000918 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
919 sw->obj_instance[0], sw->obj_instance[1],
920 sw->obj_instance[2]);
921
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100922 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000923}
924
925/* 6.2.4 / 8.3.4 Load Data End */
926static int sw_load_end(struct abis_nm_sw *sw)
927{
928 struct abis_om_hdr *oh;
929 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200930 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000931
932 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
933 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
934 sw->obj_instance[0], sw->obj_instance[1],
935 sw->obj_instance[2]);
936
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100937 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000938 return abis_nm_sendmsg(sw->bts, msg);
939}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000940
Harald Welte52b1f982008-12-23 20:25:15 +0000941/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000942static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000943{
Harald Welte4724f992009-01-18 18:01:49 +0000944 struct abis_om_hdr *oh;
945 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200946 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000947
Harald Welte4724f992009-01-18 18:01:49 +0000948 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
949 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
950 sw->obj_instance[0], sw->obj_instance[1],
951 sw->obj_instance[2]);
952
953 /* FIXME: this is BS11 specific format */
954 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
955 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
956 sw->file_version);
957
958 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000959}
Harald Welte4724f992009-01-18 18:01:49 +0000960
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100961struct sdp_firmware {
962 char magic[4];
963 char more_magic[4];
964 unsigned int header_length;
965 unsigned int file_length;
966} __attribute__ ((packed));
967
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100968static int parse_sdp_header(struct abis_nm_sw *sw)
969{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100970 struct sdp_firmware firmware_header;
971 int rc;
972 struct stat stat;
973
974 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
975 if (rc != sizeof(firmware_header)) {
976 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
977 return -1;
978 }
979
980 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
981 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
982 return -1;
983 }
984
985 if (firmware_header.more_magic[0] != 0x10 ||
986 firmware_header.more_magic[1] != 0x02 ||
987 firmware_header.more_magic[2] != 0x00 ||
988 firmware_header.more_magic[3] != 0x00) {
989 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
990 return -1;
991 }
992
993
994 if (fstat(sw->fd, &stat) == -1) {
995 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
996 return -1;
997 }
998
999 if (ntohl(firmware_header.file_length) != stat.st_size) {
1000 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1001 return -1;
1002 }
1003
1004 /* go back to the start as we checked the whole filesize.. */
1005 lseek(sw->fd, 0l, SEEK_SET);
1006 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1007 "There might be checksums in the file that are not\n"
1008 "verified and incomplete firmware might be flashed.\n"
1009 "There is absolutely no WARRANTY that flashing will\n"
1010 "work.\n");
1011 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001012}
1013
Harald Welte4724f992009-01-18 18:01:49 +00001014static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1015{
1016 char file_id[12+1];
1017 char file_version[80+1];
1018 int rc;
1019
1020 sw->fd = open(fname, O_RDONLY);
1021 if (sw->fd < 0)
1022 return sw->fd;
1023
1024 switch (sw->bts->type) {
1025 case GSM_BTS_TYPE_BS11:
1026 sw->stream = fdopen(sw->fd, "r");
1027 if (!sw->stream) {
1028 perror("fdopen");
1029 return -1;
1030 }
1031 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001032 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001033 file_id, file_version);
1034 if (rc != 2) {
1035 perror("parsing header line of software file");
1036 return -1;
1037 }
1038 strcpy((char *)sw->file_id, file_id);
1039 sw->file_id_len = strlen(file_id);
1040 strcpy((char *)sw->file_version, file_version);
1041 sw->file_version_len = strlen(file_version);
1042 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001043 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001044 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001045 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001046 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001047 rc = parse_sdp_header(sw);
1048 if (rc < 0) {
1049 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1050 return -1;
1051 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001052
1053 strcpy((char *)sw->file_id, "id");
1054 sw->file_id_len = 3;
1055 strcpy((char *)sw->file_version, "version");
1056 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001057 break;
Harald Welte4724f992009-01-18 18:01:49 +00001058 default:
1059 /* We don't know how to treat them yet */
1060 close(sw->fd);
1061 return -EINVAL;
1062 }
1063
1064 return 0;
1065}
1066
1067static void sw_close_file(struct abis_nm_sw *sw)
1068{
1069 switch (sw->bts->type) {
1070 case GSM_BTS_TYPE_BS11:
1071 fclose(sw->stream);
1072 break;
1073 default:
1074 close(sw->fd);
1075 break;
1076 }
1077}
1078
1079/* Fill the window */
1080static int sw_fill_window(struct abis_nm_sw *sw)
1081{
1082 int rc;
1083
1084 while (sw->seg_in_window < sw->window_size) {
1085 rc = sw_load_segment(sw);
1086 if (rc < 0)
1087 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001088 if (sw->last_seg)
1089 break;
Harald Welte4724f992009-01-18 18:01:49 +00001090 }
1091 return 0;
1092}
1093
1094/* callback function from abis_nm_rcvmsg() handler */
1095static int abis_nm_rcvmsg_sw(struct msgb *mb)
1096{
1097 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001098 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001099 int rc = -1;
1100 struct abis_nm_sw *sw = &g_sw;
1101 enum sw_state old_state = sw->state;
1102
Harald Welte3ffd1372009-02-01 22:15:49 +00001103 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001104
1105 switch (sw->state) {
1106 case SW_STATE_WAIT_INITACK:
1107 switch (foh->msg_type) {
1108 case NM_MT_LOAD_INIT_ACK:
1109 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001110 if (sw->cbfn)
1111 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1112 NM_MT_LOAD_INIT_ACK, mb,
1113 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001114 rc = sw_fill_window(sw);
1115 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001116 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001117 break;
1118 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001119 if (sw->forced) {
1120 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1121 "Init NACK\n");
1122 if (sw->cbfn)
1123 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1124 NM_MT_LOAD_INIT_ACK, mb,
1125 sw->cb_data, NULL);
1126 rc = sw_fill_window(sw);
1127 sw->state = SW_STATE_WAIT_SEGACK;
1128 } else {
1129 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001130 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001131 if (sw->cbfn)
1132 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1133 NM_MT_LOAD_INIT_NACK, mb,
1134 sw->cb_data, NULL);
1135 sw->state = SW_STATE_ERROR;
1136 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001137 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001138 break;
1139 }
1140 break;
1141 case SW_STATE_WAIT_SEGACK:
1142 switch (foh->msg_type) {
1143 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001144 if (sw->cbfn)
1145 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1146 NM_MT_LOAD_SEG_ACK, mb,
1147 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001148 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001149 if (!sw->last_seg) {
1150 /* fill window with more segments */
1151 rc = sw_fill_window(sw);
1152 sw->state = SW_STATE_WAIT_SEGACK;
1153 } else {
1154 /* end the transfer */
1155 sw->state = SW_STATE_WAIT_ENDACK;
1156 rc = sw_load_end(sw);
1157 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001158 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001159 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001160 case NM_MT_LOAD_ABORT:
1161 if (sw->cbfn)
1162 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1163 NM_MT_LOAD_ABORT, mb,
1164 sw->cb_data, NULL);
1165 break;
Harald Welte4724f992009-01-18 18:01:49 +00001166 }
1167 break;
1168 case SW_STATE_WAIT_ENDACK:
1169 switch (foh->msg_type) {
1170 case NM_MT_LOAD_END_ACK:
1171 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001172 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1173 sw->bts->nr);
1174 sw->state = SW_STATE_NONE;
1175 if (sw->cbfn)
1176 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1177 NM_MT_LOAD_END_ACK, mb,
1178 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001179 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001180 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001181 break;
1182 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001183 if (sw->forced) {
1184 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1185 "End NACK\n");
1186 sw->state = SW_STATE_NONE;
1187 if (sw->cbfn)
1188 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1189 NM_MT_LOAD_END_ACK, mb,
1190 sw->cb_data, NULL);
1191 } else {
1192 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001193 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001194 sw->state = SW_STATE_ERROR;
1195 if (sw->cbfn)
1196 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1197 NM_MT_LOAD_END_NACK, mb,
1198 sw->cb_data, NULL);
1199 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001200 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001201 break;
1202 }
1203 case SW_STATE_WAIT_ACTACK:
1204 switch (foh->msg_type) {
1205 case NM_MT_ACTIVATE_SW_ACK:
1206 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001207 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001208 sw->state = SW_STATE_NONE;
1209 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001210 if (sw->cbfn)
1211 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1212 NM_MT_ACTIVATE_SW_ACK, mb,
1213 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001214 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001215 break;
1216 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001217 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001218 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001219 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001220 if (sw->cbfn)
1221 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1222 NM_MT_ACTIVATE_SW_NACK, mb,
1223 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001224 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001225 break;
1226 }
1227 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001228 switch (foh->msg_type) {
1229 case NM_MT_ACTIVATE_SW_ACK:
1230 rc = 0;
1231 break;
1232 }
1233 break;
Harald Welte4724f992009-01-18 18:01:49 +00001234 case SW_STATE_ERROR:
1235 break;
1236 }
1237
1238 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001239 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001240 foh->msg_type, old_state, sw->state);
1241
1242 return rc;
1243}
1244
1245/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001246int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001247 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001248 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001249{
1250 struct abis_nm_sw *sw = &g_sw;
1251 int rc;
1252
Harald Welte5e4d1b32009-02-01 13:36:56 +00001253 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1254 bts->nr, fname);
1255
Harald Welte4724f992009-01-18 18:01:49 +00001256 if (sw->state != SW_STATE_NONE)
1257 return -EBUSY;
1258
1259 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001260 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001261
1262 switch (bts->type) {
1263 case GSM_BTS_TYPE_BS11:
1264 sw->obj_class = NM_OC_SITE_MANAGER;
1265 sw->obj_instance[0] = 0xff;
1266 sw->obj_instance[1] = 0xff;
1267 sw->obj_instance[2] = 0xff;
1268 break;
1269 case GSM_BTS_TYPE_NANOBTS:
1270 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001271 sw->obj_instance[0] = sw->bts->nr;
1272 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001273 sw->obj_instance[2] = 0xff;
1274 break;
1275 case GSM_BTS_TYPE_UNKNOWN:
1276 default:
1277 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1278 return -1;
1279 break;
1280 }
Harald Welte4724f992009-01-18 18:01:49 +00001281 sw->window_size = win_size;
1282 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001283 sw->cbfn = cbfn;
1284 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001285 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001286
1287 rc = sw_open_file(sw, fname);
1288 if (rc < 0) {
1289 sw->state = SW_STATE_NONE;
1290 return rc;
1291 }
1292
1293 return sw_load_init(sw);
1294}
Harald Welte52b1f982008-12-23 20:25:15 +00001295
Harald Welte1602ade2009-01-29 21:12:39 +00001296int abis_nm_software_load_status(struct gsm_bts *bts)
1297{
1298 struct abis_nm_sw *sw = &g_sw;
1299 struct stat st;
1300 int rc, percent;
1301
1302 rc = fstat(sw->fd, &st);
1303 if (rc < 0) {
1304 perror("ERROR during stat");
1305 return rc;
1306 }
1307
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001308 if (sw->stream)
1309 percent = (ftell(sw->stream) * 100) / st.st_size;
1310 else
1311 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001312 return percent;
1313}
1314
Harald Welte5e4d1b32009-02-01 13:36:56 +00001315/* Activate the specified software into the BTS */
1316int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1317 gsm_cbfn *cbfn, void *cb_data)
1318{
1319 struct abis_nm_sw *sw = &g_sw;
1320 int rc;
1321
1322 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1323 bts->nr, fname);
1324
1325 if (sw->state != SW_STATE_NONE)
1326 return -EBUSY;
1327
1328 sw->bts = bts;
1329 sw->obj_class = NM_OC_SITE_MANAGER;
1330 sw->obj_instance[0] = 0xff;
1331 sw->obj_instance[1] = 0xff;
1332 sw->obj_instance[2] = 0xff;
1333 sw->state = SW_STATE_WAIT_ACTACK;
1334 sw->cbfn = cbfn;
1335 sw->cb_data = cb_data;
1336
1337 /* Open the file in order to fill some sw struct members */
1338 rc = sw_open_file(sw, fname);
1339 if (rc < 0) {
1340 sw->state = SW_STATE_NONE;
1341 return rc;
1342 }
1343 sw_close_file(sw);
1344
1345 return sw_activate(sw);
1346}
1347
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001348static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1349 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001350{
Harald Welteadaf08b2009-01-18 11:08:10 +00001351 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001352 ch->bts_port = bts_port;
1353 ch->timeslot = ts_nr;
1354 ch->subslot = subslot_nr;
1355}
1356
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001357int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1358 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1359 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001360{
1361 struct abis_om_hdr *oh;
1362 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001363 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001364 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001365
1366 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1367 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1368 bts->bts_nr, trx_nr, 0xff);
1369
Harald Welte8470bf22008-12-25 23:28:35 +00001370 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001371
1372 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1373 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1374
1375 return abis_nm_sendmsg(bts, msg);
1376}
1377
1378/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1379int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001380 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001381{
Harald Welte8470bf22008-12-25 23:28:35 +00001382 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001383 struct abis_om_hdr *oh;
1384 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001385 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001386
1387 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001388 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001389 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1390
1391 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1392 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1393
1394 return abis_nm_sendmsg(bts, msg);
1395}
1396
1397#if 0
1398int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1399 struct abis_nm_abis_channel *chan)
1400{
1401}
1402#endif
1403
1404int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001405 uint8_t e1_port, uint8_t e1_timeslot,
1406 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001407{
1408 struct gsm_bts *bts = ts->trx->bts;
1409 struct abis_om_hdr *oh;
1410 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001411 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001412
1413 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1414 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001415 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001416
1417 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1418 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1419
Harald Weltef325eb42009-02-19 17:07:39 +00001420 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1421 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001422 e1_port, e1_timeslot, e1_subslot);
1423
Harald Welte52b1f982008-12-23 20:25:15 +00001424 return abis_nm_sendmsg(bts, msg);
1425}
1426
1427#if 0
1428int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1429 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001430 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001431{
1432}
1433#endif
1434
Harald Weltefe568f22012-08-14 19:15:57 +02001435/* Chapter 8.11.1 */
1436int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1437 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1438 uint8_t *attr, uint8_t attr_len)
1439{
1440 struct abis_om_hdr *oh;
1441 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001442
1443 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1444
1445 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1446 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1447 bts_nr, trx_nr, ts_nr);
1448 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1449
1450 return abis_nm_sendmsg(bts, msg);
1451}
1452
Harald Welte22af0db2009-02-14 15:41:08 +00001453/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001454int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001455{
1456 struct abis_om_hdr *oh;
1457 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001458 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001459
1460 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1461
1462 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001463 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 +00001464 cur = msgb_put(msg, attr_len);
1465 memcpy(cur, attr, attr_len);
1466
1467 return abis_nm_sendmsg(bts, msg);
1468}
1469
1470/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001471int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001472{
1473 struct abis_om_hdr *oh;
1474 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001475 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001476
1477 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1478
1479 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1480 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001481 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001482 cur = msgb_put(msg, attr_len);
1483 memcpy(cur, attr, attr_len);
1484
1485 return abis_nm_sendmsg(trx->bts, msg);
1486}
1487
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001488int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1489{
1490 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1491 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1492}
1493
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001494static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1495 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001496{
1497 int i;
1498
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001499 *reason = "Reason unknown";
1500
Harald Welte39c7deb2009-08-09 21:49:48 +02001501 /* As it turns out, the BS-11 has some very peculiar restrictions
1502 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301503 switch (ts->trx->bts->type) {
1504 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001505 switch (chan_comb) {
1506 case NM_CHANC_TCHHalf:
1507 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001508 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001509 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001510 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001511 return -EINVAL;
1512 case NM_CHANC_SDCCH:
1513 /* only one SDCCH/8 per TRX */
1514 for (i = 0; i < TRX_NR_TS; i++) {
1515 if (i == ts->nr)
1516 continue;
1517 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001518 NM_CHANC_SDCCH) {
1519 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001520 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001521 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001522 }
1523 /* not allowed for TS0 of BCCH-TRX */
1524 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001525 ts->nr == 0) {
1526 *reason = "SDCCH/8 must be on TS0.";
1527 return -EINVAL;
1528 }
1529
Harald Welte39c7deb2009-08-09 21:49:48 +02001530 /* not on the same TRX that has a BCCH+SDCCH4
1531 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001532 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001533 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001534 ts->trx->ts[0].nm_chan_comb == 8)) {
1535 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1536 return -EINVAL;
1537 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001538 break;
1539 case NM_CHANC_mainBCCH:
1540 case NM_CHANC_BCCHComb:
1541 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001542 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1543 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001544 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001545 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001546 break;
1547 case NM_CHANC_BCCH:
1548 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001549 if (ts->trx != ts->trx->bts->c0) {
1550 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001551 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001552 }
1553 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1554 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001555 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001556 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001557 break;
1558 case 8: /* this is not like 08.58, but in fact
1559 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1560 /* FIXME: only one CBCH allowed per cell */
1561 break;
1562 }
Harald Welted6575f92009-12-02 02:45:23 +05301563 break;
1564 case GSM_BTS_TYPE_NANOBTS:
1565 switch (ts->nr) {
1566 case 0:
1567 if (ts->trx->nr == 0) {
1568 /* only on TRX0 */
1569 switch (chan_comb) {
1570 case NM_CHANC_BCCH:
1571 case NM_CHANC_mainBCCH:
1572 case NM_CHANC_BCCHComb:
1573 return 0;
1574 break;
1575 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001576 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301577 return -EINVAL;
1578 }
1579 } else {
1580 switch (chan_comb) {
1581 case NM_CHANC_TCHFull:
1582 case NM_CHANC_TCHHalf:
1583 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1584 return 0;
1585 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001586 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301587 return -EINVAL;
1588 }
1589 }
1590 break;
1591 case 1:
1592 if (ts->trx->nr == 0) {
1593 switch (chan_comb) {
1594 case NM_CHANC_SDCCH_CBCH:
1595 if (ts->trx->ts[0].nm_chan_comb ==
1596 NM_CHANC_mainBCCH)
1597 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001598 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301599 return -EINVAL;
1600 case NM_CHANC_SDCCH:
1601 case NM_CHANC_TCHFull:
1602 case NM_CHANC_TCHHalf:
1603 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1604 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001605 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301606 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001607 default:
1608 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1609 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301610 }
1611 } else {
1612 switch (chan_comb) {
1613 case NM_CHANC_SDCCH:
1614 case NM_CHANC_TCHFull:
1615 case NM_CHANC_TCHHalf:
1616 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1617 return 0;
1618 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001619 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301620 return -EINVAL;
1621 }
1622 }
1623 break;
1624 case 2:
1625 case 3:
1626 case 4:
1627 case 5:
1628 case 6:
1629 case 7:
1630 switch (chan_comb) {
1631 case NM_CHANC_TCHFull:
1632 case NM_CHANC_TCHHalf:
1633 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1634 return 0;
1635 case NM_CHANC_IPAC_PDCH:
1636 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001637 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301638 if (ts->trx->nr == 0)
1639 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001640 else {
1641 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301642 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001643 }
Harald Welted6575f92009-12-02 02:45:23 +05301644 }
1645 break;
1646 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001647 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301648 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001649 case GSM_BTS_TYPE_OSMO_SYSMO:
1650 /* no known restrictions */
1651 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301652 default:
1653 /* unknown BTS type */
1654 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001655 }
1656 return 0;
1657}
1658
Harald Welte22af0db2009-02-14 15:41:08 +00001659/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001660int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001661{
1662 struct gsm_bts *bts = ts->trx->bts;
1663 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001664 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001665 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001666 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001667 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001668
1669 if (bts->type == GSM_BTS_TYPE_BS11)
1670 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001671
Harald Weltef325eb42009-02-19 17:07:39 +00001672 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001673 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001674 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001675 LOGP(DNM, LOGL_ERROR,
1676 "Invalid Channel Combination %d on %s. Reason: %s\n",
1677 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001678 return -EINVAL;
1679 }
1680 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001681
Harald Welte52b1f982008-12-23 20:25:15 +00001682 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001683 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001684 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001685 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001686 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001687 if (ts->hopping.enabled) {
1688 unsigned int i;
1689 uint8_t *len;
1690
Harald Welte6e0cd042009-09-12 13:05:33 +02001691 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1692 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001693
1694 /* build the ARFCN list */
1695 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1696 len = msgb_put(msg, 1);
1697 *len = 0;
1698 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1699 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1700 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001701 /* At least BS-11 wants a TLV16 here */
1702 if (bts->type == GSM_BTS_TYPE_BS11)
1703 *len += 1;
1704 else
1705 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001706 }
1707 }
Harald Weltee0590df2009-02-15 03:34:15 +00001708 }
Harald Welte1fe24122014-01-19 17:18:21 +01001709 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001710 if (bts->type == GSM_BTS_TYPE_BS11)
1711 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001712
1713 return abis_nm_sendmsg(bts, msg);
1714}
1715
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001716int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1717 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001718{
1719 struct abis_om_hdr *oh;
1720 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001721 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1722 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001723
1724 if (nack) {
1725 len += 2;
1726 msgtype = NM_MT_SW_ACT_REQ_NACK;
1727 }
Harald Welte34a99682009-02-13 02:41:40 +00001728
1729 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001730 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1731
Harald Welte34a99682009-02-13 02:41:40 +00001732 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001733 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001734 memcpy(ptr, attr, att_len);
1735 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001736 if (nack)
1737 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001738
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001739 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001740}
1741
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001742int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001743{
Harald Welte8470bf22008-12-25 23:28:35 +00001744 struct msgb *msg = nm_msgb_alloc();
1745 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001746 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001747
1748 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1749 fill_om_hdr(oh, len);
1750 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001751 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001752
1753 return abis_nm_sendmsg(bts, msg);
1754}
1755
1756/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001757static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001758{
1759 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001760 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001761
1762 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, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001764 0xff, 0xff, 0xff);
1765
1766 return abis_nm_sendmsg(bts, msg);
1767}
1768
Harald Welte34a99682009-02-13 02:41:40 +00001769/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001770int 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 +00001771{
1772 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001773 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001774 struct msgb *msg = nm_msgb_alloc();
1775
1776 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001777 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001778
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001779 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001780 DEBUGPC(DNM, "Sending OPSTART\n");
1781
Harald Welte34a99682009-02-13 02:41:40 +00001782 return abis_nm_sendmsg(bts, msg);
1783}
1784
1785/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001786int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1787 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001788{
1789 struct abis_om_hdr *oh;
1790 struct msgb *msg = nm_msgb_alloc();
1791
1792 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1793 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1794 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1795
1796 return abis_nm_sendmsg(bts, msg);
1797}
1798
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001799int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1800 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001801{
1802 struct abis_om_hdr *oh;
1803 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001804 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001805
1806 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1807 e1_port0, ts0, e1_port1, ts1);
1808
1809 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1810 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1811 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1812
1813 attr = msgb_put(msg, 3);
1814 attr[0] = NM_ATT_MDROP_LINK;
1815 attr[1] = e1_port0;
1816 attr[2] = ts0;
1817
1818 attr = msgb_put(msg, 3);
1819 attr[0] = NM_ATT_MDROP_NEXT;
1820 attr[1] = e1_port1;
1821 attr[2] = ts1;
1822
1823 return abis_nm_sendmsg(bts, msg);
1824}
Harald Welte34a99682009-02-13 02:41:40 +00001825
Harald Weltec7310382009-08-08 00:02:36 +02001826/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001827int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1828 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1829 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001830{
1831 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001832
Harald Welte15c61722011-05-22 22:45:37 +02001833 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001834
1835 if (!msg)
1836 msg = nm_msgb_alloc();
1837
1838 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1839 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1840 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1841 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001842 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001843
1844 return abis_nm_sendmsg(bts, msg);
1845}
1846
Harald Welte52b1f982008-12-23 20:25:15 +00001847int abis_nm_event_reports(struct gsm_bts *bts, int on)
1848{
1849 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001850 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001851 else
Harald Welte227d4072009-01-03 08:16:25 +00001852 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001853}
1854
Harald Welte47d88ae2009-01-04 12:02:08 +00001855/* Siemens (or BS-11) specific commands */
1856
Harald Welte3ffd1372009-02-01 22:15:49 +00001857int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1858{
1859 if (reconnect == 0)
1860 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1861 else
1862 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1863}
1864
Harald Welteb8427972009-02-05 19:27:17 +00001865int abis_nm_bs11_restart(struct gsm_bts *bts)
1866{
1867 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1868}
1869
1870
Harald Welte268bb402009-02-01 19:11:56 +00001871struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001872 uint16_t year;
1873 uint8_t month;
1874 uint8_t day;
1875 uint8_t hour;
1876 uint8_t min;
1877 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001878} __attribute__((packed));
1879
1880
1881void get_bs11_date_time(struct bs11_date_time *aet)
1882{
1883 time_t t;
1884 struct tm *tm;
1885
1886 t = time(NULL);
1887 tm = localtime(&t);
1888 aet->sec = tm->tm_sec;
1889 aet->min = tm->tm_min;
1890 aet->hour = tm->tm_hour;
1891 aet->day = tm->tm_mday;
1892 aet->month = tm->tm_mon;
1893 aet->year = htons(1900 + tm->tm_year);
1894}
1895
Harald Welte05188ee2009-01-18 11:39:08 +00001896int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001897{
Harald Welte4668fda2009-01-03 08:19:29 +00001898 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001899}
1900
Harald Welte05188ee2009-01-18 11:39:08 +00001901int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001902{
1903 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001904 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001905 else
Harald Welte4668fda2009-01-03 08:19:29 +00001906 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001907}
Harald Welte47d88ae2009-01-04 12:02:08 +00001908
Harald Welte05188ee2009-01-18 11:39:08 +00001909int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001910 enum abis_bs11_objtype type, uint8_t idx,
1911 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001912{
1913 struct abis_om_hdr *oh;
1914 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001915 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001916
1917 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001918 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001919 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001920 cur = msgb_put(msg, attr_len);
1921 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001922
1923 return abis_nm_sendmsg(bts, msg);
1924}
1925
Harald Welte78fc0d42009-02-19 02:50:57 +00001926int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001927 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001928{
1929 struct abis_om_hdr *oh;
1930 struct msgb *msg = nm_msgb_alloc();
1931
1932 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1933 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1934 NM_OC_BS11, type, 0, idx);
1935
1936 return abis_nm_sendmsg(bts, msg);
1937}
1938
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001939int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001940{
1941 struct abis_om_hdr *oh;
1942 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001943 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001944
1945 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001946 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001947 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1948 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001949
1950 return abis_nm_sendmsg(bts, msg);
1951}
1952
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001953int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001954{
1955 struct abis_om_hdr *oh;
1956 struct msgb *msg = nm_msgb_alloc();
1957
1958 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1959 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001960 idx, 0xff, 0xff);
1961
1962 return abis_nm_sendmsg(bts, msg);
1963}
1964
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001965int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001966{
1967 struct abis_om_hdr *oh;
1968 struct msgb *msg = nm_msgb_alloc();
1969
1970 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1971 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1972 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001973
1974 return abis_nm_sendmsg(bts, msg);
1975}
Harald Welte05188ee2009-01-18 11:39:08 +00001976
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001977static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001978int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1979{
1980 struct abis_om_hdr *oh;
1981 struct msgb *msg = nm_msgb_alloc();
1982
1983 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1984 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1985 0xff, 0xff, 0xff);
1986 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1987
1988 return abis_nm_sendmsg(bts, msg);
1989}
1990
Harald Welteb6c92ae2009-02-21 20:15:32 +00001991/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001992int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1993 uint8_t e1_timeslot, uint8_t e1_subslot,
1994 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001995{
1996 struct abis_om_hdr *oh;
1997 struct abis_nm_channel *ch;
1998 struct msgb *msg = nm_msgb_alloc();
1999
2000 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002001 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002002 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2003
2004 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2005 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002006 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002007
2008 return abis_nm_sendmsg(bts, msg);
2009}
2010
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002011int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002012{
2013 struct abis_om_hdr *oh;
2014 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002015
2016 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002017 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002018 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2019 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2020
2021 return abis_nm_sendmsg(trx->bts, msg);
2022}
2023
Harald Welte78fc0d42009-02-19 02:50:57 +00002024int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2025{
2026 struct abis_om_hdr *oh;
2027 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002028 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002029
2030 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2031 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2032 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2033 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2034
2035 return abis_nm_sendmsg(trx->bts, msg);
2036}
2037
Harald Welteaaf02d92009-04-29 13:25:57 +00002038int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2039{
2040 struct abis_om_hdr *oh;
2041 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002042 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002043
2044 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2045 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2046 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002047 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002048
2049 return abis_nm_sendmsg(bts, msg);
2050}
2051
Harald Welteef061952009-05-17 12:43:42 +00002052int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2053{
2054 struct abis_om_hdr *oh;
2055 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002056 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002057 NM_ATT_BS11_CCLK_TYPE };
2058
2059 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2060 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2061 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2062 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2063
2064 return abis_nm_sendmsg(bts, msg);
2065
2066}
Harald Welteaaf02d92009-04-29 13:25:57 +00002067
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002068//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002069
Harald Welte1bc09062009-01-18 14:17:52 +00002070int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002071{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002072 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2073}
2074
Daniel Willmann4b054c82010-01-07 00:46:26 +01002075int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2076{
2077 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2078}
2079
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002080int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002081{
Harald Welte05188ee2009-01-18 11:39:08 +00002082 struct abis_om_hdr *oh;
2083 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002084 struct bs11_date_time bdt;
2085
2086 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002087
2088 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002089 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002090 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002091 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002092 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002093 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002094 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002095 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002096 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002097 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002098 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002099 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002100 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002101 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002102 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002103 }
Harald Welte05188ee2009-01-18 11:39:08 +00002104
2105 return abis_nm_sendmsg(bts, msg);
2106}
Harald Welte1bc09062009-01-18 14:17:52 +00002107
2108int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2109{
2110 struct abis_om_hdr *oh;
2111 struct msgb *msg;
2112
2113 if (strlen(password) != 10)
2114 return -EINVAL;
2115
2116 msg = nm_msgb_alloc();
2117 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002118 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002119 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002120 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002121
2122 return abis_nm_sendmsg(bts, msg);
2123}
2124
Harald Weltee69f5fb2009-04-28 16:31:38 +00002125/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2126int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2127{
2128 struct abis_om_hdr *oh;
2129 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002130 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002131
2132 msg = nm_msgb_alloc();
2133 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2134 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2135 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002136
2137 if (locked)
2138 tlv_value = BS11_LI_PLL_LOCKED;
2139 else
2140 tlv_value = BS11_LI_PLL_STANDALONE;
2141
2142 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002143
2144 return abis_nm_sendmsg(bts, msg);
2145}
2146
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002147/* Set the calibration value of the PLL (work value/set value)
2148 * It depends on the login which one is changed */
2149int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2150{
2151 struct abis_om_hdr *oh;
2152 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002153 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002154
2155 msg = nm_msgb_alloc();
2156 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2157 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2158 BS11_OBJ_TRX1, 0x00, 0x00);
2159
2160 tlv_value[0] = value>>8;
2161 tlv_value[1] = value&0xff;
2162
2163 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2164
2165 return abis_nm_sendmsg(bts, msg);
2166}
2167
Harald Welte1bc09062009-01-18 14:17:52 +00002168int abis_nm_bs11_get_state(struct gsm_bts *bts)
2169{
2170 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2171}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002172
2173/* BS11 SWL */
2174
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002175void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002176
Harald Welte5e4d1b32009-02-01 13:36:56 +00002177struct abis_nm_bs11_sw {
2178 struct gsm_bts *bts;
2179 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002180 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002181 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002182 struct llist_head file_list;
2183 gsm_cbfn *user_cb; /* specified by the user */
2184};
2185static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2186
2187struct file_list_entry {
2188 struct llist_head list;
2189 char fname[PATH_MAX];
2190};
2191
2192struct file_list_entry *fl_dequeue(struct llist_head *queue)
2193{
2194 struct llist_head *lh;
2195
2196 if (llist_empty(queue))
2197 return NULL;
2198
2199 lh = queue->next;
2200 llist_del(lh);
2201
2202 return llist_entry(lh, struct file_list_entry, list);
2203}
2204
2205static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2206{
2207 char linebuf[255];
2208 struct llist_head *lh, *lh2;
2209 FILE *swl;
2210 int rc = 0;
2211
2212 swl = fopen(bs11_sw->swl_fname, "r");
2213 if (!swl)
2214 return -ENODEV;
2215
2216 /* zero the stale file list, if any */
2217 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2218 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002219 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002220 }
2221
2222 while (fgets(linebuf, sizeof(linebuf), swl)) {
2223 char file_id[12+1];
2224 char file_version[80+1];
2225 struct file_list_entry *fle;
2226 static char dir[PATH_MAX];
2227
2228 if (strlen(linebuf) < 4)
2229 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002230
Harald Welte5e4d1b32009-02-01 13:36:56 +00002231 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2232 if (rc < 0) {
2233 perror("ERR parsing SWL file");
2234 rc = -EINVAL;
2235 goto out;
2236 }
2237 if (rc < 2)
2238 continue;
2239
Harald Welte470ec292009-06-26 20:25:23 +02002240 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002241 if (!fle) {
2242 rc = -ENOMEM;
2243 goto out;
2244 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002245
2246 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002247 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002248 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2249 strcat(fle->fname, "/");
2250 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002251
2252 llist_add_tail(&fle->list, &bs11_sw->file_list);
2253 }
2254
2255out:
2256 fclose(swl);
2257 return rc;
2258}
2259
2260/* bs11 swload specific callback, passed to abis_nm core swload */
2261static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2262 struct msgb *msg, void *data, void *param)
2263{
2264 struct abis_nm_bs11_sw *bs11_sw = data;
2265 struct file_list_entry *fle;
2266 int rc = 0;
2267
Harald Welte5e4d1b32009-02-01 13:36:56 +00002268 switch (event) {
2269 case NM_MT_LOAD_END_ACK:
2270 fle = fl_dequeue(&bs11_sw->file_list);
2271 if (fle) {
2272 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002273 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002274 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002275 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002276 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002277 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002278 } else {
2279 /* activate the SWL */
2280 rc = abis_nm_software_activate(bs11_sw->bts,
2281 bs11_sw->swl_fname,
2282 bs11_swload_cbfn,
2283 bs11_sw);
2284 }
2285 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002286 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002287 case NM_MT_LOAD_END_NACK:
2288 case NM_MT_LOAD_INIT_ACK:
2289 case NM_MT_LOAD_INIT_NACK:
2290 case NM_MT_ACTIVATE_SW_NACK:
2291 case NM_MT_ACTIVATE_SW_ACK:
2292 default:
2293 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002294 if (bs11_sw->user_cb)
2295 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002296 break;
2297 }
2298
2299 return rc;
2300}
2301
2302/* Siemens provides a SWL file that is a mere listing of all the other
2303 * files that are part of a software release. We need to upload first
2304 * the list file, and then each file that is listed in the list file */
2305int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002306 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002307{
2308 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2309 struct file_list_entry *fle;
2310 int rc = 0;
2311
2312 INIT_LLIST_HEAD(&bs11_sw->file_list);
2313 bs11_sw->bts = bts;
2314 bs11_sw->win_size = win_size;
2315 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002316 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002317
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002318 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002319 rc = bs11_read_swl_file(bs11_sw);
2320 if (rc < 0)
2321 return rc;
2322
2323 /* dequeue next item in file list */
2324 fle = fl_dequeue(&bs11_sw->file_list);
2325 if (!fle)
2326 return -EINVAL;
2327
2328 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002329 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002330 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002331 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002332 return rc;
2333}
2334
Harald Welte5083b0b2009-02-02 19:20:52 +00002335#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002336static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002337 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2338 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2339 NM_ATT_BS11_LMT_USER_NAME,
2340
2341 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2342
2343 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2344
2345 NM_ATT_BS11_SW_LOAD_STORED };
2346
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002347static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002348 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2349 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2350 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2351 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002352#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002353
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002354static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002355 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2356 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002357 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002358
2359int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2360{
2361 struct abis_om_hdr *oh;
2362 struct msgb *msg = nm_msgb_alloc();
2363
2364 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2365 /* SiemensHW CCTRL object */
2366 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2367 0x03, 0x00, 0x00);
2368 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2369
2370 return abis_nm_sendmsg(bts, msg);
2371}
Harald Welte268bb402009-02-01 19:11:56 +00002372
2373int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2374{
2375 struct abis_om_hdr *oh;
2376 struct msgb *msg = nm_msgb_alloc();
2377 struct bs11_date_time aet;
2378
2379 get_bs11_date_time(&aet);
2380 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2381 /* SiemensHW CCTRL object */
2382 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2383 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002384 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002385
2386 return abis_nm_sendmsg(bts, msg);
2387}
Harald Welte5c1e4582009-02-15 11:57:29 +00002388
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002389int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002390{
2391 struct abis_om_hdr *oh;
2392 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002393 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002394
2395 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2396 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2397 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2398 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2399
2400 return abis_nm_sendmsg(bts, msg);
2401}
2402
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002403int 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 +02002404{
2405 struct abis_om_hdr *oh;
2406 struct msgb *msg = nm_msgb_alloc();
2407 struct bs11_date_time aet;
2408
2409 get_bs11_date_time(&aet);
2410 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2411 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2412 bport, 0xff, 0x02);
2413 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2414
2415 return abis_nm_sendmsg(bts, msg);
2416}
2417
Harald Welte5c1e4582009-02-15 11:57:29 +00002418/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002419static const char ipaccess_magic[] = "com.ipaccess";
2420
Harald Welte677c21f2009-02-17 13:22:23 +00002421
2422static int abis_nm_rx_ipacc(struct msgb *msg)
2423{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002424 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002425 struct abis_om_hdr *oh = msgb_l2(msg);
2426 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002427 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002428 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002429 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002430 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002431
2432 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002433 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002434 return -EINVAL;
2435 }
2436
Harald Welte193fefc2009-04-30 15:16:27 +00002437 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002438 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002439
Harald Welte15c61722011-05-22 22:45:37 +02002440 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002441
Harald Welte746d6092009-10-19 22:11:11 +02002442 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002443
Harald Welte677c21f2009-02-17 13:22:23 +00002444 switch (foh->msg_type) {
2445 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002446 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002447 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2448 memcpy(&addr,
2449 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2450
2451 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2452 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002453 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002454 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002455 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002456 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002457 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2458 DEBUGPC(DNM, "STREAM=0x%02x ",
2459 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002460 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002461 break;
2462 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002463 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002464 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002465 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002466 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002467 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002468 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002469 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002470 case NM_MT_IPACC_SET_NVATTR_ACK:
2471 DEBUGPC(DNM, "SET NVATTR ACK\n");
2472 /* FIXME: decode and show the actual attributes */
2473 break;
2474 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002475 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002476 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002477 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002478 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002479 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002480 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002481 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002482 case NM_MT_IPACC_GET_NVATTR_ACK:
2483 DEBUGPC(DNM, "GET NVATTR ACK\n");
2484 /* FIXME: decode and show the actual attributes */
2485 break;
2486 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002487 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002488 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002489 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002490 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002491 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002492 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002493 break;
Harald Welte15c44172009-10-08 20:15:24 +02002494 case NM_MT_IPACC_SET_ATTR_ACK:
2495 DEBUGPC(DNM, "SET ATTR ACK\n");
2496 break;
2497 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002498 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002499 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002500 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002501 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002502 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002503 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002504 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002505 default:
2506 DEBUGPC(DNM, "unknown\n");
2507 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002508 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002509
2510 /* signal handling */
2511 switch (foh->msg_type) {
2512 case NM_MT_IPACC_RSL_CONNECT_NACK:
2513 case NM_MT_IPACC_SET_NVATTR_NACK:
2514 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002515 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 +01002516 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002517 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002518 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002519 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002520 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 +01002521 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002522 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002523 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002524 default:
2525 break;
2526 }
2527
Harald Welte677c21f2009-02-17 13:22:23 +00002528 return 0;
2529}
2530
Harald Welte193fefc2009-04-30 15:16:27 +00002531/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002532int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2533 uint8_t obj_class, uint8_t bts_nr,
2534 uint8_t trx_nr, uint8_t ts_nr,
2535 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002536{
2537 struct msgb *msg = nm_msgb_alloc();
2538 struct abis_om_hdr *oh;
2539 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002540 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002541
2542 /* construct the 12.21 OM header, observe the erroneous length */
2543 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2544 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2545 oh->mdisc = ABIS_OM_MDISC_MANUF;
2546
2547 /* add the ip.access magic */
2548 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2549 *data++ = sizeof(ipaccess_magic);
2550 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2551
2552 /* fill the 12.21 FOM header */
2553 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2554 foh->msg_type = msg_type;
2555 foh->obj_class = obj_class;
2556 foh->obj_inst.bts_nr = bts_nr;
2557 foh->obj_inst.trx_nr = trx_nr;
2558 foh->obj_inst.ts_nr = ts_nr;
2559
2560 if (attr && attr_len) {
2561 data = msgb_put(msg, attr_len);
2562 memcpy(data, attr, attr_len);
2563 }
2564
2565 return abis_nm_sendmsg(bts, msg);
2566}
Harald Welte677c21f2009-02-17 13:22:23 +00002567
Harald Welte193fefc2009-04-30 15:16:27 +00002568/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002569int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002570 int attr_len)
2571{
Harald Welte2ef156d2010-01-07 20:39:42 +01002572 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2573 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002574 attr_len);
2575}
2576
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002577int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002578 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002579{
2580 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002581 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002582 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2583 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2584
2585 int attr_len = sizeof(attr);
2586
2587 ia.s_addr = htonl(ip);
2588 attr[1] = stream;
2589 attr[3] = port >> 8;
2590 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002591 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002592
2593 /* if ip == 0, we use the default IP */
2594 if (ip == 0)
2595 attr_len -= 5;
2596
2597 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002598 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002599
2600 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2601 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2602 trx->nr, 0xff, attr, attr_len);
2603}
2604
Harald Welte193fefc2009-04-30 15:16:27 +00002605/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002606int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002607{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002608 struct abis_om_hdr *oh;
2609 struct msgb *msg = nm_msgb_alloc();
2610
2611 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2612 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2613 trx->bts->nr, trx->nr, 0xff);
2614
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002615 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002616}
Harald Weltedaef5212009-10-24 10:20:41 +02002617
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002618int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2619 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2620 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002621{
2622 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2623 obj_class, bts_nr, trx_nr, ts_nr,
2624 attr, attr_len);
2625}
Harald Welte0f255852009-11-12 14:48:42 +01002626
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002627void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002628{
2629 /* we simply reuse the GSM48 function and overwrite the RAC
2630 * with the Cell ID */
2631 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002632 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002633}
2634
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002635void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2636{
2637 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2638
Harald Welted64c0bc2011-05-30 12:07:53 +02002639 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002640 if (!trx->bts || !trx->bts->oml_link)
2641 return;
2642
2643 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2644 trx->bts->bts_nr, trx->nr, 0xff,
2645 new_state);
2646}
2647
Harald Welte92b1fe42010-03-25 11:45:30 +08002648static const struct value_string ipacc_testres_names[] = {
2649 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2650 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2651 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2652 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2653 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2654 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002655};
2656
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002657const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002658{
Harald Welte92b1fe42010-03-25 11:45:30 +08002659 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002660}
2661
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002662void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002663{
2664 cid->mcc = (buf[0] & 0xf) * 100;
2665 cid->mcc += (buf[0] >> 4) * 10;
2666 cid->mcc += (buf[1] & 0xf) * 1;
2667
2668 if (buf[1] >> 4 == 0xf) {
2669 cid->mnc = (buf[2] & 0xf) * 10;
2670 cid->mnc += (buf[2] >> 4) * 1;
2671 } else {
2672 cid->mnc = (buf[2] & 0xf) * 100;
2673 cid->mnc += (buf[2] >> 4) * 10;
2674 cid->mnc += (buf[1] >> 4) * 1;
2675 }
2676
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002677 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2678 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002679}
2680
Harald Welte0f255852009-11-12 14:48:42 +01002681/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002682int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002683{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002684 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002685 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002686
Harald Welteaf109b92010-07-22 18:14:36 +02002687 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002688
2689 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2690 return -EINVAL;
2691 cur++;
2692
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002693 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002694 cur += 2;
2695
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002696 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002697 cur += 2;
2698
2699 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2700 binf->freq_qual = *cur >> 2;
2701
Harald Welteaf109b92010-07-22 18:14:36 +02002702 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002703 binf->arfcn |= *cur++;
2704
2705 if (binf->info_type & IPAC_BINF_RXLEV)
2706 binf->rx_lev = *cur & 0x3f;
2707 cur++;
2708
2709 if (binf->info_type & IPAC_BINF_RXQUAL)
2710 binf->rx_qual = *cur & 0x7;
2711 cur++;
2712
2713 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002714 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002715 cur += 2;
2716
2717 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002718 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002719 cur += 2;
2720
2721 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002722 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002723 cur += 4;
2724
Harald Weltea780a3d2010-07-30 22:34:42 +02002725#if 0
2726 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002727 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002728#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002729 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002730 cur++;
2731
Harald Welteb40a38f2009-11-13 11:56:05 +01002732 ipac_parse_cgi(&binf->cgi, cur);
2733 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002734
2735 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2736 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2737 cur += sizeof(binf->ba_list_si2);
2738 }
2739
2740 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2741 memcpy(binf->ba_list_si2bis, cur,
2742 sizeof(binf->ba_list_si2bis));
2743 cur += sizeof(binf->ba_list_si2bis);
2744 }
2745
2746 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2747 memcpy(binf->ba_list_si2ter, cur,
2748 sizeof(binf->ba_list_si2ter));
2749 cur += sizeof(binf->ba_list_si2ter);
2750 }
2751
2752 return 0;
2753}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002754
2755void abis_nm_clear_queue(struct gsm_bts *bts)
2756{
2757 struct msgb *msg;
2758
2759 while (!llist_empty(&bts->abis_queue)) {
2760 msg = msgb_dequeue(&bts->abis_queue);
2761 msgb_free(msg);
2762 }
2763
2764 bts->abis_nm_pend = 0;
2765}