blob: 2698225167936165d50314b3e187366c9cb45d94 [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>
40#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Neels Hofmeyr93bafb62017-01-13 03:12:08 +010043#include <osmocom/core/utils.h>
Harald Welte8470bf22008-12-25 23:28:35 +000044#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000045#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000046#include <openbsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020047#include <osmocom/abis/e1_input.h>
Harald Welte52b1f982008-12-23 20:25:15 +000048
Harald Welte8470bf22008-12-25 23:28:35 +000049#define OM_ALLOC_SIZE 1024
50#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010051#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000052
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020053int 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 +000054{
Harald Welte39315c42010-01-10 18:01:52 +010055 if (!bts->model)
56 return -EIO;
57 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000058}
Harald Weltee0590df2009-02-15 03:34:15 +000059
Harald Welte52b1f982008-12-23 20:25:15 +000060static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
61{
62 int i;
63
64 for (i = 0; i < size; i++) {
65 if (arr[i] == mt)
66 return 1;
67 }
68
69 return 0;
70}
71
Holger Freytherca362a62009-01-04 21:05:01 +000072#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000073/* is this msgtype the usual ACK/NACK type ? */
74static int is_ack_nack(enum abis_nm_msgtype mt)
75{
76 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
77}
Holger Freytherca362a62009-01-04 21:05:01 +000078#endif
Harald Welte52b1f982008-12-23 20:25:15 +000079
80/* is this msgtype a report ? */
81static int is_report(enum abis_nm_msgtype mt)
82{
Harald Welte15c61722011-05-22 22:45:37 +020083 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000084}
85
86#define MT_ACK(x) (x+1)
87#define MT_NACK(x) (x+2)
88
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020089static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000090{
91 oh->mdisc = ABIS_OM_MDISC_FOM;
92 oh->placement = ABIS_OM_PLACEMENT_ONLY;
93 oh->sequence = 0;
94 oh->length = len;
95}
96
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +020097static 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 +020098 uint8_t msg_type, uint8_t obj_class,
99 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000100{
101 struct abis_om_fom_hdr *foh =
102 (struct abis_om_fom_hdr *) oh->data;
103
Harald Welte702d8702008-12-26 20:25:35 +0000104 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000105 foh->msg_type = msg_type;
106 foh->obj_class = obj_class;
107 foh->obj_inst.bts_nr = bts_nr;
108 foh->obj_inst.trx_nr = trx_nr;
109 foh->obj_inst.ts_nr = ts_nr;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200110 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000111}
112
Harald Welte8470bf22008-12-25 23:28:35 +0000113static struct msgb *nm_msgb_alloc(void)
114{
Harald Welte966636f2009-06-26 19:39:35 +0200115 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
116 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000117}
118
Harald Welte15eae8d2011-09-26 23:43:23 +0200119int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200120{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200121 msg->l2h = msg->data;
122
123 if (!msg->dst) {
124 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
125 return -EINVAL;
126 }
127
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200128 return abis_sendmsg(msg);
129}
130
Harald Welte52b1f982008-12-23 20:25:15 +0000131/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100132static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000133{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200134 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000135
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100136 /* queue OML messages */
137 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
138 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200139 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100140 } else {
141 msgb_enqueue(&bts->abis_queue, msg);
142 return 0;
143 }
144
145}
146
147int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
148{
149 OBSC_NM_W_ACK_CB(msg) = 1;
150 return abis_nm_queue_msg(bts, msg);
151}
152
153static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
154{
155 OBSC_NM_W_ACK_CB(msg) = 0;
156 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000157}
158
Harald Welte4724f992009-01-18 18:01:49 +0000159static int abis_nm_rcvmsg_sw(struct msgb *mb);
160
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100161int nm_is_running(struct gsm_nm_state *s) {
162 return (s->operational == NM_OPSTATE_ENABLED) && (
163 (s->availability == NM_AVSTATE_OK) ||
164 (s->availability == 0xff)
165 );
166}
167
Harald Weltee0590df2009-02-15 03:34:15 +0000168/* Update the administrative state of a given object in our in-memory data
169 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200170static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
171 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000172{
Harald Welteaeedeb42009-05-01 13:08:14 +0000173 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100174 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000175
Harald Welteaf9b8102011-03-06 21:20:38 +0100176 memset(&nsd, 0, sizeof(nsd));
177
Harald Welte978714d2011-06-06 18:31:20 +0200178 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100179 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100180 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200181 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000182 if (!nm_state)
183 return -1;
184
185 new_state = *nm_state;
186 new_state.administrative = adm_state;
187
Harald Weltef38ca9a2011-03-06 22:11:32 +0100188 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100189 nsd.obj_class = obj_class;
190 nsd.old_state = nm_state;
191 nsd.new_state = &new_state;
192 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200193 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000194
195 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000196
Harald Weltef338a032011-01-14 15:55:42 +0100197 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000198}
199
Harald Welte97ed1e72009-02-06 13:38:02 +0000200static int abis_nm_rx_statechg_rep(struct msgb *mb)
201{
Harald Weltee0590df2009-02-15 03:34:15 +0000202 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000203 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200204 struct e1inp_sign_link *sign_link = mb->dst;
205 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000206 struct tlv_parsed tp;
207 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000208
Harald Welte23897662009-05-01 14:52:51 +0000209 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000210
Harald Welte8b697c72009-06-05 19:18:45 +0000211 memset(&new_state, 0, sizeof(new_state));
212
Harald Welte978714d2011-06-06 18:31:20 +0200213 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000214 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100215 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000216 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000217 }
Harald Weltee0590df2009-02-15 03:34:15 +0000218
219 new_state = *nm_state;
220
Harald Welte39315c42010-01-10 18:01:52 +0100221 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000222 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
223 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200224 DEBUGPC(DNM, "OP_STATE=%s ",
225 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000226 }
227 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000228 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
229 new_state.availability = 0xff;
230 else
231 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200232 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
233 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000234 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100235 } else
236 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000237 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
238 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200239 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200240 get_value_string(abis_nm_adm_state_names,
241 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000242 }
243 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000244
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100245 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
246 new_state.operational != nm_state->operational ||
247 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000248 /* Update the operational state of a given object in our in-memory data
249 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100250 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200251 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100252 nsd.obj_class = foh->obj_class;
253 nsd.old_state = nm_state;
254 nsd.new_state = &new_state;
255 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100256 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200257 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100258 nm_state->operational = new_state.operational;
259 nm_state->availability = new_state.availability;
260 if (nm_state->administrative == 0)
261 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000262 }
263#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000264 if (op_state == 1) {
265 /* try to enable objects that are disabled */
266 abis_nm_opstart(bts, foh->obj_class,
267 foh->obj_inst.bts_nr,
268 foh->obj_inst.trx_nr,
269 foh->obj_inst.ts_nr);
270 }
Harald Weltee0590df2009-02-15 03:34:15 +0000271#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000272 return 0;
273}
274
Harald Welte0db97b22009-05-01 17:22:47 +0000275static int rx_fail_evt_rep(struct msgb *mb)
276{
277 struct abis_om_hdr *oh = msgb_l2(mb);
278 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200279 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000280 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100281 const uint8_t *p_val;
282 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000283
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200284 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000285
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200286 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000287
288 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200289 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
290 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000291 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200292 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
293 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100294 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
295 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200296 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100297 }
298 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
299 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
300 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
301 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200302 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100303 talloc_free(p_text);
304 }
305 }
Harald Welte0db97b22009-05-01 17:22:47 +0000306
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200307 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000308
309 return 0;
310}
311
Harald Welte97ed1e72009-02-06 13:38:02 +0000312static int abis_nm_rcvmsg_report(struct msgb *mb)
313{
314 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200315 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000316
Harald Welte15c61722011-05-22 22:45:37 +0200317 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000318
Harald Welte97ed1e72009-02-06 13:38:02 +0000319 //nmh->cfg->report_cb(mb, foh);
320
321 switch (mt) {
322 case NM_MT_STATECHG_EVENT_REP:
323 return abis_nm_rx_statechg_rep(mb);
324 break;
Harald Welte34a99682009-02-13 02:41:40 +0000325 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000326 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200327 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000328 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000329 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000330 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200331 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000332 break;
Harald Weltec7310382009-08-08 00:02:36 +0200333 case NM_MT_TEST_REP:
334 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200335 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200336 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000337 default:
Harald Welte23897662009-05-01 14:52:51 +0000338 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000339 break;
340
Harald Welte97ed1e72009-02-06 13:38:02 +0000341 };
342
Harald Welte97ed1e72009-02-06 13:38:02 +0000343 return 0;
344}
345
Harald Welte34a99682009-02-13 02:41:40 +0000346/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200347static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
348 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000349{
350 struct abis_om_hdr *oh;
351 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200352 uint8_t len = swdesc_len;
353 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000354
355 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
356 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
357
358 trailer = msgb_put(msg, swdesc_len);
359 memcpy(trailer, sw_desc, swdesc_len);
360
361 return abis_nm_sendmsg(bts, msg);
362}
363
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100364int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
365 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100366{
367 static const struct tlv_definition sw_descr_def = {
368 .def = {
369 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
370 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
371 },
372 };
373
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100374 size_t pos = 0;
375 int desc_pos = 0;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100376
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100377 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
378 uint8_t tag;
379 uint16_t tag_len;
380 const uint8_t *val;
381 int len;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100382
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100383 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
384 desc[desc_pos].start = &sw_descr[pos];
385
386 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
387 * nested nature and the fact you have to assume it contains only two sub
388 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
389 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
390 LOGP(DNM, LOGL_ERROR,
391 "SW_DESCR attribute identifier not found!\n");
392 return -1;
393 }
394
395 pos += 1;
396 len = tlv_parse_one(&tag, &tag_len, &val,
397 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
398 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
399 LOGP(DNM, LOGL_ERROR,
400 "FILE_ID attribute identifier not found!\n");
401 return -2;
402 }
403 desc[desc_pos].file_id = val;
404 desc[desc_pos].file_id_len = tag_len;
405 pos += len;
406
407
408 len = tlv_parse_one(&tag, &tag_len, &val,
409 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
410 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
411 LOGP(DNM, LOGL_ERROR,
412 "FILE_VERSION attribute identifier not found!\n");
413 return -3;
414 }
415 desc[desc_pos].file_ver = val;
416 desc[desc_pos].file_ver_len = tag_len;
417 pos += len;
418
419 /* final size */
420 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100421 }
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100422
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100423 return desc_pos;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100424}
425
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100426int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
427 const size_t size)
428{
429 int res = 0;
430 int i;
431
432 for (i = 1; i < size; ++i) {
433 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
434 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
435 res = i;
436 }
437 }
438
439 return res;
440}
441
Harald Welte34a99682009-02-13 02:41:40 +0000442static int abis_nm_rx_sw_act_req(struct msgb *mb)
443{
444 struct abis_om_hdr *oh = msgb_l2(mb);
445 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200446 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200447 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200448 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100449 int ret, sw_config_len, len;
450 struct abis_nm_sw_descr sw_descr[5];
Harald Welte34a99682009-02-13 02:41:40 +0000451
Harald Welte15c61722011-05-22 22:45:37 +0200452 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200453
454 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000455
Harald Welte97a282b2010-03-14 15:37:43 +0800456 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000457
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200458 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000459 foh->obj_inst.bts_nr,
460 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800461 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000462 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100463 if (ret != 0) {
464 LOGP(DNM, LOGL_ERROR,
465 "Sending SW ActReq ACK failed: %d\n", ret);
466 return ret;
467 }
Harald Welte34a99682009-02-13 02:41:40 +0000468
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200469 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200470 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
471 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
472 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100473 LOGP(DNM, LOGL_ERROR,
474 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200475 return -EINVAL;
476 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200477 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200478 }
479
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100480 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100481 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100482 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100483 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100484 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100485 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100486 }
Mike Habena03f9772009-10-01 14:56:13 +0200487
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100488 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
489 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
490
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200491 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000492 foh->obj_inst.bts_nr,
493 foh->obj_inst.trx_nr,
494 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100495 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte34a99682009-02-13 02:41:40 +0000496}
497
Harald Weltee0590df2009-02-15 03:34:15 +0000498/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
499static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
500{
501 struct abis_om_hdr *oh = msgb_l2(mb);
502 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200503 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000504 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200505 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000506
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200507 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000508 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
509 return -EINVAL;
510
511 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
512
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200513 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000514}
515
Harald Welteee670472009-02-22 21:58:49 +0000516static int abis_nm_rx_lmt_event(struct msgb *mb)
517{
518 struct abis_om_hdr *oh = msgb_l2(mb);
519 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200520 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000521 struct tlv_parsed tp;
522
523 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200524 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000525 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
526 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200527 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000528 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
529 }
530 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
531 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200532 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000533 DEBUGPC(DNM, "Level=%u ", level);
534 }
535 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
536 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
537 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
538 DEBUGPC(DNM, "Username=%s ", name);
539 }
540 DEBUGPC(DNM, "\n");
541 /* FIXME: parse LMT LOGON TIME */
542 return 0;
543}
544
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200545void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100546{
547 int wait = 0;
548 struct msgb *msg;
549 /* the queue is empty */
550 while (!llist_empty(&bts->abis_queue)) {
551 msg = msgb_dequeue(&bts->abis_queue);
552 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200553 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100554
555 if (wait)
556 break;
557 }
558
559 bts->abis_nm_pend = wait;
560}
561
Harald Welte52b1f982008-12-23 20:25:15 +0000562/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000563static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000564{
Harald Welte6c96ba52009-05-01 13:03:40 +0000565 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000566 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200567 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200568 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100569 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
570 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100571 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000572
573 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000574 if (is_report(mt))
575 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000576
Harald Welte15c61722011-05-22 22:45:37 +0200577 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000578 return abis_nm_rcvmsg_sw(mb);
579
Harald Welte15c61722011-05-22 22:45:37 +0200580 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800581 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000582 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200583
Harald Welte15c61722011-05-22 22:45:37 +0200584 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200585
Harald Welte15c61722011-05-22 22:45:37 +0200586 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000587
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100588 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000589 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200590 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200591 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000592 else
593 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200594
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800595 nack_data.msg = mb;
596 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100597 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200598 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100599 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200600 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000601 }
Harald Weltead384642008-12-26 10:20:07 +0000602#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000603 /* check if last message is to be acked */
604 if (is_ack_nack(nmh->last_msgtype)) {
605 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100606 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000607 /* we got our ACK, continue sending the next msg */
608 } else if (mt == MT_NACK(nmh->last_msgtype)) {
609 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100610 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000611 /* FIXME: somehow signal this to the caller */
612 } else {
613 /* really strange things happen */
614 return -EINVAL;
615 }
616 }
Harald Weltead384642008-12-26 10:20:07 +0000617#endif
618
Harald Welte97ed1e72009-02-06 13:38:02 +0000619 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000620 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100621 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000622 break;
Harald Welte34a99682009-02-13 02:41:40 +0000623 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100624 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000625 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000626 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100627 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000628 break;
Harald Welte1989c082009-08-06 17:58:31 +0200629 case NM_MT_CONN_MDROP_LINK_ACK:
630 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
631 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100632 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200633 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100634 break;
635 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200636 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100637 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100638 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100639 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000640 }
641
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100642 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100643 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000644}
645
Harald Welte677c21f2009-02-17 13:22:23 +0000646static int abis_nm_rx_ipacc(struct msgb *mb);
647
648static int abis_nm_rcvmsg_manuf(struct msgb *mb)
649{
650 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200651 struct e1inp_sign_link *sign_link = mb->dst;
652 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000653
654 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100655 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200656 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000657 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200658 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000659 break;
660 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100661 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
662 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000663 rc = 0;
664 break;
665 }
666
667 return rc;
668}
669
Harald Welte52b1f982008-12-23 20:25:15 +0000670/* High-Level API */
671/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000672int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000673{
Harald Welte52b1f982008-12-23 20:25:15 +0000674 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000675 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000676
677 /* Various consistency checks */
678 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100679 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000680 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200681 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
682 rc = -EINVAL;
683 goto err;
684 }
Harald Welte52b1f982008-12-23 20:25:15 +0000685 }
686 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100687 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000688 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200689 rc = -EINVAL;
690 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000691 }
Harald Welte702d8702008-12-26 20:25:35 +0000692#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200693 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000694 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000695 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100696 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000697 oh->length + sizeof(*oh), l2_len);
698 return -EINVAL;
699 }
Harald Welte702d8702008-12-26 20:25:35 +0000700 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100701 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 +0000702#endif
Harald Weltead384642008-12-26 10:20:07 +0000703 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000704
705 switch (oh->mdisc) {
706 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000707 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000708 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000709 case ABIS_OM_MDISC_MANUF:
710 rc = abis_nm_rcvmsg_manuf(msg);
711 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000712 case ABIS_OM_MDISC_MMI:
713 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100714 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000715 oh->mdisc);
716 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000717 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100718 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000719 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200720 rc = -EINVAL;
721 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000722 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200723err:
Harald Weltead384642008-12-26 10:20:07 +0000724 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000725 return rc;
726}
727
728#if 0
729/* initialized all resources */
730struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
731{
732 struct abis_nm_h *nmh;
733
734 nmh = malloc(sizeof(*nmh));
735 if (!nmh)
736 return NULL;
737
738 nmh->cfg = cfg;
739
740 return nmh;
741}
742
743/* free all resources */
744void abis_nm_fini(struct abis_nm_h *nmh)
745{
746 free(nmh);
747}
748#endif
749
750/* Here we are trying to define a high-level API that can be used by
751 * the actual BSC implementation. However, the architecture is currently
752 * still under design. Ideally the calls to this API would be synchronous,
753 * while the underlying stack behind the APi runs in a traditional select
754 * based state machine.
755 */
756
Harald Welte4724f992009-01-18 18:01:49 +0000757/* 6.2 Software Load: */
758enum sw_state {
759 SW_STATE_NONE,
760 SW_STATE_WAIT_INITACK,
761 SW_STATE_WAIT_SEGACK,
762 SW_STATE_WAIT_ENDACK,
763 SW_STATE_WAIT_ACTACK,
764 SW_STATE_ERROR,
765};
Harald Welte52b1f982008-12-23 20:25:15 +0000766
Harald Welte52b1f982008-12-23 20:25:15 +0000767struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000768 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800769 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000770 gsm_cbfn *cbfn;
771 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000772 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000773
Harald Welte52b1f982008-12-23 20:25:15 +0000774 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200775 uint8_t obj_class;
776 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000777
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200778 uint8_t file_id[255];
779 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000780
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200781 uint8_t file_version[255];
782 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000783
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200784 uint8_t window_size;
785 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000786
787 int fd;
788 FILE *stream;
789 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000790 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000791};
792
Harald Welte4724f992009-01-18 18:01:49 +0000793static struct abis_nm_sw g_sw;
794
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100795static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
796{
797 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
798 msgb_v_put(msg, NM_ATT_SW_DESCR);
799 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
800 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
801 sw->file_version);
802 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
803 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
804 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
805 sw->file_version);
806 } else {
807 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
808 }
809}
810
Harald Welte4724f992009-01-18 18:01:49 +0000811/* 6.2.1 / 8.3.1: Load Data Initiate */
812static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000813{
Harald Welte4724f992009-01-18 18:01:49 +0000814 struct abis_om_hdr *oh;
815 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200816 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000817
818 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
819 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
820 sw->obj_instance[0], sw->obj_instance[1],
821 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100822
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100823 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000824 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
825
826 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000827}
828
Harald Welte1602ade2009-01-29 21:12:39 +0000829static int is_last_line(FILE *stream)
830{
831 char next_seg_buf[256];
832 long pos;
833
834 /* check if we're sending the last line */
835 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200836
837 /* Did ftell fail? Then we are at the end for sure */
838 if (pos < 0)
839 return 1;
840
Harald Welte1602ade2009-01-29 21:12:39 +0000841 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +0100842 int rc = fseek(stream, pos, SEEK_SET);
843 if (rc < 0)
844 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000845 return 1;
846 }
847
848 fseek(stream, pos, SEEK_SET);
849 return 0;
850}
851
Harald Welte4724f992009-01-18 18:01:49 +0000852/* 6.2.2 / 8.3.2 Load Data Segment */
853static int sw_load_segment(struct abis_nm_sw *sw)
854{
855 struct abis_om_hdr *oh;
856 struct msgb *msg = nm_msgb_alloc();
857 char seg_buf[256];
858 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000859 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200860 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000861
862 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000863
864 switch (sw->bts->type) {
865 case GSM_BTS_TYPE_BS11:
866 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
867 perror("fgets reading segment");
868 return -EINVAL;
869 }
870 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000871
872 /* check if we're sending the last line */
873 sw->last_seg = is_last_line(sw->stream);
874 if (sw->last_seg)
875 seg_buf[1] = 0;
876 else
877 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000878
879 len = strlen(line_buf) + 2;
880 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200881 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000882 /* BS11 wants CR + LF in excess of the TLV length !?! */
883 tlv[1] -= 2;
884
885 /* we only now know the exact length for the OM hdr */
886 len = strlen(line_buf)+2;
887 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100888 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200889 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100890 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
891 if (len < 0) {
892 perror("read failed");
893 return -EINVAL;
894 }
895
896 if (len != IPACC_SEGMENT_SIZE)
897 sw->last_seg = 1;
898
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100899 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200900 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100901 len += 3;
902 break;
903 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000904 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100905 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000906 /* FIXME: Other BTS types */
907 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000908 }
Harald Welte4724f992009-01-18 18:01:49 +0000909
Harald Welte4724f992009-01-18 18:01:49 +0000910 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
911 sw->obj_instance[0], sw->obj_instance[1],
912 sw->obj_instance[2]);
913
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100914 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000915}
916
917/* 6.2.4 / 8.3.4 Load Data End */
918static int sw_load_end(struct abis_nm_sw *sw)
919{
920 struct abis_om_hdr *oh;
921 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200922 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000923
924 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
925 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
926 sw->obj_instance[0], sw->obj_instance[1],
927 sw->obj_instance[2]);
928
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100929 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000930 return abis_nm_sendmsg(sw->bts, msg);
931}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000932
Harald Welte52b1f982008-12-23 20:25:15 +0000933/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000934static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000935{
Harald Welte4724f992009-01-18 18:01:49 +0000936 struct abis_om_hdr *oh;
937 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200938 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000939
Harald Welte4724f992009-01-18 18:01:49 +0000940 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
941 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
942 sw->obj_instance[0], sw->obj_instance[1],
943 sw->obj_instance[2]);
944
945 /* FIXME: this is BS11 specific format */
946 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
947 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
948 sw->file_version);
949
950 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000951}
Harald Welte4724f992009-01-18 18:01:49 +0000952
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100953struct sdp_firmware {
954 char magic[4];
955 char more_magic[4];
956 unsigned int header_length;
957 unsigned int file_length;
958} __attribute__ ((packed));
959
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100960static int parse_sdp_header(struct abis_nm_sw *sw)
961{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100962 struct sdp_firmware firmware_header;
963 int rc;
964 struct stat stat;
965
966 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
967 if (rc != sizeof(firmware_header)) {
968 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
969 return -1;
970 }
971
972 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
973 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
974 return -1;
975 }
976
977 if (firmware_header.more_magic[0] != 0x10 ||
978 firmware_header.more_magic[1] != 0x02 ||
979 firmware_header.more_magic[2] != 0x00 ||
980 firmware_header.more_magic[3] != 0x00) {
981 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
982 return -1;
983 }
984
985
986 if (fstat(sw->fd, &stat) == -1) {
987 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
988 return -1;
989 }
990
991 if (ntohl(firmware_header.file_length) != stat.st_size) {
992 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
993 return -1;
994 }
995
996 /* go back to the start as we checked the whole filesize.. */
997 lseek(sw->fd, 0l, SEEK_SET);
998 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
999 "There might be checksums in the file that are not\n"
1000 "verified and incomplete firmware might be flashed.\n"
1001 "There is absolutely no WARRANTY that flashing will\n"
1002 "work.\n");
1003 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001004}
1005
Harald Welte4724f992009-01-18 18:01:49 +00001006static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1007{
1008 char file_id[12+1];
1009 char file_version[80+1];
1010 int rc;
1011
1012 sw->fd = open(fname, O_RDONLY);
1013 if (sw->fd < 0)
1014 return sw->fd;
1015
1016 switch (sw->bts->type) {
1017 case GSM_BTS_TYPE_BS11:
1018 sw->stream = fdopen(sw->fd, "r");
1019 if (!sw->stream) {
1020 perror("fdopen");
1021 return -1;
1022 }
1023 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001024 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001025 file_id, file_version);
1026 if (rc != 2) {
1027 perror("parsing header line of software file");
1028 return -1;
1029 }
1030 strcpy((char *)sw->file_id, file_id);
1031 sw->file_id_len = strlen(file_id);
1032 strcpy((char *)sw->file_version, file_version);
1033 sw->file_version_len = strlen(file_version);
1034 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001035 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001036 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001037 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001038 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001039 rc = parse_sdp_header(sw);
1040 if (rc < 0) {
1041 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1042 return -1;
1043 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001044
1045 strcpy((char *)sw->file_id, "id");
1046 sw->file_id_len = 3;
1047 strcpy((char *)sw->file_version, "version");
1048 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001049 break;
Harald Welte4724f992009-01-18 18:01:49 +00001050 default:
1051 /* We don't know how to treat them yet */
1052 close(sw->fd);
1053 return -EINVAL;
1054 }
1055
1056 return 0;
1057}
1058
1059static void sw_close_file(struct abis_nm_sw *sw)
1060{
1061 switch (sw->bts->type) {
1062 case GSM_BTS_TYPE_BS11:
1063 fclose(sw->stream);
1064 break;
1065 default:
1066 close(sw->fd);
1067 break;
1068 }
1069}
1070
1071/* Fill the window */
1072static int sw_fill_window(struct abis_nm_sw *sw)
1073{
1074 int rc;
1075
1076 while (sw->seg_in_window < sw->window_size) {
1077 rc = sw_load_segment(sw);
1078 if (rc < 0)
1079 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001080 if (sw->last_seg)
1081 break;
Harald Welte4724f992009-01-18 18:01:49 +00001082 }
1083 return 0;
1084}
1085
1086/* callback function from abis_nm_rcvmsg() handler */
1087static int abis_nm_rcvmsg_sw(struct msgb *mb)
1088{
1089 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001090 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001091 int rc = -1;
1092 struct abis_nm_sw *sw = &g_sw;
1093 enum sw_state old_state = sw->state;
1094
Harald Welte3ffd1372009-02-01 22:15:49 +00001095 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001096
1097 switch (sw->state) {
1098 case SW_STATE_WAIT_INITACK:
1099 switch (foh->msg_type) {
1100 case NM_MT_LOAD_INIT_ACK:
1101 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001102 if (sw->cbfn)
1103 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1104 NM_MT_LOAD_INIT_ACK, mb,
1105 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001106 rc = sw_fill_window(sw);
1107 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001108 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001109 break;
1110 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001111 if (sw->forced) {
1112 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1113 "Init NACK\n");
1114 if (sw->cbfn)
1115 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1116 NM_MT_LOAD_INIT_ACK, mb,
1117 sw->cb_data, NULL);
1118 rc = sw_fill_window(sw);
1119 sw->state = SW_STATE_WAIT_SEGACK;
1120 } else {
1121 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001122 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001123 if (sw->cbfn)
1124 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1125 NM_MT_LOAD_INIT_NACK, mb,
1126 sw->cb_data, NULL);
1127 sw->state = SW_STATE_ERROR;
1128 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001129 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001130 break;
1131 }
1132 break;
1133 case SW_STATE_WAIT_SEGACK:
1134 switch (foh->msg_type) {
1135 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001136 if (sw->cbfn)
1137 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1138 NM_MT_LOAD_SEG_ACK, mb,
1139 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001140 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001141 if (!sw->last_seg) {
1142 /* fill window with more segments */
1143 rc = sw_fill_window(sw);
1144 sw->state = SW_STATE_WAIT_SEGACK;
1145 } else {
1146 /* end the transfer */
1147 sw->state = SW_STATE_WAIT_ENDACK;
1148 rc = sw_load_end(sw);
1149 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001150 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001151 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001152 case NM_MT_LOAD_ABORT:
1153 if (sw->cbfn)
1154 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1155 NM_MT_LOAD_ABORT, mb,
1156 sw->cb_data, NULL);
1157 break;
Harald Welte4724f992009-01-18 18:01:49 +00001158 }
1159 break;
1160 case SW_STATE_WAIT_ENDACK:
1161 switch (foh->msg_type) {
1162 case NM_MT_LOAD_END_ACK:
1163 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001164 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1165 sw->bts->nr);
1166 sw->state = SW_STATE_NONE;
1167 if (sw->cbfn)
1168 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1169 NM_MT_LOAD_END_ACK, mb,
1170 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001171 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001172 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001173 break;
1174 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001175 if (sw->forced) {
1176 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1177 "End NACK\n");
1178 sw->state = SW_STATE_NONE;
1179 if (sw->cbfn)
1180 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1181 NM_MT_LOAD_END_ACK, mb,
1182 sw->cb_data, NULL);
1183 } else {
1184 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001185 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001186 sw->state = SW_STATE_ERROR;
1187 if (sw->cbfn)
1188 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1189 NM_MT_LOAD_END_NACK, mb,
1190 sw->cb_data, NULL);
1191 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001192 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001193 break;
1194 }
1195 case SW_STATE_WAIT_ACTACK:
1196 switch (foh->msg_type) {
1197 case NM_MT_ACTIVATE_SW_ACK:
1198 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001199 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001200 sw->state = SW_STATE_NONE;
1201 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001202 if (sw->cbfn)
1203 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1204 NM_MT_ACTIVATE_SW_ACK, mb,
1205 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001206 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001207 break;
1208 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001209 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001210 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001211 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001212 if (sw->cbfn)
1213 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1214 NM_MT_ACTIVATE_SW_NACK, mb,
1215 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001216 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001217 break;
1218 }
1219 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001220 switch (foh->msg_type) {
1221 case NM_MT_ACTIVATE_SW_ACK:
1222 rc = 0;
1223 break;
1224 }
1225 break;
Harald Welte4724f992009-01-18 18:01:49 +00001226 case SW_STATE_ERROR:
1227 break;
1228 }
1229
1230 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001231 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001232 foh->msg_type, old_state, sw->state);
1233
1234 return rc;
1235}
1236
1237/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001238int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001239 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001240 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001241{
1242 struct abis_nm_sw *sw = &g_sw;
1243 int rc;
1244
Harald Welte5e4d1b32009-02-01 13:36:56 +00001245 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1246 bts->nr, fname);
1247
Harald Welte4724f992009-01-18 18:01:49 +00001248 if (sw->state != SW_STATE_NONE)
1249 return -EBUSY;
1250
1251 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001252 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001253
1254 switch (bts->type) {
1255 case GSM_BTS_TYPE_BS11:
1256 sw->obj_class = NM_OC_SITE_MANAGER;
1257 sw->obj_instance[0] = 0xff;
1258 sw->obj_instance[1] = 0xff;
1259 sw->obj_instance[2] = 0xff;
1260 break;
1261 case GSM_BTS_TYPE_NANOBTS:
1262 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001263 sw->obj_instance[0] = sw->bts->nr;
1264 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001265 sw->obj_instance[2] = 0xff;
1266 break;
1267 case GSM_BTS_TYPE_UNKNOWN:
1268 default:
1269 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1270 return -1;
1271 break;
1272 }
Harald Welte4724f992009-01-18 18:01:49 +00001273 sw->window_size = win_size;
1274 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001275 sw->cbfn = cbfn;
1276 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001277 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001278
1279 rc = sw_open_file(sw, fname);
1280 if (rc < 0) {
1281 sw->state = SW_STATE_NONE;
1282 return rc;
1283 }
1284
1285 return sw_load_init(sw);
1286}
Harald Welte52b1f982008-12-23 20:25:15 +00001287
Harald Welte1602ade2009-01-29 21:12:39 +00001288int abis_nm_software_load_status(struct gsm_bts *bts)
1289{
1290 struct abis_nm_sw *sw = &g_sw;
1291 struct stat st;
1292 int rc, percent;
1293
1294 rc = fstat(sw->fd, &st);
1295 if (rc < 0) {
1296 perror("ERROR during stat");
1297 return rc;
1298 }
1299
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001300 if (sw->stream)
1301 percent = (ftell(sw->stream) * 100) / st.st_size;
1302 else
1303 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001304 return percent;
1305}
1306
Harald Welte5e4d1b32009-02-01 13:36:56 +00001307/* Activate the specified software into the BTS */
1308int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1309 gsm_cbfn *cbfn, void *cb_data)
1310{
1311 struct abis_nm_sw *sw = &g_sw;
1312 int rc;
1313
1314 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1315 bts->nr, fname);
1316
1317 if (sw->state != SW_STATE_NONE)
1318 return -EBUSY;
1319
1320 sw->bts = bts;
1321 sw->obj_class = NM_OC_SITE_MANAGER;
1322 sw->obj_instance[0] = 0xff;
1323 sw->obj_instance[1] = 0xff;
1324 sw->obj_instance[2] = 0xff;
1325 sw->state = SW_STATE_WAIT_ACTACK;
1326 sw->cbfn = cbfn;
1327 sw->cb_data = cb_data;
1328
1329 /* Open the file in order to fill some sw struct members */
1330 rc = sw_open_file(sw, fname);
1331 if (rc < 0) {
1332 sw->state = SW_STATE_NONE;
1333 return rc;
1334 }
1335 sw_close_file(sw);
1336
1337 return sw_activate(sw);
1338}
1339
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001340static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1341 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001342{
Harald Welteadaf08b2009-01-18 11:08:10 +00001343 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001344 ch->bts_port = bts_port;
1345 ch->timeslot = ts_nr;
1346 ch->subslot = subslot_nr;
1347}
1348
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001349int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1350 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1351 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001352{
1353 struct abis_om_hdr *oh;
1354 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001355 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001356 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001357
1358 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1359 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1360 bts->bts_nr, trx_nr, 0xff);
1361
Harald Welte8470bf22008-12-25 23:28:35 +00001362 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001363
1364 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1365 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1366
1367 return abis_nm_sendmsg(bts, msg);
1368}
1369
1370/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1371int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001372 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001373{
Harald Welte8470bf22008-12-25 23:28:35 +00001374 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001375 struct abis_om_hdr *oh;
1376 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001377 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001378
1379 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001380 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001381 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1382
1383 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1384 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1385
1386 return abis_nm_sendmsg(bts, msg);
1387}
1388
1389#if 0
1390int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1391 struct abis_nm_abis_channel *chan)
1392{
1393}
1394#endif
1395
1396int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001397 uint8_t e1_port, uint8_t e1_timeslot,
1398 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001399{
1400 struct gsm_bts *bts = ts->trx->bts;
1401 struct abis_om_hdr *oh;
1402 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001403 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001404
1405 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1406 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001407 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001408
1409 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1410 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1411
Harald Weltef325eb42009-02-19 17:07:39 +00001412 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1413 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001414 e1_port, e1_timeslot, e1_subslot);
1415
Harald Welte52b1f982008-12-23 20:25:15 +00001416 return abis_nm_sendmsg(bts, msg);
1417}
1418
1419#if 0
1420int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1421 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001422 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001423{
1424}
1425#endif
1426
Harald Weltefe568f22012-08-14 19:15:57 +02001427/* Chapter 8.11.1 */
1428int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1429 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1430 uint8_t *attr, uint8_t attr_len)
1431{
1432 struct abis_om_hdr *oh;
1433 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001434
1435 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1436
1437 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1438 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1439 bts_nr, trx_nr, ts_nr);
1440 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1441
1442 return abis_nm_sendmsg(bts, msg);
1443}
1444
Harald Welte22af0db2009-02-14 15:41:08 +00001445/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001446int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001447{
1448 struct abis_om_hdr *oh;
1449 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001450 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001451
1452 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1453
1454 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001455 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 +00001456 cur = msgb_put(msg, attr_len);
1457 memcpy(cur, attr, attr_len);
1458
1459 return abis_nm_sendmsg(bts, msg);
1460}
1461
1462/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001463int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001464{
1465 struct abis_om_hdr *oh;
1466 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001467 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001468
1469 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1470
1471 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1472 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001473 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001474 cur = msgb_put(msg, attr_len);
1475 memcpy(cur, attr, attr_len);
1476
1477 return abis_nm_sendmsg(trx->bts, msg);
1478}
1479
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001480int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1481{
1482 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1483 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1484}
1485
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001486static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1487 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001488{
1489 int i;
1490
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001491 *reason = "Reason unknown";
1492
Harald Welte39c7deb2009-08-09 21:49:48 +02001493 /* As it turns out, the BS-11 has some very peculiar restrictions
1494 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301495 switch (ts->trx->bts->type) {
1496 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001497 switch (chan_comb) {
1498 case NM_CHANC_TCHHalf:
1499 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001500 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001501 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001502 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001503 return -EINVAL;
1504 case NM_CHANC_SDCCH:
1505 /* only one SDCCH/8 per TRX */
1506 for (i = 0; i < TRX_NR_TS; i++) {
1507 if (i == ts->nr)
1508 continue;
1509 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001510 NM_CHANC_SDCCH) {
1511 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001512 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001513 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001514 }
1515 /* not allowed for TS0 of BCCH-TRX */
1516 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001517 ts->nr == 0) {
1518 *reason = "SDCCH/8 must be on TS0.";
1519 return -EINVAL;
1520 }
1521
Harald Welte39c7deb2009-08-09 21:49:48 +02001522 /* not on the same TRX that has a BCCH+SDCCH4
1523 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001524 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001525 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001526 ts->trx->ts[0].nm_chan_comb == 8)) {
1527 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1528 return -EINVAL;
1529 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001530 break;
1531 case NM_CHANC_mainBCCH:
1532 case NM_CHANC_BCCHComb:
1533 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001534 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1535 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001536 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001537 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001538 break;
1539 case NM_CHANC_BCCH:
1540 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001541 if (ts->trx != ts->trx->bts->c0) {
1542 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001543 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001544 }
1545 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1546 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001547 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001548 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001549 break;
1550 case 8: /* this is not like 08.58, but in fact
1551 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1552 /* FIXME: only one CBCH allowed per cell */
1553 break;
1554 }
Harald Welted6575f92009-12-02 02:45:23 +05301555 break;
1556 case GSM_BTS_TYPE_NANOBTS:
1557 switch (ts->nr) {
1558 case 0:
1559 if (ts->trx->nr == 0) {
1560 /* only on TRX0 */
1561 switch (chan_comb) {
1562 case NM_CHANC_BCCH:
1563 case NM_CHANC_mainBCCH:
1564 case NM_CHANC_BCCHComb:
1565 return 0;
1566 break;
1567 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001568 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301569 return -EINVAL;
1570 }
1571 } else {
1572 switch (chan_comb) {
1573 case NM_CHANC_TCHFull:
1574 case NM_CHANC_TCHHalf:
1575 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1576 return 0;
1577 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001578 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301579 return -EINVAL;
1580 }
1581 }
1582 break;
1583 case 1:
1584 if (ts->trx->nr == 0) {
1585 switch (chan_comb) {
1586 case NM_CHANC_SDCCH_CBCH:
1587 if (ts->trx->ts[0].nm_chan_comb ==
1588 NM_CHANC_mainBCCH)
1589 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001590 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301591 return -EINVAL;
1592 case NM_CHANC_SDCCH:
1593 case NM_CHANC_TCHFull:
1594 case NM_CHANC_TCHHalf:
1595 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1596 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001597 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301598 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001599 default:
1600 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1601 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301602 }
1603 } else {
1604 switch (chan_comb) {
1605 case NM_CHANC_SDCCH:
1606 case NM_CHANC_TCHFull:
1607 case NM_CHANC_TCHHalf:
1608 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1609 return 0;
1610 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001611 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301612 return -EINVAL;
1613 }
1614 }
1615 break;
1616 case 2:
1617 case 3:
1618 case 4:
1619 case 5:
1620 case 6:
1621 case 7:
1622 switch (chan_comb) {
1623 case NM_CHANC_TCHFull:
1624 case NM_CHANC_TCHHalf:
1625 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1626 return 0;
1627 case NM_CHANC_IPAC_PDCH:
1628 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001629 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301630 if (ts->trx->nr == 0)
1631 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001632 else {
1633 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301634 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001635 }
Harald Welted6575f92009-12-02 02:45:23 +05301636 }
1637 break;
1638 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001639 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301640 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001641 case GSM_BTS_TYPE_OSMO_SYSMO:
1642 /* no known restrictions */
1643 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301644 default:
1645 /* unknown BTS type */
1646 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001647 }
1648 return 0;
1649}
1650
Harald Welte22af0db2009-02-14 15:41:08 +00001651/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001652int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001653{
1654 struct gsm_bts *bts = ts->trx->bts;
1655 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001656 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001657 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001658 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001659 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001660
1661 if (bts->type == GSM_BTS_TYPE_BS11)
1662 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001663
Harald Weltef325eb42009-02-19 17:07:39 +00001664 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001665 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001666 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001667 LOGP(DNM, LOGL_ERROR,
1668 "Invalid Channel Combination %d on %s. Reason: %s\n",
1669 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001670 return -EINVAL;
1671 }
1672 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001673
Harald Welte52b1f982008-12-23 20:25:15 +00001674 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001675 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001676 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001677 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001678 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001679 if (ts->hopping.enabled) {
1680 unsigned int i;
1681 uint8_t *len;
1682
Harald Welte6e0cd042009-09-12 13:05:33 +02001683 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1684 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001685
1686 /* build the ARFCN list */
1687 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1688 len = msgb_put(msg, 1);
1689 *len = 0;
1690 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1691 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1692 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001693 /* At least BS-11 wants a TLV16 here */
1694 if (bts->type == GSM_BTS_TYPE_BS11)
1695 *len += 1;
1696 else
1697 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001698 }
1699 }
Harald Weltee0590df2009-02-15 03:34:15 +00001700 }
Harald Welte1fe24122014-01-19 17:18:21 +01001701 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001702 if (bts->type == GSM_BTS_TYPE_BS11)
1703 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001704
1705 return abis_nm_sendmsg(bts, msg);
1706}
1707
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001708int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1709 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001710{
1711 struct abis_om_hdr *oh;
1712 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001713 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1714 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001715
1716 if (nack) {
1717 len += 2;
1718 msgtype = NM_MT_SW_ACT_REQ_NACK;
1719 }
Harald Welte34a99682009-02-13 02:41:40 +00001720
1721 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001722 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1723
Harald Welte34a99682009-02-13 02:41:40 +00001724 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001725 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001726 memcpy(ptr, attr, att_len);
1727 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001728 if (nack)
1729 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001730
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001731 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001732}
1733
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001734int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001735{
Harald Welte8470bf22008-12-25 23:28:35 +00001736 struct msgb *msg = nm_msgb_alloc();
1737 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001738 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001739
1740 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1741 fill_om_hdr(oh, len);
1742 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001743 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001744
1745 return abis_nm_sendmsg(bts, msg);
1746}
1747
1748/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001749static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001750{
1751 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001752 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001753
1754 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001755 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001756 0xff, 0xff, 0xff);
1757
1758 return abis_nm_sendmsg(bts, msg);
1759}
1760
Harald Welte34a99682009-02-13 02:41:40 +00001761/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001762int 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 +00001763{
1764 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001765 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001766 struct msgb *msg = nm_msgb_alloc();
1767
1768 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001769 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001770
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001771 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001772 DEBUGPC(DNM, "Sending OPSTART\n");
1773
Harald Welte34a99682009-02-13 02:41:40 +00001774 return abis_nm_sendmsg(bts, msg);
1775}
1776
1777/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001778int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1779 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001780{
1781 struct abis_om_hdr *oh;
1782 struct msgb *msg = nm_msgb_alloc();
1783
1784 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1785 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1786 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1787
1788 return abis_nm_sendmsg(bts, msg);
1789}
1790
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001791int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1792 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001793{
1794 struct abis_om_hdr *oh;
1795 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001796 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001797
1798 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1799 e1_port0, ts0, e1_port1, ts1);
1800
1801 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1802 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1803 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1804
1805 attr = msgb_put(msg, 3);
1806 attr[0] = NM_ATT_MDROP_LINK;
1807 attr[1] = e1_port0;
1808 attr[2] = ts0;
1809
1810 attr = msgb_put(msg, 3);
1811 attr[0] = NM_ATT_MDROP_NEXT;
1812 attr[1] = e1_port1;
1813 attr[2] = ts1;
1814
1815 return abis_nm_sendmsg(bts, msg);
1816}
Harald Welte34a99682009-02-13 02:41:40 +00001817
Harald Weltec7310382009-08-08 00:02:36 +02001818/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001819int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1820 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1821 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001822{
1823 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001824
Harald Welte15c61722011-05-22 22:45:37 +02001825 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001826
1827 if (!msg)
1828 msg = nm_msgb_alloc();
1829
1830 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1831 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1832 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1833 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001834 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001835
1836 return abis_nm_sendmsg(bts, msg);
1837}
1838
Harald Welte52b1f982008-12-23 20:25:15 +00001839int abis_nm_event_reports(struct gsm_bts *bts, int on)
1840{
1841 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001842 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001843 else
Harald Welte227d4072009-01-03 08:16:25 +00001844 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001845}
1846
Harald Welte47d88ae2009-01-04 12:02:08 +00001847/* Siemens (or BS-11) specific commands */
1848
Harald Welte3ffd1372009-02-01 22:15:49 +00001849int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1850{
1851 if (reconnect == 0)
1852 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1853 else
1854 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1855}
1856
Harald Welteb8427972009-02-05 19:27:17 +00001857int abis_nm_bs11_restart(struct gsm_bts *bts)
1858{
1859 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1860}
1861
1862
Harald Welte268bb402009-02-01 19:11:56 +00001863struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001864 uint16_t year;
1865 uint8_t month;
1866 uint8_t day;
1867 uint8_t hour;
1868 uint8_t min;
1869 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001870} __attribute__((packed));
1871
1872
1873void get_bs11_date_time(struct bs11_date_time *aet)
1874{
1875 time_t t;
1876 struct tm *tm;
1877
1878 t = time(NULL);
1879 tm = localtime(&t);
1880 aet->sec = tm->tm_sec;
1881 aet->min = tm->tm_min;
1882 aet->hour = tm->tm_hour;
1883 aet->day = tm->tm_mday;
1884 aet->month = tm->tm_mon;
1885 aet->year = htons(1900 + tm->tm_year);
1886}
1887
Harald Welte05188ee2009-01-18 11:39:08 +00001888int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001889{
Harald Welte4668fda2009-01-03 08:19:29 +00001890 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001891}
1892
Harald Welte05188ee2009-01-18 11:39:08 +00001893int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001894{
1895 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001896 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001897 else
Harald Welte4668fda2009-01-03 08:19:29 +00001898 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001899}
Harald Welte47d88ae2009-01-04 12:02:08 +00001900
Harald Welte05188ee2009-01-18 11:39:08 +00001901int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001902 enum abis_bs11_objtype type, uint8_t idx,
1903 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001904{
1905 struct abis_om_hdr *oh;
1906 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001907 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001908
1909 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001910 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001911 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001912 cur = msgb_put(msg, attr_len);
1913 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001914
1915 return abis_nm_sendmsg(bts, msg);
1916}
1917
Harald Welte78fc0d42009-02-19 02:50:57 +00001918int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001919 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001920{
1921 struct abis_om_hdr *oh;
1922 struct msgb *msg = nm_msgb_alloc();
1923
1924 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1925 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1926 NM_OC_BS11, type, 0, idx);
1927
1928 return abis_nm_sendmsg(bts, msg);
1929}
1930
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001931int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001932{
1933 struct abis_om_hdr *oh;
1934 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001935 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001936
1937 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001938 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001939 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1940 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001941
1942 return abis_nm_sendmsg(bts, msg);
1943}
1944
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001945int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001946{
1947 struct abis_om_hdr *oh;
1948 struct msgb *msg = nm_msgb_alloc();
1949
1950 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1951 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001952 idx, 0xff, 0xff);
1953
1954 return abis_nm_sendmsg(bts, msg);
1955}
1956
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001957int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001958{
1959 struct abis_om_hdr *oh;
1960 struct msgb *msg = nm_msgb_alloc();
1961
1962 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1963 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1964 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001965
1966 return abis_nm_sendmsg(bts, msg);
1967}
Harald Welte05188ee2009-01-18 11:39:08 +00001968
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001969static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001970int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1971{
1972 struct abis_om_hdr *oh;
1973 struct msgb *msg = nm_msgb_alloc();
1974
1975 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1976 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1977 0xff, 0xff, 0xff);
1978 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1979
1980 return abis_nm_sendmsg(bts, msg);
1981}
1982
Harald Welteb6c92ae2009-02-21 20:15:32 +00001983/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001984int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1985 uint8_t e1_timeslot, uint8_t e1_subslot,
1986 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001987{
1988 struct abis_om_hdr *oh;
1989 struct abis_nm_channel *ch;
1990 struct msgb *msg = nm_msgb_alloc();
1991
1992 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001993 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001994 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1995
1996 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1997 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001998 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001999
2000 return abis_nm_sendmsg(bts, msg);
2001}
2002
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002003int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002004{
2005 struct abis_om_hdr *oh;
2006 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002007
2008 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002009 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002010 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2011 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2012
2013 return abis_nm_sendmsg(trx->bts, msg);
2014}
2015
Harald Welte78fc0d42009-02-19 02:50:57 +00002016int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2017{
2018 struct abis_om_hdr *oh;
2019 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002020 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002021
2022 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2023 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2024 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2025 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2026
2027 return abis_nm_sendmsg(trx->bts, msg);
2028}
2029
Harald Welteaaf02d92009-04-29 13:25:57 +00002030int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2031{
2032 struct abis_om_hdr *oh;
2033 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002034 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002035
2036 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2037 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2038 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002039 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002040
2041 return abis_nm_sendmsg(bts, msg);
2042}
2043
Harald Welteef061952009-05-17 12:43:42 +00002044int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2045{
2046 struct abis_om_hdr *oh;
2047 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002048 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002049 NM_ATT_BS11_CCLK_TYPE };
2050
2051 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2052 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2053 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2054 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2055
2056 return abis_nm_sendmsg(bts, msg);
2057
2058}
Harald Welteaaf02d92009-04-29 13:25:57 +00002059
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002060//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002061
Harald Welte1bc09062009-01-18 14:17:52 +00002062int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002063{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002064 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2065}
2066
Daniel Willmann4b054c82010-01-07 00:46:26 +01002067int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2068{
2069 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2070}
2071
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002072int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002073{
Harald Welte05188ee2009-01-18 11:39:08 +00002074 struct abis_om_hdr *oh;
2075 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002076 struct bs11_date_time bdt;
2077
2078 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002079
2080 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002081 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002082 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002083 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002084 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002085 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002086 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002087 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002088 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002089 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002090 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002091 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002092 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002093 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002094 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002095 }
Harald Welte05188ee2009-01-18 11:39:08 +00002096
2097 return abis_nm_sendmsg(bts, msg);
2098}
Harald Welte1bc09062009-01-18 14:17:52 +00002099
2100int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2101{
2102 struct abis_om_hdr *oh;
2103 struct msgb *msg;
2104
2105 if (strlen(password) != 10)
2106 return -EINVAL;
2107
2108 msg = nm_msgb_alloc();
2109 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002110 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002111 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002112 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002113
2114 return abis_nm_sendmsg(bts, msg);
2115}
2116
Harald Weltee69f5fb2009-04-28 16:31:38 +00002117/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2118int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2119{
2120 struct abis_om_hdr *oh;
2121 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002122 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002123
2124 msg = nm_msgb_alloc();
2125 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2126 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2127 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002128
2129 if (locked)
2130 tlv_value = BS11_LI_PLL_LOCKED;
2131 else
2132 tlv_value = BS11_LI_PLL_STANDALONE;
2133
2134 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002135
2136 return abis_nm_sendmsg(bts, msg);
2137}
2138
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002139/* Set the calibration value of the PLL (work value/set value)
2140 * It depends on the login which one is changed */
2141int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2142{
2143 struct abis_om_hdr *oh;
2144 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002145 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002146
2147 msg = nm_msgb_alloc();
2148 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2149 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2150 BS11_OBJ_TRX1, 0x00, 0x00);
2151
2152 tlv_value[0] = value>>8;
2153 tlv_value[1] = value&0xff;
2154
2155 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2156
2157 return abis_nm_sendmsg(bts, msg);
2158}
2159
Harald Welte1bc09062009-01-18 14:17:52 +00002160int abis_nm_bs11_get_state(struct gsm_bts *bts)
2161{
2162 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2163}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002164
2165/* BS11 SWL */
2166
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002167void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002168
Harald Welte5e4d1b32009-02-01 13:36:56 +00002169struct abis_nm_bs11_sw {
2170 struct gsm_bts *bts;
2171 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002172 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002173 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002174 struct llist_head file_list;
2175 gsm_cbfn *user_cb; /* specified by the user */
2176};
2177static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2178
2179struct file_list_entry {
2180 struct llist_head list;
2181 char fname[PATH_MAX];
2182};
2183
2184struct file_list_entry *fl_dequeue(struct llist_head *queue)
2185{
2186 struct llist_head *lh;
2187
2188 if (llist_empty(queue))
2189 return NULL;
2190
2191 lh = queue->next;
2192 llist_del(lh);
2193
2194 return llist_entry(lh, struct file_list_entry, list);
2195}
2196
2197static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2198{
2199 char linebuf[255];
2200 struct llist_head *lh, *lh2;
2201 FILE *swl;
2202 int rc = 0;
2203
2204 swl = fopen(bs11_sw->swl_fname, "r");
2205 if (!swl)
2206 return -ENODEV;
2207
2208 /* zero the stale file list, if any */
2209 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2210 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002211 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002212 }
2213
2214 while (fgets(linebuf, sizeof(linebuf), swl)) {
2215 char file_id[12+1];
2216 char file_version[80+1];
2217 struct file_list_entry *fle;
2218 static char dir[PATH_MAX];
2219
2220 if (strlen(linebuf) < 4)
2221 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002222
Harald Welte5e4d1b32009-02-01 13:36:56 +00002223 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2224 if (rc < 0) {
2225 perror("ERR parsing SWL file");
2226 rc = -EINVAL;
2227 goto out;
2228 }
2229 if (rc < 2)
2230 continue;
2231
Harald Welte470ec292009-06-26 20:25:23 +02002232 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002233 if (!fle) {
2234 rc = -ENOMEM;
2235 goto out;
2236 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002237
2238 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002239 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002240 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2241 strcat(fle->fname, "/");
2242 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002243
2244 llist_add_tail(&fle->list, &bs11_sw->file_list);
2245 }
2246
2247out:
2248 fclose(swl);
2249 return rc;
2250}
2251
2252/* bs11 swload specific callback, passed to abis_nm core swload */
2253static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2254 struct msgb *msg, void *data, void *param)
2255{
2256 struct abis_nm_bs11_sw *bs11_sw = data;
2257 struct file_list_entry *fle;
2258 int rc = 0;
2259
Harald Welte5e4d1b32009-02-01 13:36:56 +00002260 switch (event) {
2261 case NM_MT_LOAD_END_ACK:
2262 fle = fl_dequeue(&bs11_sw->file_list);
2263 if (fle) {
2264 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002265 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002266 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002267 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002268 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002269 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002270 } else {
2271 /* activate the SWL */
2272 rc = abis_nm_software_activate(bs11_sw->bts,
2273 bs11_sw->swl_fname,
2274 bs11_swload_cbfn,
2275 bs11_sw);
2276 }
2277 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002278 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002279 case NM_MT_LOAD_END_NACK:
2280 case NM_MT_LOAD_INIT_ACK:
2281 case NM_MT_LOAD_INIT_NACK:
2282 case NM_MT_ACTIVATE_SW_NACK:
2283 case NM_MT_ACTIVATE_SW_ACK:
2284 default:
2285 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002286 if (bs11_sw->user_cb)
2287 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002288 break;
2289 }
2290
2291 return rc;
2292}
2293
2294/* Siemens provides a SWL file that is a mere listing of all the other
2295 * files that are part of a software release. We need to upload first
2296 * the list file, and then each file that is listed in the list file */
2297int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002298 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002299{
2300 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2301 struct file_list_entry *fle;
2302 int rc = 0;
2303
2304 INIT_LLIST_HEAD(&bs11_sw->file_list);
2305 bs11_sw->bts = bts;
2306 bs11_sw->win_size = win_size;
2307 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002308 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002309
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002310 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002311 rc = bs11_read_swl_file(bs11_sw);
2312 if (rc < 0)
2313 return rc;
2314
2315 /* dequeue next item in file list */
2316 fle = fl_dequeue(&bs11_sw->file_list);
2317 if (!fle)
2318 return -EINVAL;
2319
2320 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002321 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002322 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002323 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002324 return rc;
2325}
2326
Harald Welte5083b0b2009-02-02 19:20:52 +00002327#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002328static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002329 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2330 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2331 NM_ATT_BS11_LMT_USER_NAME,
2332
2333 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2334
2335 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2336
2337 NM_ATT_BS11_SW_LOAD_STORED };
2338
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002339static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002340 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2341 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2342 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2343 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002344#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002345
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002346static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002347 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2348 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002349 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002350
2351int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2352{
2353 struct abis_om_hdr *oh;
2354 struct msgb *msg = nm_msgb_alloc();
2355
2356 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2357 /* SiemensHW CCTRL object */
2358 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2359 0x03, 0x00, 0x00);
2360 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2361
2362 return abis_nm_sendmsg(bts, msg);
2363}
Harald Welte268bb402009-02-01 19:11:56 +00002364
2365int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2366{
2367 struct abis_om_hdr *oh;
2368 struct msgb *msg = nm_msgb_alloc();
2369 struct bs11_date_time aet;
2370
2371 get_bs11_date_time(&aet);
2372 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2373 /* SiemensHW CCTRL object */
2374 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2375 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002376 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002377
2378 return abis_nm_sendmsg(bts, msg);
2379}
Harald Welte5c1e4582009-02-15 11:57:29 +00002380
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002381int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002382{
2383 struct abis_om_hdr *oh;
2384 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002385 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002386
2387 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2388 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2389 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2390 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2391
2392 return abis_nm_sendmsg(bts, msg);
2393}
2394
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002395int 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 +02002396{
2397 struct abis_om_hdr *oh;
2398 struct msgb *msg = nm_msgb_alloc();
2399 struct bs11_date_time aet;
2400
2401 get_bs11_date_time(&aet);
2402 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2403 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2404 bport, 0xff, 0x02);
2405 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2406
2407 return abis_nm_sendmsg(bts, msg);
2408}
2409
Harald Welte5c1e4582009-02-15 11:57:29 +00002410/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002411static const char ipaccess_magic[] = "com.ipaccess";
2412
Harald Welte677c21f2009-02-17 13:22:23 +00002413
2414static int abis_nm_rx_ipacc(struct msgb *msg)
2415{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002416 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002417 struct abis_om_hdr *oh = msgb_l2(msg);
2418 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002419 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002420 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002421 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002422 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002423
2424 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002425 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002426 return -EINVAL;
2427 }
2428
Harald Welte193fefc2009-04-30 15:16:27 +00002429 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002430 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002431
Harald Welte15c61722011-05-22 22:45:37 +02002432 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002433
Harald Welte746d6092009-10-19 22:11:11 +02002434 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002435
Harald Welte677c21f2009-02-17 13:22:23 +00002436 switch (foh->msg_type) {
2437 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002438 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002439 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2440 memcpy(&addr,
2441 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2442
2443 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2444 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002445 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002446 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002447 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002448 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002449 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2450 DEBUGPC(DNM, "STREAM=0x%02x ",
2451 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002452 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002453 break;
2454 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002455 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002456 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002457 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002458 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002459 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002460 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002461 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002462 case NM_MT_IPACC_SET_NVATTR_ACK:
2463 DEBUGPC(DNM, "SET NVATTR ACK\n");
2464 /* FIXME: decode and show the actual attributes */
2465 break;
2466 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002467 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002468 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002469 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002470 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002471 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002472 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002473 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002474 case NM_MT_IPACC_GET_NVATTR_ACK:
2475 DEBUGPC(DNM, "GET NVATTR ACK\n");
2476 /* FIXME: decode and show the actual attributes */
2477 break;
2478 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002479 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002480 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002481 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002482 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002483 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002484 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002485 break;
Harald Welte15c44172009-10-08 20:15:24 +02002486 case NM_MT_IPACC_SET_ATTR_ACK:
2487 DEBUGPC(DNM, "SET ATTR ACK\n");
2488 break;
2489 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002490 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002491 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002492 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002493 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002494 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002495 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002496 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002497 default:
2498 DEBUGPC(DNM, "unknown\n");
2499 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002500 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002501
2502 /* signal handling */
2503 switch (foh->msg_type) {
2504 case NM_MT_IPACC_RSL_CONNECT_NACK:
2505 case NM_MT_IPACC_SET_NVATTR_NACK:
2506 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002507 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 +01002508 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002509 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002510 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002511 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002512 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 +01002513 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002514 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002515 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002516 default:
2517 break;
2518 }
2519
Harald Welte677c21f2009-02-17 13:22:23 +00002520 return 0;
2521}
2522
Harald Welte193fefc2009-04-30 15:16:27 +00002523/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002524int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2525 uint8_t obj_class, uint8_t bts_nr,
2526 uint8_t trx_nr, uint8_t ts_nr,
2527 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002528{
2529 struct msgb *msg = nm_msgb_alloc();
2530 struct abis_om_hdr *oh;
2531 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002532 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002533
2534 /* construct the 12.21 OM header, observe the erroneous length */
2535 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2536 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2537 oh->mdisc = ABIS_OM_MDISC_MANUF;
2538
2539 /* add the ip.access magic */
2540 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2541 *data++ = sizeof(ipaccess_magic);
2542 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2543
2544 /* fill the 12.21 FOM header */
2545 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2546 foh->msg_type = msg_type;
2547 foh->obj_class = obj_class;
2548 foh->obj_inst.bts_nr = bts_nr;
2549 foh->obj_inst.trx_nr = trx_nr;
2550 foh->obj_inst.ts_nr = ts_nr;
2551
2552 if (attr && attr_len) {
2553 data = msgb_put(msg, attr_len);
2554 memcpy(data, attr, attr_len);
2555 }
2556
2557 return abis_nm_sendmsg(bts, msg);
2558}
Harald Welte677c21f2009-02-17 13:22:23 +00002559
Harald Welte193fefc2009-04-30 15:16:27 +00002560/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002561int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002562 int attr_len)
2563{
Harald Welte2ef156d2010-01-07 20:39:42 +01002564 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2565 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002566 attr_len);
2567}
2568
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002569int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002570 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002571{
2572 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002573 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002574 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2575 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2576
2577 int attr_len = sizeof(attr);
2578
2579 ia.s_addr = htonl(ip);
2580 attr[1] = stream;
2581 attr[3] = port >> 8;
2582 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002583 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002584
2585 /* if ip == 0, we use the default IP */
2586 if (ip == 0)
2587 attr_len -= 5;
2588
2589 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002590 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002591
2592 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2593 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2594 trx->nr, 0xff, attr, attr_len);
2595}
2596
Harald Welte193fefc2009-04-30 15:16:27 +00002597/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002598int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002599{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002600 struct abis_om_hdr *oh;
2601 struct msgb *msg = nm_msgb_alloc();
2602
2603 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2604 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2605 trx->bts->nr, trx->nr, 0xff);
2606
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002607 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002608}
Harald Weltedaef5212009-10-24 10:20:41 +02002609
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002610int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2611 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2612 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002613{
2614 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2615 obj_class, bts_nr, trx_nr, ts_nr,
2616 attr, attr_len);
2617}
Harald Welte0f255852009-11-12 14:48:42 +01002618
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002619void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002620{
2621 /* we simply reuse the GSM48 function and overwrite the RAC
2622 * with the Cell ID */
2623 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002624 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002625}
2626
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002627void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2628{
2629 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2630
Harald Welted64c0bc2011-05-30 12:07:53 +02002631 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002632 if (!trx->bts || !trx->bts->oml_link)
2633 return;
2634
2635 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2636 trx->bts->bts_nr, trx->nr, 0xff,
2637 new_state);
2638}
2639
Harald Welte92b1fe42010-03-25 11:45:30 +08002640static const struct value_string ipacc_testres_names[] = {
2641 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2642 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2643 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2644 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2645 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2646 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002647};
2648
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002649const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002650{
Harald Welte92b1fe42010-03-25 11:45:30 +08002651 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002652}
2653
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002654void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002655{
2656 cid->mcc = (buf[0] & 0xf) * 100;
2657 cid->mcc += (buf[0] >> 4) * 10;
2658 cid->mcc += (buf[1] & 0xf) * 1;
2659
2660 if (buf[1] >> 4 == 0xf) {
2661 cid->mnc = (buf[2] & 0xf) * 10;
2662 cid->mnc += (buf[2] >> 4) * 1;
2663 } else {
2664 cid->mnc = (buf[2] & 0xf) * 100;
2665 cid->mnc += (buf[2] >> 4) * 10;
2666 cid->mnc += (buf[1] >> 4) * 1;
2667 }
2668
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002669 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2670 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002671}
2672
Harald Welte0f255852009-11-12 14:48:42 +01002673/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002674int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002675{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002676 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002677 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002678
Harald Welteaf109b92010-07-22 18:14:36 +02002679 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002680
2681 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2682 return -EINVAL;
2683 cur++;
2684
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002685 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002686 cur += 2;
2687
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002688 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002689 cur += 2;
2690
2691 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2692 binf->freq_qual = *cur >> 2;
2693
Harald Welteaf109b92010-07-22 18:14:36 +02002694 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002695 binf->arfcn |= *cur++;
2696
2697 if (binf->info_type & IPAC_BINF_RXLEV)
2698 binf->rx_lev = *cur & 0x3f;
2699 cur++;
2700
2701 if (binf->info_type & IPAC_BINF_RXQUAL)
2702 binf->rx_qual = *cur & 0x7;
2703 cur++;
2704
2705 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002706 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002707 cur += 2;
2708
2709 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002710 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002711 cur += 2;
2712
2713 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002714 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002715 cur += 4;
2716
Harald Weltea780a3d2010-07-30 22:34:42 +02002717#if 0
2718 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002719 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002720#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002721 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002722 cur++;
2723
Harald Welteb40a38f2009-11-13 11:56:05 +01002724 ipac_parse_cgi(&binf->cgi, cur);
2725 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002726
2727 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2728 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2729 cur += sizeof(binf->ba_list_si2);
2730 }
2731
2732 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2733 memcpy(binf->ba_list_si2bis, cur,
2734 sizeof(binf->ba_list_si2bis));
2735 cur += sizeof(binf->ba_list_si2bis);
2736 }
2737
2738 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2739 memcpy(binf->ba_list_si2ter, cur,
2740 sizeof(binf->ba_list_si2ter));
2741 cur += sizeof(binf->ba_list_si2ter);
2742 }
2743
2744 return 0;
2745}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002746
2747void abis_nm_clear_queue(struct gsm_bts *bts)
2748{
2749 struct msgb *msg;
2750
2751 while (!llist_empty(&bts->abis_queue)) {
2752 msg = msgb_dequeue(&bts->abis_queue);
2753 msgb_free(msg);
2754 }
2755
2756 bts->abis_nm_pend = 0;
2757}