blob: 33a23a203f1d1667f0dfc9e3ee1bdb7520a1b903 [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
Maxa5e36932017-01-11 11:51:28 +010040#include <osmocom/gsm/protocol/gsm_12_21.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010041#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020042#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010043#include <osmocom/core/talloc.h>
Neels Hofmeyr93bafb62017-01-13 03:12:08 +010044#include <osmocom/core/utils.h>
Harald Welte8470bf22008-12-25 23:28:35 +000045#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000046#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000047#include <openbsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020048#include <osmocom/abis/e1_input.h>
Harald Welte52b1f982008-12-23 20:25:15 +000049
Harald Welte8470bf22008-12-25 23:28:35 +000050#define OM_ALLOC_SIZE 1024
51#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010052#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000053
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020054int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +000055{
Harald Welte39315c42010-01-10 18:01:52 +010056 if (!bts->model)
57 return -EIO;
58 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000059}
Harald Weltee0590df2009-02-15 03:34:15 +000060
Harald Welte52b1f982008-12-23 20:25:15 +000061static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
62{
63 int i;
64
65 for (i = 0; i < size; i++) {
66 if (arr[i] == mt)
67 return 1;
68 }
69
70 return 0;
71}
72
Holger Freytherca362a62009-01-04 21:05:01 +000073#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000074/* is this msgtype the usual ACK/NACK type ? */
75static int is_ack_nack(enum abis_nm_msgtype mt)
76{
77 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
78}
Holger Freytherca362a62009-01-04 21:05:01 +000079#endif
Harald Welte52b1f982008-12-23 20:25:15 +000080
81/* is this msgtype a report ? */
82static int is_report(enum abis_nm_msgtype mt)
83{
Harald Welte15c61722011-05-22 22:45:37 +020084 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000085}
86
87#define MT_ACK(x) (x+1)
88#define MT_NACK(x) (x+2)
89
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020090static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000091{
92 oh->mdisc = ABIS_OM_MDISC_FOM;
93 oh->placement = ABIS_OM_PLACEMENT_ONLY;
94 oh->sequence = 0;
95 oh->length = len;
96}
97
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +020098static struct abis_om_fom_hdr *fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020099 uint8_t msg_type, uint8_t obj_class,
100 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000101{
102 struct abis_om_fom_hdr *foh =
103 (struct abis_om_fom_hdr *) oh->data;
104
Harald Welte702d8702008-12-26 20:25:35 +0000105 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000106 foh->msg_type = msg_type;
107 foh->obj_class = obj_class;
108 foh->obj_inst.bts_nr = bts_nr;
109 foh->obj_inst.trx_nr = trx_nr;
110 foh->obj_inst.ts_nr = ts_nr;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200111 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000112}
113
Harald Welte8470bf22008-12-25 23:28:35 +0000114static struct msgb *nm_msgb_alloc(void)
115{
Harald Welte966636f2009-06-26 19:39:35 +0200116 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
117 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000118}
119
Harald Welte15eae8d2011-09-26 23:43:23 +0200120int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200121{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200122 msg->l2h = msg->data;
123
124 if (!msg->dst) {
125 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
126 return -EINVAL;
127 }
128
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200129 return abis_sendmsg(msg);
130}
131
Harald Welte52b1f982008-12-23 20:25:15 +0000132/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100133static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000134{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200135 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000136
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100137 /* queue OML messages */
138 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
139 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200140 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100141 } else {
142 msgb_enqueue(&bts->abis_queue, msg);
143 return 0;
144 }
145
146}
147
148int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
149{
150 OBSC_NM_W_ACK_CB(msg) = 1;
151 return abis_nm_queue_msg(bts, msg);
152}
153
154static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
155{
156 OBSC_NM_W_ACK_CB(msg) = 0;
157 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000158}
159
Harald Welte4724f992009-01-18 18:01:49 +0000160static int abis_nm_rcvmsg_sw(struct msgb *mb);
161
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100162int nm_is_running(struct gsm_nm_state *s) {
163 return (s->operational == NM_OPSTATE_ENABLED) && (
164 (s->availability == NM_AVSTATE_OK) ||
165 (s->availability == 0xff)
166 );
167}
168
Harald Weltee0590df2009-02-15 03:34:15 +0000169/* Update the administrative state of a given object in our in-memory data
170 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200171static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
172 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000173{
Harald Welteaeedeb42009-05-01 13:08:14 +0000174 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100175 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000176
Harald Welteaf9b8102011-03-06 21:20:38 +0100177 memset(&nsd, 0, sizeof(nsd));
178
Harald Welte978714d2011-06-06 18:31:20 +0200179 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100180 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100181 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200182 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000183 if (!nm_state)
184 return -1;
185
186 new_state = *nm_state;
187 new_state.administrative = adm_state;
188
Harald Weltef38ca9a2011-03-06 22:11:32 +0100189 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100190 nsd.obj_class = obj_class;
191 nsd.old_state = nm_state;
192 nsd.new_state = &new_state;
193 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200194 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000195
196 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000197
Harald Weltef338a032011-01-14 15:55:42 +0100198 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000199}
200
Harald Welte97ed1e72009-02-06 13:38:02 +0000201static int abis_nm_rx_statechg_rep(struct msgb *mb)
202{
Harald Weltee0590df2009-02-15 03:34:15 +0000203 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000204 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200205 struct e1inp_sign_link *sign_link = mb->dst;
206 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000207 struct tlv_parsed tp;
208 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000209
Harald Welte23897662009-05-01 14:52:51 +0000210 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000211
Harald Welte8b697c72009-06-05 19:18:45 +0000212 memset(&new_state, 0, sizeof(new_state));
213
Harald Welte978714d2011-06-06 18:31:20 +0200214 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000215 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100216 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000217 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000218 }
Harald Weltee0590df2009-02-15 03:34:15 +0000219
220 new_state = *nm_state;
221
Harald Welte39315c42010-01-10 18:01:52 +0100222 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000223 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
224 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200225 DEBUGPC(DNM, "OP_STATE=%s ",
226 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000227 }
228 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000229 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
230 new_state.availability = 0xff;
231 else
232 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200233 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
234 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000235 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100236 } else
237 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000238 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
239 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200240 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200241 get_value_string(abis_nm_adm_state_names,
242 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000243 }
244 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000245
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100246 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
247 new_state.operational != nm_state->operational ||
248 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000249 /* Update the operational state of a given object in our in-memory data
250 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100251 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200252 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100253 nsd.obj_class = foh->obj_class;
254 nsd.old_state = nm_state;
255 nsd.new_state = &new_state;
256 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100257 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200258 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100259 nm_state->operational = new_state.operational;
260 nm_state->availability = new_state.availability;
261 if (nm_state->administrative == 0)
262 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000263 }
264#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000265 if (op_state == 1) {
266 /* try to enable objects that are disabled */
267 abis_nm_opstart(bts, foh->obj_class,
268 foh->obj_inst.bts_nr,
269 foh->obj_inst.trx_nr,
270 foh->obj_inst.ts_nr);
271 }
Harald Weltee0590df2009-02-15 03:34:15 +0000272#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000273 return 0;
274}
275
Maxb1e6b372017-03-15 14:30:21 +0100276static inline void log_oml_fail_rep(const struct gsm_bts *bts, const char *type,
277 const char *severity, const uint8_t *p_val,
278 const char *text)
279{
280 enum abis_nm_pcause_type pcause = p_val[0];
281 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
282
283 LOGPC(DNM, LOGL_ERROR, "BTS %u: Failure Event Report: ", bts->nr);
284 if (type)
285 LOGPC(DNM, LOGL_ERROR, "Type=%s, ", type);
286 if (severity)
287 LOGPC(DNM, LOGL_ERROR, "Severity=%s, ", severity);
288
289 LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ",
290 get_value_string(abis_nm_pcause_type_names, pcause));
291
292 if (pcause == NM_PCAUSE_T_MANUF)
293 LOGPC(DNM, LOGL_ERROR, "%s, ",
294 get_value_string(abis_mm_event_cause_names, cause));
295 else
296 LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]);
297
298 if (text) {
299 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", text);
300 }
301
302 LOGPC(DNM, LOGL_ERROR, "\n");
303}
304
305static inline void handle_manufact_report(const struct gsm_bts *bts,
306 const uint8_t *p_val, const char *type,
307 const char *severity, const char *text)
308{
309 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
310
311 switch (cause) {
312 case OSMO_EVT_PCU_VERS:
313 if (text)
314 LOGPC(DNM, LOGL_NOTICE,
315 "BTS %u reported connected PCU version %s\n",
316 bts->nr, text);
317 else
318 LOGPC(DNM, LOGL_ERROR,
319 "BTS %u sent %s without actual version string.\n",
320 bts->nr,
321 get_value_string(abis_mm_event_cause_names,
322 cause));
323 break;
324 default:
325 log_oml_fail_rep(bts, type, severity, p_val, text);
326 };
327}
328
329static int rx_fail_evt_rep(struct msgb *mb, const struct gsm_bts *bts)
Harald Welte0db97b22009-05-01 17:22:47 +0000330{
331 struct abis_om_hdr *oh = msgb_l2(mb);
332 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200333 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000334 struct tlv_parsed tp;
Maxb1e6b372017-03-15 14:30:21 +0100335 int rc = 0;
336 const uint8_t *p_val = NULL;
337 char *p_text = NULL;
338 const char *e_type = NULL, *severity = NULL;
Harald Welte0db97b22009-05-01 17:22:47 +0000339
Maxb1e6b372017-03-15 14:30:21 +0100340 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data,
341 oh->length-sizeof(*foh));
Maxa5e36932017-01-11 11:51:28 +0100342
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100343 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
344 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
Maxb1e6b372017-03-15 14:30:21 +0100345 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val,
346 TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100347 }
Harald Welte0db97b22009-05-01 17:22:47 +0000348
Maxb1e6b372017-03-15 14:30:21 +0100349 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
350 e_type = abis_nm_event_type_name(*TLVP_VAL(&tp,
351 NM_ATT_EVENT_TYPE));
Harald Welte0db97b22009-05-01 17:22:47 +0000352
Maxb1e6b372017-03-15 14:30:21 +0100353 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
354 severity = abis_nm_severity_name(*TLVP_VAL(&tp,
355 NM_ATT_SEVERITY));
356
357 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
358 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
359
360 switch (p_val[0]) {
361 case NM_PCAUSE_T_MANUF:
362 handle_manufact_report(bts, p_val, e_type, severity,
363 p_text);
364 break;
365 default:
366 log_oml_fail_rep(bts, e_type, severity, p_val, p_text);
367 };
368 } else {
369 LOGPC(DNM, LOGL_ERROR, "BTS%u: Failure Event Report without "
370 "Probable Cause?!\n", bts->nr);
371 rc = -EINVAL;
372 }
373
374 if (p_text)
375 talloc_free(p_text);
376
377 return rc;
Harald Welte0db97b22009-05-01 17:22:47 +0000378}
379
Maxb1e6b372017-03-15 14:30:21 +0100380static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts)
Harald Welte97ed1e72009-02-06 13:38:02 +0000381{
382 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200383 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000384
Harald Welte15c61722011-05-22 22:45:37 +0200385 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000386
Harald Welte97ed1e72009-02-06 13:38:02 +0000387 //nmh->cfg->report_cb(mb, foh);
388
389 switch (mt) {
390 case NM_MT_STATECHG_EVENT_REP:
391 return abis_nm_rx_statechg_rep(mb);
392 break;
Harald Welte34a99682009-02-13 02:41:40 +0000393 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000394 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200395 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000396 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000397 case NM_MT_FAILURE_EVENT_REP:
Maxb1e6b372017-03-15 14:30:21 +0100398 rx_fail_evt_rep(mb, bts);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200399 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000400 break;
Harald Weltec7310382009-08-08 00:02:36 +0200401 case NM_MT_TEST_REP:
402 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200403 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200404 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000405 default:
Harald Welte23897662009-05-01 14:52:51 +0000406 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000407 break;
408
Harald Welte97ed1e72009-02-06 13:38:02 +0000409 };
410
Harald Welte97ed1e72009-02-06 13:38:02 +0000411 return 0;
412}
413
Harald Welte34a99682009-02-13 02:41:40 +0000414/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200415static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
416 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000417{
418 struct abis_om_hdr *oh;
419 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200420 uint8_t len = swdesc_len;
421 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000422
423 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
424 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
425
426 trailer = msgb_put(msg, swdesc_len);
427 memcpy(trailer, sw_desc, swdesc_len);
428
429 return abis_nm_sendmsg(bts, msg);
430}
431
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100432int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
433 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100434{
435 static const struct tlv_definition sw_descr_def = {
436 .def = {
437 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
438 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
439 },
440 };
441
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100442 size_t pos = 0;
443 int desc_pos = 0;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100444
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100445 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
446 uint8_t tag;
447 uint16_t tag_len;
448 const uint8_t *val;
449 int len;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100450
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100451 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
452 desc[desc_pos].start = &sw_descr[pos];
453
454 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
455 * nested nature and the fact you have to assume it contains only two sub
456 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
457 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
458 LOGP(DNM, LOGL_ERROR,
459 "SW_DESCR attribute identifier not found!\n");
460 return -1;
461 }
462
463 pos += 1;
464 len = tlv_parse_one(&tag, &tag_len, &val,
465 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
466 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
467 LOGP(DNM, LOGL_ERROR,
468 "FILE_ID attribute identifier not found!\n");
469 return -2;
470 }
471 desc[desc_pos].file_id = val;
472 desc[desc_pos].file_id_len = tag_len;
473 pos += len;
474
475
476 len = tlv_parse_one(&tag, &tag_len, &val,
477 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
478 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
479 LOGP(DNM, LOGL_ERROR,
480 "FILE_VERSION attribute identifier not found!\n");
481 return -3;
482 }
483 desc[desc_pos].file_ver = val;
484 desc[desc_pos].file_ver_len = tag_len;
485 pos += len;
486
487 /* final size */
488 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100489 }
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100490
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100491 return desc_pos;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100492}
493
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100494int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
495 const size_t size)
496{
497 int res = 0;
498 int i;
499
500 for (i = 1; i < size; ++i) {
501 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
502 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
503 res = i;
504 }
505 }
506
507 return res;
508}
509
Harald Welte34a99682009-02-13 02:41:40 +0000510static int abis_nm_rx_sw_act_req(struct msgb *mb)
511{
512 struct abis_om_hdr *oh = msgb_l2(mb);
513 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200514 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200515 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200516 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100517 int ret, sw_config_len, len;
518 struct abis_nm_sw_descr sw_descr[5];
Harald Welte34a99682009-02-13 02:41:40 +0000519
Harald Welte15c61722011-05-22 22:45:37 +0200520 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200521
522 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000523
Harald Welte97a282b2010-03-14 15:37:43 +0800524 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000525
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200526 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000527 foh->obj_inst.bts_nr,
528 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800529 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000530 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100531 if (ret != 0) {
532 LOGP(DNM, LOGL_ERROR,
533 "Sending SW ActReq ACK failed: %d\n", ret);
534 return ret;
535 }
Harald Welte34a99682009-02-13 02:41:40 +0000536
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200537 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200538 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
539 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
540 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100541 LOGP(DNM, LOGL_ERROR,
542 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200543 return -EINVAL;
544 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200545 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200546 }
547
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100548 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100549 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100550 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100551 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100552 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100553 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100554 }
Mike Habena03f9772009-10-01 14:56:13 +0200555
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100556 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
557 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
558
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200559 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000560 foh->obj_inst.bts_nr,
561 foh->obj_inst.trx_nr,
562 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100563 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte34a99682009-02-13 02:41:40 +0000564}
565
Harald Weltee0590df2009-02-15 03:34:15 +0000566/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
567static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
568{
569 struct abis_om_hdr *oh = msgb_l2(mb);
570 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200571 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000572 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200573 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000574
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200575 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000576 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
577 return -EINVAL;
578
579 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
580
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200581 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000582}
583
Harald Welteee670472009-02-22 21:58:49 +0000584static int abis_nm_rx_lmt_event(struct msgb *mb)
585{
586 struct abis_om_hdr *oh = msgb_l2(mb);
587 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200588 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000589 struct tlv_parsed tp;
590
591 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200592 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000593 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
594 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200595 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000596 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
597 }
598 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
599 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200600 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000601 DEBUGPC(DNM, "Level=%u ", level);
602 }
603 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
604 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
605 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
606 DEBUGPC(DNM, "Username=%s ", name);
607 }
608 DEBUGPC(DNM, "\n");
609 /* FIXME: parse LMT LOGON TIME */
610 return 0;
611}
612
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200613void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100614{
615 int wait = 0;
616 struct msgb *msg;
617 /* the queue is empty */
618 while (!llist_empty(&bts->abis_queue)) {
619 msg = msgb_dequeue(&bts->abis_queue);
620 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200621 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100622
623 if (wait)
624 break;
625 }
626
627 bts->abis_nm_pend = wait;
628}
629
Harald Welte52b1f982008-12-23 20:25:15 +0000630/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000631static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000632{
Harald Welte6c96ba52009-05-01 13:03:40 +0000633 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000634 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200635 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200636 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100637 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
638 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100639 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000640
641 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000642 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100643 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000644
Harald Welte15c61722011-05-22 22:45:37 +0200645 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000646 return abis_nm_rcvmsg_sw(mb);
647
Harald Welte15c61722011-05-22 22:45:37 +0200648 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800649 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000650 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200651
Harald Welte15c61722011-05-22 22:45:37 +0200652 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200653
Harald Welte15c61722011-05-22 22:45:37 +0200654 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000655
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100656 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000657 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200658 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200659 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000660 else
661 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200662
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800663 nack_data.msg = mb;
664 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100665 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200666 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100667 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200668 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000669 }
Harald Weltead384642008-12-26 10:20:07 +0000670#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000671 /* check if last message is to be acked */
672 if (is_ack_nack(nmh->last_msgtype)) {
673 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100674 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000675 /* we got our ACK, continue sending the next msg */
676 } else if (mt == MT_NACK(nmh->last_msgtype)) {
677 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100678 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000679 /* FIXME: somehow signal this to the caller */
680 } else {
681 /* really strange things happen */
682 return -EINVAL;
683 }
684 }
Harald Weltead384642008-12-26 10:20:07 +0000685#endif
686
Harald Welte97ed1e72009-02-06 13:38:02 +0000687 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000688 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100689 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000690 break;
Harald Welte34a99682009-02-13 02:41:40 +0000691 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100692 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000693 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000694 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100695 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000696 break;
Harald Welte1989c082009-08-06 17:58:31 +0200697 case NM_MT_CONN_MDROP_LINK_ACK:
698 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
699 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100700 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200701 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100702 break;
703 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200704 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100705 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100706 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100707 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000708 }
709
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100710 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100711 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000712}
713
Harald Welte677c21f2009-02-17 13:22:23 +0000714static int abis_nm_rx_ipacc(struct msgb *mb);
715
716static int abis_nm_rcvmsg_manuf(struct msgb *mb)
717{
718 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200719 struct e1inp_sign_link *sign_link = mb->dst;
720 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000721
722 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100723 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200724 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000725 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200726 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000727 break;
728 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100729 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
730 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000731 rc = 0;
732 break;
733 }
734
735 return rc;
736}
737
Harald Welte52b1f982008-12-23 20:25:15 +0000738/* High-Level API */
739/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000740int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000741{
Harald Welte52b1f982008-12-23 20:25:15 +0000742 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000743 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000744
745 /* Various consistency checks */
746 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100747 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000748 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200749 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
750 rc = -EINVAL;
751 goto err;
752 }
Harald Welte52b1f982008-12-23 20:25:15 +0000753 }
754 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100755 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000756 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200757 rc = -EINVAL;
758 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000759 }
Harald Welte702d8702008-12-26 20:25:35 +0000760#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200761 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000762 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000763 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100764 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000765 oh->length + sizeof(*oh), l2_len);
766 return -EINVAL;
767 }
Harald Welte702d8702008-12-26 20:25:35 +0000768 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100769 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 +0000770#endif
Harald Weltead384642008-12-26 10:20:07 +0000771 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000772
773 switch (oh->mdisc) {
774 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000775 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000776 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000777 case ABIS_OM_MDISC_MANUF:
778 rc = abis_nm_rcvmsg_manuf(msg);
779 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000780 case ABIS_OM_MDISC_MMI:
781 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100782 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000783 oh->mdisc);
784 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000785 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100786 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000787 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200788 rc = -EINVAL;
789 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000790 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200791err:
Harald Weltead384642008-12-26 10:20:07 +0000792 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000793 return rc;
794}
795
796#if 0
797/* initialized all resources */
798struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
799{
800 struct abis_nm_h *nmh;
801
802 nmh = malloc(sizeof(*nmh));
803 if (!nmh)
804 return NULL;
805
806 nmh->cfg = cfg;
807
808 return nmh;
809}
810
811/* free all resources */
812void abis_nm_fini(struct abis_nm_h *nmh)
813{
814 free(nmh);
815}
816#endif
817
818/* Here we are trying to define a high-level API that can be used by
819 * the actual BSC implementation. However, the architecture is currently
820 * still under design. Ideally the calls to this API would be synchronous,
821 * while the underlying stack behind the APi runs in a traditional select
822 * based state machine.
823 */
824
Harald Welte4724f992009-01-18 18:01:49 +0000825/* 6.2 Software Load: */
826enum sw_state {
827 SW_STATE_NONE,
828 SW_STATE_WAIT_INITACK,
829 SW_STATE_WAIT_SEGACK,
830 SW_STATE_WAIT_ENDACK,
831 SW_STATE_WAIT_ACTACK,
832 SW_STATE_ERROR,
833};
Harald Welte52b1f982008-12-23 20:25:15 +0000834
Harald Welte52b1f982008-12-23 20:25:15 +0000835struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000836 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800837 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000838 gsm_cbfn *cbfn;
839 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000840 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000841
Harald Welte52b1f982008-12-23 20:25:15 +0000842 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200843 uint8_t obj_class;
844 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000845
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200846 uint8_t file_id[255];
847 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000848
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200849 uint8_t file_version[255];
850 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000851
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200852 uint8_t window_size;
853 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000854
855 int fd;
856 FILE *stream;
857 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000858 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000859};
860
Harald Welte4724f992009-01-18 18:01:49 +0000861static struct abis_nm_sw g_sw;
862
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100863static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
864{
865 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
866 msgb_v_put(msg, NM_ATT_SW_DESCR);
867 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
868 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
869 sw->file_version);
870 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
871 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
872 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
873 sw->file_version);
874 } else {
875 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
876 }
877}
878
Harald Welte4724f992009-01-18 18:01:49 +0000879/* 6.2.1 / 8.3.1: Load Data Initiate */
880static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000881{
Harald Welte4724f992009-01-18 18:01:49 +0000882 struct abis_om_hdr *oh;
883 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200884 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000885
886 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
887 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
888 sw->obj_instance[0], sw->obj_instance[1],
889 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100890
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100891 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000892 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
893
894 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000895}
896
Harald Welte1602ade2009-01-29 21:12:39 +0000897static int is_last_line(FILE *stream)
898{
899 char next_seg_buf[256];
900 long pos;
901
902 /* check if we're sending the last line */
903 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200904
905 /* Did ftell fail? Then we are at the end for sure */
906 if (pos < 0)
907 return 1;
908
Harald Welte1602ade2009-01-29 21:12:39 +0000909 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +0100910 int rc = fseek(stream, pos, SEEK_SET);
911 if (rc < 0)
912 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000913 return 1;
914 }
915
916 fseek(stream, pos, SEEK_SET);
917 return 0;
918}
919
Harald Welte4724f992009-01-18 18:01:49 +0000920/* 6.2.2 / 8.3.2 Load Data Segment */
921static int sw_load_segment(struct abis_nm_sw *sw)
922{
923 struct abis_om_hdr *oh;
924 struct msgb *msg = nm_msgb_alloc();
925 char seg_buf[256];
926 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000927 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200928 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000929
930 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000931
932 switch (sw->bts->type) {
933 case GSM_BTS_TYPE_BS11:
934 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
935 perror("fgets reading segment");
936 return -EINVAL;
937 }
938 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000939
940 /* check if we're sending the last line */
941 sw->last_seg = is_last_line(sw->stream);
942 if (sw->last_seg)
943 seg_buf[1] = 0;
944 else
945 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000946
947 len = strlen(line_buf) + 2;
948 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200949 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000950 /* BS11 wants CR + LF in excess of the TLV length !?! */
951 tlv[1] -= 2;
952
953 /* we only now know the exact length for the OM hdr */
954 len = strlen(line_buf)+2;
955 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100956 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200957 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100958 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
959 if (len < 0) {
960 perror("read failed");
961 return -EINVAL;
962 }
963
964 if (len != IPACC_SEGMENT_SIZE)
965 sw->last_seg = 1;
966
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100967 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200968 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100969 len += 3;
970 break;
971 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000972 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100973 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000974 /* FIXME: Other BTS types */
975 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000976 }
Harald Welte4724f992009-01-18 18:01:49 +0000977
Harald Welte4724f992009-01-18 18:01:49 +0000978 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
979 sw->obj_instance[0], sw->obj_instance[1],
980 sw->obj_instance[2]);
981
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100982 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000983}
984
985/* 6.2.4 / 8.3.4 Load Data End */
986static int sw_load_end(struct abis_nm_sw *sw)
987{
988 struct abis_om_hdr *oh;
989 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200990 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000991
992 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
993 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
994 sw->obj_instance[0], sw->obj_instance[1],
995 sw->obj_instance[2]);
996
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100997 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000998 return abis_nm_sendmsg(sw->bts, msg);
999}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001000
Harald Welte52b1f982008-12-23 20:25:15 +00001001/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001002static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001003{
Harald Welte4724f992009-01-18 18:01:49 +00001004 struct abis_om_hdr *oh;
1005 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001006 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001007
Harald Welte4724f992009-01-18 18:01:49 +00001008 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1009 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1010 sw->obj_instance[0], sw->obj_instance[1],
1011 sw->obj_instance[2]);
1012
1013 /* FIXME: this is BS11 specific format */
1014 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1015 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1016 sw->file_version);
1017
1018 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001019}
Harald Welte4724f992009-01-18 18:01:49 +00001020
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001021struct sdp_firmware {
1022 char magic[4];
1023 char more_magic[4];
1024 unsigned int header_length;
1025 unsigned int file_length;
1026} __attribute__ ((packed));
1027
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001028static int parse_sdp_header(struct abis_nm_sw *sw)
1029{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001030 struct sdp_firmware firmware_header;
1031 int rc;
1032 struct stat stat;
1033
1034 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1035 if (rc != sizeof(firmware_header)) {
1036 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1037 return -1;
1038 }
1039
1040 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1041 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1042 return -1;
1043 }
1044
1045 if (firmware_header.more_magic[0] != 0x10 ||
1046 firmware_header.more_magic[1] != 0x02 ||
1047 firmware_header.more_magic[2] != 0x00 ||
1048 firmware_header.more_magic[3] != 0x00) {
1049 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1050 return -1;
1051 }
1052
1053
1054 if (fstat(sw->fd, &stat) == -1) {
1055 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1056 return -1;
1057 }
1058
1059 if (ntohl(firmware_header.file_length) != stat.st_size) {
1060 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1061 return -1;
1062 }
1063
1064 /* go back to the start as we checked the whole filesize.. */
1065 lseek(sw->fd, 0l, SEEK_SET);
1066 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1067 "There might be checksums in the file that are not\n"
1068 "verified and incomplete firmware might be flashed.\n"
1069 "There is absolutely no WARRANTY that flashing will\n"
1070 "work.\n");
1071 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001072}
1073
Harald Welte4724f992009-01-18 18:01:49 +00001074static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1075{
1076 char file_id[12+1];
1077 char file_version[80+1];
1078 int rc;
1079
1080 sw->fd = open(fname, O_RDONLY);
1081 if (sw->fd < 0)
1082 return sw->fd;
1083
1084 switch (sw->bts->type) {
1085 case GSM_BTS_TYPE_BS11:
1086 sw->stream = fdopen(sw->fd, "r");
1087 if (!sw->stream) {
1088 perror("fdopen");
1089 return -1;
1090 }
1091 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001092 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001093 file_id, file_version);
1094 if (rc != 2) {
1095 perror("parsing header line of software file");
1096 return -1;
1097 }
1098 strcpy((char *)sw->file_id, file_id);
1099 sw->file_id_len = strlen(file_id);
1100 strcpy((char *)sw->file_version, file_version);
1101 sw->file_version_len = strlen(file_version);
1102 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001103 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001104 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001105 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001106 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001107 rc = parse_sdp_header(sw);
1108 if (rc < 0) {
1109 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1110 return -1;
1111 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001112
1113 strcpy((char *)sw->file_id, "id");
1114 sw->file_id_len = 3;
1115 strcpy((char *)sw->file_version, "version");
1116 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001117 break;
Harald Welte4724f992009-01-18 18:01:49 +00001118 default:
1119 /* We don't know how to treat them yet */
1120 close(sw->fd);
1121 return -EINVAL;
1122 }
1123
1124 return 0;
1125}
1126
1127static void sw_close_file(struct abis_nm_sw *sw)
1128{
1129 switch (sw->bts->type) {
1130 case GSM_BTS_TYPE_BS11:
1131 fclose(sw->stream);
1132 break;
1133 default:
1134 close(sw->fd);
1135 break;
1136 }
1137}
1138
1139/* Fill the window */
1140static int sw_fill_window(struct abis_nm_sw *sw)
1141{
1142 int rc;
1143
1144 while (sw->seg_in_window < sw->window_size) {
1145 rc = sw_load_segment(sw);
1146 if (rc < 0)
1147 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001148 if (sw->last_seg)
1149 break;
Harald Welte4724f992009-01-18 18:01:49 +00001150 }
1151 return 0;
1152}
1153
1154/* callback function from abis_nm_rcvmsg() handler */
1155static int abis_nm_rcvmsg_sw(struct msgb *mb)
1156{
1157 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001158 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001159 int rc = -1;
1160 struct abis_nm_sw *sw = &g_sw;
1161 enum sw_state old_state = sw->state;
1162
Harald Welte3ffd1372009-02-01 22:15:49 +00001163 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001164
1165 switch (sw->state) {
1166 case SW_STATE_WAIT_INITACK:
1167 switch (foh->msg_type) {
1168 case NM_MT_LOAD_INIT_ACK:
1169 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001170 if (sw->cbfn)
1171 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1172 NM_MT_LOAD_INIT_ACK, mb,
1173 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001174 rc = sw_fill_window(sw);
1175 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001176 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001177 break;
1178 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001179 if (sw->forced) {
1180 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1181 "Init NACK\n");
1182 if (sw->cbfn)
1183 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1184 NM_MT_LOAD_INIT_ACK, mb,
1185 sw->cb_data, NULL);
1186 rc = sw_fill_window(sw);
1187 sw->state = SW_STATE_WAIT_SEGACK;
1188 } else {
1189 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001190 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001191 if (sw->cbfn)
1192 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1193 NM_MT_LOAD_INIT_NACK, mb,
1194 sw->cb_data, NULL);
1195 sw->state = SW_STATE_ERROR;
1196 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001197 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001198 break;
1199 }
1200 break;
1201 case SW_STATE_WAIT_SEGACK:
1202 switch (foh->msg_type) {
1203 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001204 if (sw->cbfn)
1205 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1206 NM_MT_LOAD_SEG_ACK, mb,
1207 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001208 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001209 if (!sw->last_seg) {
1210 /* fill window with more segments */
1211 rc = sw_fill_window(sw);
1212 sw->state = SW_STATE_WAIT_SEGACK;
1213 } else {
1214 /* end the transfer */
1215 sw->state = SW_STATE_WAIT_ENDACK;
1216 rc = sw_load_end(sw);
1217 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001218 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001219 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001220 case NM_MT_LOAD_ABORT:
1221 if (sw->cbfn)
1222 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1223 NM_MT_LOAD_ABORT, mb,
1224 sw->cb_data, NULL);
1225 break;
Harald Welte4724f992009-01-18 18:01:49 +00001226 }
1227 break;
1228 case SW_STATE_WAIT_ENDACK:
1229 switch (foh->msg_type) {
1230 case NM_MT_LOAD_END_ACK:
1231 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001232 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1233 sw->bts->nr);
1234 sw->state = SW_STATE_NONE;
1235 if (sw->cbfn)
1236 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1237 NM_MT_LOAD_END_ACK, mb,
1238 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001239 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001240 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001241 break;
1242 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001243 if (sw->forced) {
1244 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1245 "End NACK\n");
1246 sw->state = SW_STATE_NONE;
1247 if (sw->cbfn)
1248 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1249 NM_MT_LOAD_END_ACK, mb,
1250 sw->cb_data, NULL);
1251 } else {
1252 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001253 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001254 sw->state = SW_STATE_ERROR;
1255 if (sw->cbfn)
1256 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1257 NM_MT_LOAD_END_NACK, mb,
1258 sw->cb_data, NULL);
1259 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001260 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001261 break;
1262 }
1263 case SW_STATE_WAIT_ACTACK:
1264 switch (foh->msg_type) {
1265 case NM_MT_ACTIVATE_SW_ACK:
1266 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001267 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001268 sw->state = SW_STATE_NONE;
1269 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001270 if (sw->cbfn)
1271 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1272 NM_MT_ACTIVATE_SW_ACK, mb,
1273 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001274 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001275 break;
1276 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001277 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001278 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001279 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001280 if (sw->cbfn)
1281 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1282 NM_MT_ACTIVATE_SW_NACK, mb,
1283 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001284 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001285 break;
1286 }
1287 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001288 switch (foh->msg_type) {
1289 case NM_MT_ACTIVATE_SW_ACK:
1290 rc = 0;
1291 break;
1292 }
1293 break;
Harald Welte4724f992009-01-18 18:01:49 +00001294 case SW_STATE_ERROR:
1295 break;
1296 }
1297
1298 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001299 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001300 foh->msg_type, old_state, sw->state);
1301
1302 return rc;
1303}
1304
1305/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001306int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001307 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001308 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001309{
1310 struct abis_nm_sw *sw = &g_sw;
1311 int rc;
1312
Harald Welte5e4d1b32009-02-01 13:36:56 +00001313 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1314 bts->nr, fname);
1315
Harald Welte4724f992009-01-18 18:01:49 +00001316 if (sw->state != SW_STATE_NONE)
1317 return -EBUSY;
1318
1319 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001320 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001321
1322 switch (bts->type) {
1323 case GSM_BTS_TYPE_BS11:
1324 sw->obj_class = NM_OC_SITE_MANAGER;
1325 sw->obj_instance[0] = 0xff;
1326 sw->obj_instance[1] = 0xff;
1327 sw->obj_instance[2] = 0xff;
1328 break;
1329 case GSM_BTS_TYPE_NANOBTS:
1330 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001331 sw->obj_instance[0] = sw->bts->nr;
1332 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001333 sw->obj_instance[2] = 0xff;
1334 break;
1335 case GSM_BTS_TYPE_UNKNOWN:
1336 default:
1337 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1338 return -1;
1339 break;
1340 }
Harald Welte4724f992009-01-18 18:01:49 +00001341 sw->window_size = win_size;
1342 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001343 sw->cbfn = cbfn;
1344 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001345 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001346
1347 rc = sw_open_file(sw, fname);
1348 if (rc < 0) {
1349 sw->state = SW_STATE_NONE;
1350 return rc;
1351 }
1352
1353 return sw_load_init(sw);
1354}
Harald Welte52b1f982008-12-23 20:25:15 +00001355
Harald Welte1602ade2009-01-29 21:12:39 +00001356int abis_nm_software_load_status(struct gsm_bts *bts)
1357{
1358 struct abis_nm_sw *sw = &g_sw;
1359 struct stat st;
1360 int rc, percent;
1361
1362 rc = fstat(sw->fd, &st);
1363 if (rc < 0) {
1364 perror("ERROR during stat");
1365 return rc;
1366 }
1367
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001368 if (sw->stream)
1369 percent = (ftell(sw->stream) * 100) / st.st_size;
1370 else
1371 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001372 return percent;
1373}
1374
Harald Welte5e4d1b32009-02-01 13:36:56 +00001375/* Activate the specified software into the BTS */
1376int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1377 gsm_cbfn *cbfn, void *cb_data)
1378{
1379 struct abis_nm_sw *sw = &g_sw;
1380 int rc;
1381
1382 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1383 bts->nr, fname);
1384
1385 if (sw->state != SW_STATE_NONE)
1386 return -EBUSY;
1387
1388 sw->bts = bts;
1389 sw->obj_class = NM_OC_SITE_MANAGER;
1390 sw->obj_instance[0] = 0xff;
1391 sw->obj_instance[1] = 0xff;
1392 sw->obj_instance[2] = 0xff;
1393 sw->state = SW_STATE_WAIT_ACTACK;
1394 sw->cbfn = cbfn;
1395 sw->cb_data = cb_data;
1396
1397 /* Open the file in order to fill some sw struct members */
1398 rc = sw_open_file(sw, fname);
1399 if (rc < 0) {
1400 sw->state = SW_STATE_NONE;
1401 return rc;
1402 }
1403 sw_close_file(sw);
1404
1405 return sw_activate(sw);
1406}
1407
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001408static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1409 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001410{
Harald Welteadaf08b2009-01-18 11:08:10 +00001411 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001412 ch->bts_port = bts_port;
1413 ch->timeslot = ts_nr;
1414 ch->subslot = subslot_nr;
1415}
1416
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001417int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1418 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1419 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001420{
1421 struct abis_om_hdr *oh;
1422 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001423 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001424 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001425
1426 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1427 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1428 bts->bts_nr, trx_nr, 0xff);
1429
Harald Welte8470bf22008-12-25 23:28:35 +00001430 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001431
1432 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1433 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1434
1435 return abis_nm_sendmsg(bts, msg);
1436}
1437
1438/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1439int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001440 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001441{
Harald Welte8470bf22008-12-25 23:28:35 +00001442 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001443 struct abis_om_hdr *oh;
1444 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001445 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001446
1447 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001448 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001449 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1450
1451 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1452 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1453
1454 return abis_nm_sendmsg(bts, msg);
1455}
1456
1457#if 0
1458int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1459 struct abis_nm_abis_channel *chan)
1460{
1461}
1462#endif
1463
1464int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001465 uint8_t e1_port, uint8_t e1_timeslot,
1466 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001467{
1468 struct gsm_bts *bts = ts->trx->bts;
1469 struct abis_om_hdr *oh;
1470 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001471 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001472
1473 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1474 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001475 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001476
1477 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1478 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1479
Harald Weltef325eb42009-02-19 17:07:39 +00001480 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1481 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001482 e1_port, e1_timeslot, e1_subslot);
1483
Harald Welte52b1f982008-12-23 20:25:15 +00001484 return abis_nm_sendmsg(bts, msg);
1485}
1486
1487#if 0
1488int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1489 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001490 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001491{
1492}
1493#endif
1494
Harald Weltefe568f22012-08-14 19:15:57 +02001495/* Chapter 8.11.1 */
1496int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1497 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1498 uint8_t *attr, uint8_t attr_len)
1499{
1500 struct abis_om_hdr *oh;
1501 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001502
1503 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1504
1505 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1506 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1507 bts_nr, trx_nr, ts_nr);
1508 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1509
1510 return abis_nm_sendmsg(bts, msg);
1511}
1512
Harald Welte22af0db2009-02-14 15:41:08 +00001513/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001514int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001515{
1516 struct abis_om_hdr *oh;
1517 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001518 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001519
1520 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1521
1522 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001523 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 +00001524 cur = msgb_put(msg, attr_len);
1525 memcpy(cur, attr, attr_len);
1526
1527 return abis_nm_sendmsg(bts, msg);
1528}
1529
1530/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001531int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001532{
1533 struct abis_om_hdr *oh;
1534 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001535 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001536
1537 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1538
1539 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1540 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001541 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001542 cur = msgb_put(msg, attr_len);
1543 memcpy(cur, attr, attr_len);
1544
1545 return abis_nm_sendmsg(trx->bts, msg);
1546}
1547
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001548int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1549{
1550 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1551 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1552}
1553
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001554static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1555 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001556{
1557 int i;
1558
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001559 *reason = "Reason unknown";
1560
Harald Welte39c7deb2009-08-09 21:49:48 +02001561 /* As it turns out, the BS-11 has some very peculiar restrictions
1562 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301563 switch (ts->trx->bts->type) {
1564 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001565 switch (chan_comb) {
1566 case NM_CHANC_TCHHalf:
1567 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001568 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001569 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001570 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001571 return -EINVAL;
1572 case NM_CHANC_SDCCH:
1573 /* only one SDCCH/8 per TRX */
1574 for (i = 0; i < TRX_NR_TS; i++) {
1575 if (i == ts->nr)
1576 continue;
1577 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001578 NM_CHANC_SDCCH) {
1579 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001580 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001581 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001582 }
1583 /* not allowed for TS0 of BCCH-TRX */
1584 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001585 ts->nr == 0) {
1586 *reason = "SDCCH/8 must be on TS0.";
1587 return -EINVAL;
1588 }
1589
Harald Welte39c7deb2009-08-09 21:49:48 +02001590 /* not on the same TRX that has a BCCH+SDCCH4
1591 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001592 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001593 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001594 ts->trx->ts[0].nm_chan_comb == 8)) {
1595 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1596 return -EINVAL;
1597 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001598 break;
1599 case NM_CHANC_mainBCCH:
1600 case NM_CHANC_BCCHComb:
1601 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001602 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1603 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001604 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001605 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001606 break;
1607 case NM_CHANC_BCCH:
1608 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001609 if (ts->trx != ts->trx->bts->c0) {
1610 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001611 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001612 }
1613 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1614 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001615 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001616 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001617 break;
1618 case 8: /* this is not like 08.58, but in fact
1619 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1620 /* FIXME: only one CBCH allowed per cell */
1621 break;
1622 }
Harald Welted6575f92009-12-02 02:45:23 +05301623 break;
1624 case GSM_BTS_TYPE_NANOBTS:
1625 switch (ts->nr) {
1626 case 0:
1627 if (ts->trx->nr == 0) {
1628 /* only on TRX0 */
1629 switch (chan_comb) {
1630 case NM_CHANC_BCCH:
1631 case NM_CHANC_mainBCCH:
1632 case NM_CHANC_BCCHComb:
1633 return 0;
1634 break;
1635 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001636 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301637 return -EINVAL;
1638 }
1639 } else {
1640 switch (chan_comb) {
1641 case NM_CHANC_TCHFull:
1642 case NM_CHANC_TCHHalf:
1643 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1644 return 0;
1645 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001646 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301647 return -EINVAL;
1648 }
1649 }
1650 break;
1651 case 1:
1652 if (ts->trx->nr == 0) {
1653 switch (chan_comb) {
1654 case NM_CHANC_SDCCH_CBCH:
1655 if (ts->trx->ts[0].nm_chan_comb ==
1656 NM_CHANC_mainBCCH)
1657 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001658 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301659 return -EINVAL;
1660 case NM_CHANC_SDCCH:
1661 case NM_CHANC_TCHFull:
1662 case NM_CHANC_TCHHalf:
1663 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1664 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001665 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301666 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001667 default:
1668 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1669 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301670 }
1671 } else {
1672 switch (chan_comb) {
1673 case NM_CHANC_SDCCH:
1674 case NM_CHANC_TCHFull:
1675 case NM_CHANC_TCHHalf:
1676 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1677 return 0;
1678 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001679 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301680 return -EINVAL;
1681 }
1682 }
1683 break;
1684 case 2:
1685 case 3:
1686 case 4:
1687 case 5:
1688 case 6:
1689 case 7:
1690 switch (chan_comb) {
1691 case NM_CHANC_TCHFull:
1692 case NM_CHANC_TCHHalf:
1693 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1694 return 0;
1695 case NM_CHANC_IPAC_PDCH:
1696 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001697 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301698 if (ts->trx->nr == 0)
1699 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001700 else {
1701 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301702 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001703 }
Harald Welted6575f92009-12-02 02:45:23 +05301704 }
1705 break;
1706 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001707 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301708 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001709 case GSM_BTS_TYPE_OSMO_SYSMO:
1710 /* no known restrictions */
1711 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301712 default:
1713 /* unknown BTS type */
1714 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001715 }
1716 return 0;
1717}
1718
Harald Welte22af0db2009-02-14 15:41:08 +00001719/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001720int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001721{
1722 struct gsm_bts *bts = ts->trx->bts;
1723 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001724 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001725 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001726 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001727 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001728
1729 if (bts->type == GSM_BTS_TYPE_BS11)
1730 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001731
Harald Weltef325eb42009-02-19 17:07:39 +00001732 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001733 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001734 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001735 LOGP(DNM, LOGL_ERROR,
1736 "Invalid Channel Combination %d on %s. Reason: %s\n",
1737 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001738 return -EINVAL;
1739 }
1740 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001741
Harald Welte52b1f982008-12-23 20:25:15 +00001742 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001743 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001744 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001745 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001746 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001747 if (ts->hopping.enabled) {
1748 unsigned int i;
1749 uint8_t *len;
1750
Harald Welte6e0cd042009-09-12 13:05:33 +02001751 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1752 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001753
1754 /* build the ARFCN list */
1755 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1756 len = msgb_put(msg, 1);
1757 *len = 0;
1758 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1759 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1760 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001761 /* At least BS-11 wants a TLV16 here */
1762 if (bts->type == GSM_BTS_TYPE_BS11)
1763 *len += 1;
1764 else
1765 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001766 }
1767 }
Harald Weltee0590df2009-02-15 03:34:15 +00001768 }
Harald Welte1fe24122014-01-19 17:18:21 +01001769 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001770 if (bts->type == GSM_BTS_TYPE_BS11)
1771 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001772
1773 return abis_nm_sendmsg(bts, msg);
1774}
1775
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001776int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1777 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001778{
1779 struct abis_om_hdr *oh;
1780 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001781 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1782 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001783
1784 if (nack) {
1785 len += 2;
1786 msgtype = NM_MT_SW_ACT_REQ_NACK;
1787 }
Harald Welte34a99682009-02-13 02:41:40 +00001788
1789 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001790 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1791
Harald Welte34a99682009-02-13 02:41:40 +00001792 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001793 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001794 memcpy(ptr, attr, att_len);
1795 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001796 if (nack)
1797 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001798
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001799 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001800}
1801
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001802int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001803{
Harald Welte8470bf22008-12-25 23:28:35 +00001804 struct msgb *msg = nm_msgb_alloc();
1805 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001806 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001807
1808 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1809 fill_om_hdr(oh, len);
1810 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001811 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001812
1813 return abis_nm_sendmsg(bts, msg);
1814}
1815
1816/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001817static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001818{
1819 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001820 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001821
1822 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001823 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001824 0xff, 0xff, 0xff);
1825
1826 return abis_nm_sendmsg(bts, msg);
1827}
1828
Harald Welte34a99682009-02-13 02:41:40 +00001829/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001830int 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 +00001831{
1832 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001833 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001834 struct msgb *msg = nm_msgb_alloc();
1835
1836 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001837 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001838
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001839 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001840 DEBUGPC(DNM, "Sending OPSTART\n");
1841
Harald Welte34a99682009-02-13 02:41:40 +00001842 return abis_nm_sendmsg(bts, msg);
1843}
1844
1845/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001846int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1847 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001848{
1849 struct abis_om_hdr *oh;
1850 struct msgb *msg = nm_msgb_alloc();
1851
1852 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1853 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1854 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1855
1856 return abis_nm_sendmsg(bts, msg);
1857}
1858
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001859int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1860 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001861{
1862 struct abis_om_hdr *oh;
1863 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001864 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001865
1866 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1867 e1_port0, ts0, e1_port1, ts1);
1868
1869 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1870 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1871 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1872
1873 attr = msgb_put(msg, 3);
1874 attr[0] = NM_ATT_MDROP_LINK;
1875 attr[1] = e1_port0;
1876 attr[2] = ts0;
1877
1878 attr = msgb_put(msg, 3);
1879 attr[0] = NM_ATT_MDROP_NEXT;
1880 attr[1] = e1_port1;
1881 attr[2] = ts1;
1882
1883 return abis_nm_sendmsg(bts, msg);
1884}
Harald Welte34a99682009-02-13 02:41:40 +00001885
Harald Weltec7310382009-08-08 00:02:36 +02001886/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001887int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1888 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1889 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001890{
1891 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001892
Harald Welte15c61722011-05-22 22:45:37 +02001893 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001894
1895 if (!msg)
1896 msg = nm_msgb_alloc();
1897
1898 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1899 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1900 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1901 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001902 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001903
1904 return abis_nm_sendmsg(bts, msg);
1905}
1906
Harald Welte52b1f982008-12-23 20:25:15 +00001907int abis_nm_event_reports(struct gsm_bts *bts, int on)
1908{
1909 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001910 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001911 else
Harald Welte227d4072009-01-03 08:16:25 +00001912 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001913}
1914
Harald Welte47d88ae2009-01-04 12:02:08 +00001915/* Siemens (or BS-11) specific commands */
1916
Harald Welte3ffd1372009-02-01 22:15:49 +00001917int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1918{
1919 if (reconnect == 0)
1920 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1921 else
1922 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1923}
1924
Harald Welteb8427972009-02-05 19:27:17 +00001925int abis_nm_bs11_restart(struct gsm_bts *bts)
1926{
1927 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1928}
1929
1930
Harald Welte268bb402009-02-01 19:11:56 +00001931struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001932 uint16_t year;
1933 uint8_t month;
1934 uint8_t day;
1935 uint8_t hour;
1936 uint8_t min;
1937 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001938} __attribute__((packed));
1939
1940
1941void get_bs11_date_time(struct bs11_date_time *aet)
1942{
1943 time_t t;
1944 struct tm *tm;
1945
1946 t = time(NULL);
1947 tm = localtime(&t);
1948 aet->sec = tm->tm_sec;
1949 aet->min = tm->tm_min;
1950 aet->hour = tm->tm_hour;
1951 aet->day = tm->tm_mday;
1952 aet->month = tm->tm_mon;
1953 aet->year = htons(1900 + tm->tm_year);
1954}
1955
Harald Welte05188ee2009-01-18 11:39:08 +00001956int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001957{
Harald Welte4668fda2009-01-03 08:19:29 +00001958 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001959}
1960
Harald Welte05188ee2009-01-18 11:39:08 +00001961int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001962{
1963 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001964 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001965 else
Harald Welte4668fda2009-01-03 08:19:29 +00001966 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001967}
Harald Welte47d88ae2009-01-04 12:02:08 +00001968
Harald Welte05188ee2009-01-18 11:39:08 +00001969int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001970 enum abis_bs11_objtype type, uint8_t idx,
1971 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001972{
1973 struct abis_om_hdr *oh;
1974 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001975 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001976
1977 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001978 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001979 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001980 cur = msgb_put(msg, attr_len);
1981 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001982
1983 return abis_nm_sendmsg(bts, msg);
1984}
1985
Harald Welte78fc0d42009-02-19 02:50:57 +00001986int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001987 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001988{
1989 struct abis_om_hdr *oh;
1990 struct msgb *msg = nm_msgb_alloc();
1991
1992 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1993 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1994 NM_OC_BS11, type, 0, idx);
1995
1996 return abis_nm_sendmsg(bts, msg);
1997}
1998
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001999int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002000{
2001 struct abis_om_hdr *oh;
2002 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002003 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002004
2005 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002006 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002007 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2008 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002009
2010 return abis_nm_sendmsg(bts, msg);
2011}
2012
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002013int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002014{
2015 struct abis_om_hdr *oh;
2016 struct msgb *msg = nm_msgb_alloc();
2017
2018 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2019 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002020 idx, 0xff, 0xff);
2021
2022 return abis_nm_sendmsg(bts, msg);
2023}
2024
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002025int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002026{
2027 struct abis_om_hdr *oh;
2028 struct msgb *msg = nm_msgb_alloc();
2029
2030 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2031 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2032 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002033
2034 return abis_nm_sendmsg(bts, msg);
2035}
Harald Welte05188ee2009-01-18 11:39:08 +00002036
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002037static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002038int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2039{
2040 struct abis_om_hdr *oh;
2041 struct msgb *msg = nm_msgb_alloc();
2042
2043 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2044 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2045 0xff, 0xff, 0xff);
2046 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2047
2048 return abis_nm_sendmsg(bts, msg);
2049}
2050
Harald Welteb6c92ae2009-02-21 20:15:32 +00002051/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002052int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2053 uint8_t e1_timeslot, uint8_t e1_subslot,
2054 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002055{
2056 struct abis_om_hdr *oh;
2057 struct abis_nm_channel *ch;
2058 struct msgb *msg = nm_msgb_alloc();
2059
2060 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002061 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002062 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2063
2064 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2065 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002066 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002067
2068 return abis_nm_sendmsg(bts, msg);
2069}
2070
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002071int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002072{
2073 struct abis_om_hdr *oh;
2074 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002075
2076 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002077 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002078 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2079 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2080
2081 return abis_nm_sendmsg(trx->bts, msg);
2082}
2083
Harald Welte78fc0d42009-02-19 02:50:57 +00002084int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2085{
2086 struct abis_om_hdr *oh;
2087 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002088 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002089
2090 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2091 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2092 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2093 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2094
2095 return abis_nm_sendmsg(trx->bts, msg);
2096}
2097
Harald Welteaaf02d92009-04-29 13:25:57 +00002098int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2099{
2100 struct abis_om_hdr *oh;
2101 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002102 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002103
2104 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2105 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2106 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002107 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002108
2109 return abis_nm_sendmsg(bts, msg);
2110}
2111
Harald Welteef061952009-05-17 12:43:42 +00002112int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2113{
2114 struct abis_om_hdr *oh;
2115 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002116 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002117 NM_ATT_BS11_CCLK_TYPE };
2118
2119 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2120 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2121 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2122 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2123
2124 return abis_nm_sendmsg(bts, msg);
2125
2126}
Harald Welteaaf02d92009-04-29 13:25:57 +00002127
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002128//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002129
Harald Welte1bc09062009-01-18 14:17:52 +00002130int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002131{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002132 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2133}
2134
Daniel Willmann4b054c82010-01-07 00:46:26 +01002135int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2136{
2137 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2138}
2139
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002140int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002141{
Harald Welte05188ee2009-01-18 11:39:08 +00002142 struct abis_om_hdr *oh;
2143 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002144 struct bs11_date_time bdt;
2145
2146 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002147
2148 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002149 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002150 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002151 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002152 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002153 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002154 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002155 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002156 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002157 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002158 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002159 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002160 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002161 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002162 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002163 }
Harald Welte05188ee2009-01-18 11:39:08 +00002164
2165 return abis_nm_sendmsg(bts, msg);
2166}
Harald Welte1bc09062009-01-18 14:17:52 +00002167
2168int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2169{
2170 struct abis_om_hdr *oh;
2171 struct msgb *msg;
2172
2173 if (strlen(password) != 10)
2174 return -EINVAL;
2175
2176 msg = nm_msgb_alloc();
2177 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002178 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002179 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002180 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002181
2182 return abis_nm_sendmsg(bts, msg);
2183}
2184
Harald Weltee69f5fb2009-04-28 16:31:38 +00002185/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2186int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2187{
2188 struct abis_om_hdr *oh;
2189 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002190 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002191
2192 msg = nm_msgb_alloc();
2193 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2194 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2195 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002196
2197 if (locked)
2198 tlv_value = BS11_LI_PLL_LOCKED;
2199 else
2200 tlv_value = BS11_LI_PLL_STANDALONE;
2201
2202 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002203
2204 return abis_nm_sendmsg(bts, msg);
2205}
2206
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002207/* Set the calibration value of the PLL (work value/set value)
2208 * It depends on the login which one is changed */
2209int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2210{
2211 struct abis_om_hdr *oh;
2212 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002213 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002214
2215 msg = nm_msgb_alloc();
2216 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2217 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2218 BS11_OBJ_TRX1, 0x00, 0x00);
2219
2220 tlv_value[0] = value>>8;
2221 tlv_value[1] = value&0xff;
2222
2223 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2224
2225 return abis_nm_sendmsg(bts, msg);
2226}
2227
Harald Welte1bc09062009-01-18 14:17:52 +00002228int abis_nm_bs11_get_state(struct gsm_bts *bts)
2229{
2230 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2231}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002232
2233/* BS11 SWL */
2234
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002235void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002236
Harald Welte5e4d1b32009-02-01 13:36:56 +00002237struct abis_nm_bs11_sw {
2238 struct gsm_bts *bts;
2239 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002240 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002241 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002242 struct llist_head file_list;
2243 gsm_cbfn *user_cb; /* specified by the user */
2244};
2245static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2246
2247struct file_list_entry {
2248 struct llist_head list;
2249 char fname[PATH_MAX];
2250};
2251
2252struct file_list_entry *fl_dequeue(struct llist_head *queue)
2253{
2254 struct llist_head *lh;
2255
2256 if (llist_empty(queue))
2257 return NULL;
2258
2259 lh = queue->next;
2260 llist_del(lh);
2261
2262 return llist_entry(lh, struct file_list_entry, list);
2263}
2264
2265static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2266{
2267 char linebuf[255];
2268 struct llist_head *lh, *lh2;
2269 FILE *swl;
2270 int rc = 0;
2271
2272 swl = fopen(bs11_sw->swl_fname, "r");
2273 if (!swl)
2274 return -ENODEV;
2275
2276 /* zero the stale file list, if any */
2277 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2278 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002279 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002280 }
2281
2282 while (fgets(linebuf, sizeof(linebuf), swl)) {
2283 char file_id[12+1];
2284 char file_version[80+1];
2285 struct file_list_entry *fle;
2286 static char dir[PATH_MAX];
2287
2288 if (strlen(linebuf) < 4)
2289 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002290
Harald Welte5e4d1b32009-02-01 13:36:56 +00002291 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2292 if (rc < 0) {
2293 perror("ERR parsing SWL file");
2294 rc = -EINVAL;
2295 goto out;
2296 }
2297 if (rc < 2)
2298 continue;
2299
Harald Welte470ec292009-06-26 20:25:23 +02002300 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002301 if (!fle) {
2302 rc = -ENOMEM;
2303 goto out;
2304 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002305
2306 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002307 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002308 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2309 strcat(fle->fname, "/");
2310 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002311
2312 llist_add_tail(&fle->list, &bs11_sw->file_list);
2313 }
2314
2315out:
2316 fclose(swl);
2317 return rc;
2318}
2319
2320/* bs11 swload specific callback, passed to abis_nm core swload */
2321static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2322 struct msgb *msg, void *data, void *param)
2323{
2324 struct abis_nm_bs11_sw *bs11_sw = data;
2325 struct file_list_entry *fle;
2326 int rc = 0;
2327
Harald Welte5e4d1b32009-02-01 13:36:56 +00002328 switch (event) {
2329 case NM_MT_LOAD_END_ACK:
2330 fle = fl_dequeue(&bs11_sw->file_list);
2331 if (fle) {
2332 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002333 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002334 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002335 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002336 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002337 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002338 } else {
2339 /* activate the SWL */
2340 rc = abis_nm_software_activate(bs11_sw->bts,
2341 bs11_sw->swl_fname,
2342 bs11_swload_cbfn,
2343 bs11_sw);
2344 }
2345 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002346 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002347 case NM_MT_LOAD_END_NACK:
2348 case NM_MT_LOAD_INIT_ACK:
2349 case NM_MT_LOAD_INIT_NACK:
2350 case NM_MT_ACTIVATE_SW_NACK:
2351 case NM_MT_ACTIVATE_SW_ACK:
2352 default:
2353 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002354 if (bs11_sw->user_cb)
2355 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002356 break;
2357 }
2358
2359 return rc;
2360}
2361
2362/* Siemens provides a SWL file that is a mere listing of all the other
2363 * files that are part of a software release. We need to upload first
2364 * the list file, and then each file that is listed in the list file */
2365int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002366 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002367{
2368 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2369 struct file_list_entry *fle;
2370 int rc = 0;
2371
2372 INIT_LLIST_HEAD(&bs11_sw->file_list);
2373 bs11_sw->bts = bts;
2374 bs11_sw->win_size = win_size;
2375 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002376 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002377
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002378 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002379 rc = bs11_read_swl_file(bs11_sw);
2380 if (rc < 0)
2381 return rc;
2382
2383 /* dequeue next item in file list */
2384 fle = fl_dequeue(&bs11_sw->file_list);
2385 if (!fle)
2386 return -EINVAL;
2387
2388 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002389 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002390 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002391 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002392 return rc;
2393}
2394
Harald Welte5083b0b2009-02-02 19:20:52 +00002395#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002396static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002397 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2398 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2399 NM_ATT_BS11_LMT_USER_NAME,
2400
2401 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2402
2403 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2404
2405 NM_ATT_BS11_SW_LOAD_STORED };
2406
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002407static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002408 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2409 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2410 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2411 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002412#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002413
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002414static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002415 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2416 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002417 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002418
2419int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2420{
2421 struct abis_om_hdr *oh;
2422 struct msgb *msg = nm_msgb_alloc();
2423
2424 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2425 /* SiemensHW CCTRL object */
2426 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2427 0x03, 0x00, 0x00);
2428 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2429
2430 return abis_nm_sendmsg(bts, msg);
2431}
Harald Welte268bb402009-02-01 19:11:56 +00002432
2433int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2434{
2435 struct abis_om_hdr *oh;
2436 struct msgb *msg = nm_msgb_alloc();
2437 struct bs11_date_time aet;
2438
2439 get_bs11_date_time(&aet);
2440 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2441 /* SiemensHW CCTRL object */
2442 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2443 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002444 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002445
2446 return abis_nm_sendmsg(bts, msg);
2447}
Harald Welte5c1e4582009-02-15 11:57:29 +00002448
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002449int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002450{
2451 struct abis_om_hdr *oh;
2452 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002453 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002454
2455 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2456 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2457 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2458 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2459
2460 return abis_nm_sendmsg(bts, msg);
2461}
2462
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002463int 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 +02002464{
2465 struct abis_om_hdr *oh;
2466 struct msgb *msg = nm_msgb_alloc();
2467 struct bs11_date_time aet;
2468
2469 get_bs11_date_time(&aet);
2470 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2471 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2472 bport, 0xff, 0x02);
2473 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2474
2475 return abis_nm_sendmsg(bts, msg);
2476}
2477
Harald Welte5c1e4582009-02-15 11:57:29 +00002478/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002479static const char ipaccess_magic[] = "com.ipaccess";
2480
Harald Welte677c21f2009-02-17 13:22:23 +00002481
2482static int abis_nm_rx_ipacc(struct msgb *msg)
2483{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002484 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002485 struct abis_om_hdr *oh = msgb_l2(msg);
2486 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002487 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002488 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002489 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002490 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002491
2492 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002493 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002494 return -EINVAL;
2495 }
2496
Harald Welte193fefc2009-04-30 15:16:27 +00002497 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002498 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002499
Harald Welte15c61722011-05-22 22:45:37 +02002500 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002501
Harald Welte746d6092009-10-19 22:11:11 +02002502 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002503
Harald Welte677c21f2009-02-17 13:22:23 +00002504 switch (foh->msg_type) {
2505 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002506 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002507 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2508 memcpy(&addr,
2509 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2510
2511 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2512 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002513 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002514 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002515 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002516 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002517 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2518 DEBUGPC(DNM, "STREAM=0x%02x ",
2519 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002520 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002521 break;
2522 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002523 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002524 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002525 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002526 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002527 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002528 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002529 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002530 case NM_MT_IPACC_SET_NVATTR_ACK:
2531 DEBUGPC(DNM, "SET NVATTR ACK\n");
2532 /* FIXME: decode and show the actual attributes */
2533 break;
2534 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002535 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002536 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002537 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002538 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002539 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002540 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002541 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002542 case NM_MT_IPACC_GET_NVATTR_ACK:
2543 DEBUGPC(DNM, "GET NVATTR ACK\n");
2544 /* FIXME: decode and show the actual attributes */
2545 break;
2546 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002547 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002548 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002549 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002550 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002551 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002552 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002553 break;
Harald Welte15c44172009-10-08 20:15:24 +02002554 case NM_MT_IPACC_SET_ATTR_ACK:
2555 DEBUGPC(DNM, "SET ATTR ACK\n");
2556 break;
2557 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002558 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002559 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002560 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002561 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002562 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002563 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002564 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002565 default:
2566 DEBUGPC(DNM, "unknown\n");
2567 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002568 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002569
2570 /* signal handling */
2571 switch (foh->msg_type) {
2572 case NM_MT_IPACC_RSL_CONNECT_NACK:
2573 case NM_MT_IPACC_SET_NVATTR_NACK:
2574 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002575 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 +01002576 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002577 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002578 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002579 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002580 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 +01002581 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002582 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002583 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002584 default:
2585 break;
2586 }
2587
Harald Welte677c21f2009-02-17 13:22:23 +00002588 return 0;
2589}
2590
Harald Welte193fefc2009-04-30 15:16:27 +00002591/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002592int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2593 uint8_t obj_class, uint8_t bts_nr,
2594 uint8_t trx_nr, uint8_t ts_nr,
2595 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002596{
2597 struct msgb *msg = nm_msgb_alloc();
2598 struct abis_om_hdr *oh;
2599 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002600 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002601
2602 /* construct the 12.21 OM header, observe the erroneous length */
2603 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2604 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2605 oh->mdisc = ABIS_OM_MDISC_MANUF;
2606
2607 /* add the ip.access magic */
2608 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2609 *data++ = sizeof(ipaccess_magic);
2610 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2611
2612 /* fill the 12.21 FOM header */
2613 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2614 foh->msg_type = msg_type;
2615 foh->obj_class = obj_class;
2616 foh->obj_inst.bts_nr = bts_nr;
2617 foh->obj_inst.trx_nr = trx_nr;
2618 foh->obj_inst.ts_nr = ts_nr;
2619
2620 if (attr && attr_len) {
2621 data = msgb_put(msg, attr_len);
2622 memcpy(data, attr, attr_len);
2623 }
2624
2625 return abis_nm_sendmsg(bts, msg);
2626}
Harald Welte677c21f2009-02-17 13:22:23 +00002627
Harald Welte193fefc2009-04-30 15:16:27 +00002628/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002629int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002630 int attr_len)
2631{
Harald Welte2ef156d2010-01-07 20:39:42 +01002632 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2633 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002634 attr_len);
2635}
2636
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002637int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002638 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002639{
2640 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002641 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002642 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2643 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2644
2645 int attr_len = sizeof(attr);
2646
2647 ia.s_addr = htonl(ip);
2648 attr[1] = stream;
2649 attr[3] = port >> 8;
2650 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002651 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002652
2653 /* if ip == 0, we use the default IP */
2654 if (ip == 0)
2655 attr_len -= 5;
2656
2657 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002658 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002659
2660 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2661 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2662 trx->nr, 0xff, attr, attr_len);
2663}
2664
Harald Welte193fefc2009-04-30 15:16:27 +00002665/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002666int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002667{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002668 struct abis_om_hdr *oh;
2669 struct msgb *msg = nm_msgb_alloc();
2670
2671 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2672 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2673 trx->bts->nr, trx->nr, 0xff);
2674
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002675 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002676}
Harald Weltedaef5212009-10-24 10:20:41 +02002677
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002678int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2679 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2680 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002681{
2682 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2683 obj_class, bts_nr, trx_nr, ts_nr,
2684 attr, attr_len);
2685}
Harald Welte0f255852009-11-12 14:48:42 +01002686
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002687void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002688{
2689 /* we simply reuse the GSM48 function and overwrite the RAC
2690 * with the Cell ID */
2691 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002692 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002693}
2694
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002695void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2696{
2697 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2698
Harald Welted64c0bc2011-05-30 12:07:53 +02002699 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002700 if (!trx->bts || !trx->bts->oml_link)
2701 return;
2702
2703 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2704 trx->bts->bts_nr, trx->nr, 0xff,
2705 new_state);
2706}
2707
Harald Welte92b1fe42010-03-25 11:45:30 +08002708static const struct value_string ipacc_testres_names[] = {
2709 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2710 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2711 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2712 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2713 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2714 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002715};
2716
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002717const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002718{
Harald Welte92b1fe42010-03-25 11:45:30 +08002719 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002720}
2721
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002722void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002723{
2724 cid->mcc = (buf[0] & 0xf) * 100;
2725 cid->mcc += (buf[0] >> 4) * 10;
2726 cid->mcc += (buf[1] & 0xf) * 1;
2727
2728 if (buf[1] >> 4 == 0xf) {
2729 cid->mnc = (buf[2] & 0xf) * 10;
2730 cid->mnc += (buf[2] >> 4) * 1;
2731 } else {
2732 cid->mnc = (buf[2] & 0xf) * 100;
2733 cid->mnc += (buf[2] >> 4) * 10;
2734 cid->mnc += (buf[1] >> 4) * 1;
2735 }
2736
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002737 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2738 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002739}
2740
Harald Welte0f255852009-11-12 14:48:42 +01002741/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002742int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002743{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002744 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002745 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002746
Harald Welteaf109b92010-07-22 18:14:36 +02002747 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002748
2749 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2750 return -EINVAL;
2751 cur++;
2752
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002753 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002754 cur += 2;
2755
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002756 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002757 cur += 2;
2758
2759 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2760 binf->freq_qual = *cur >> 2;
2761
Harald Welteaf109b92010-07-22 18:14:36 +02002762 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002763 binf->arfcn |= *cur++;
2764
2765 if (binf->info_type & IPAC_BINF_RXLEV)
2766 binf->rx_lev = *cur & 0x3f;
2767 cur++;
2768
2769 if (binf->info_type & IPAC_BINF_RXQUAL)
2770 binf->rx_qual = *cur & 0x7;
2771 cur++;
2772
2773 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002774 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002775 cur += 2;
2776
2777 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002778 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002779 cur += 2;
2780
2781 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002782 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002783 cur += 4;
2784
Harald Weltea780a3d2010-07-30 22:34:42 +02002785#if 0
2786 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002787 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002788#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002789 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002790 cur++;
2791
Harald Welteb40a38f2009-11-13 11:56:05 +01002792 ipac_parse_cgi(&binf->cgi, cur);
2793 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002794
2795 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2796 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2797 cur += sizeof(binf->ba_list_si2);
2798 }
2799
2800 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2801 memcpy(binf->ba_list_si2bis, cur,
2802 sizeof(binf->ba_list_si2bis));
2803 cur += sizeof(binf->ba_list_si2bis);
2804 }
2805
2806 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2807 memcpy(binf->ba_list_si2ter, cur,
2808 sizeof(binf->ba_list_si2ter));
2809 cur += sizeof(binf->ba_list_si2ter);
2810 }
2811
2812 return 0;
2813}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002814
2815void abis_nm_clear_queue(struct gsm_bts *bts)
2816{
2817 struct msgb *msg;
2818
2819 while (!llist_empty(&bts->abis_queue)) {
2820 msg = msgb_dequeue(&bts->abis_queue);
2821 msgb_free(msg);
2822 }
2823
2824 bts->abis_nm_pend = 0;
2825}