blob: 651ca02f3ca87393289247c1c73f2ddd89b0f894 [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;
Max689e7e52017-04-04 19:21:24 +0200697 case NM_MT_OPSTART_ACK:
698 abis_nm_debugp_foh(DNM, foh);
699 DEBUGPC(DNM, "Opstart ACK\n");
700 break;
701 case NM_MT_SET_CHAN_ATTR_ACK:
702 abis_nm_debugp_foh(DNM, foh);
703 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
704 break;
705 case NM_MT_SET_RADIO_ATTR_ACK:
706 abis_nm_debugp_foh(DNM, foh);
707 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
708 break;
Harald Welte1989c082009-08-06 17:58:31 +0200709 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200710 abis_nm_debugp_foh(DNM, foh);
711 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200712 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100713 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200714 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100715 break;
716 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200717 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100718 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100719 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100720 break;
Max689e7e52017-04-04 19:21:24 +0200721 default:
722 abis_nm_debugp_foh(DNM, foh);
723 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
724 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000725 }
726
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100727 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100728 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000729}
730
Harald Welte677c21f2009-02-17 13:22:23 +0000731static int abis_nm_rx_ipacc(struct msgb *mb);
732
733static int abis_nm_rcvmsg_manuf(struct msgb *mb)
734{
735 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200736 struct e1inp_sign_link *sign_link = mb->dst;
737 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000738
739 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100740 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200741 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000742 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200743 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000744 break;
745 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100746 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
747 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000748 rc = 0;
749 break;
750 }
751
752 return rc;
753}
754
Harald Welte52b1f982008-12-23 20:25:15 +0000755/* High-Level API */
756/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000757int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000758{
Harald Welte52b1f982008-12-23 20:25:15 +0000759 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000760 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000761
762 /* Various consistency checks */
763 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100764 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000765 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200766 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
767 rc = -EINVAL;
768 goto err;
769 }
Harald Welte52b1f982008-12-23 20:25:15 +0000770 }
771 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100772 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000773 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200774 rc = -EINVAL;
775 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000776 }
Harald Welte702d8702008-12-26 20:25:35 +0000777#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200778 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000779 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000780 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100781 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000782 oh->length + sizeof(*oh), l2_len);
783 return -EINVAL;
784 }
Harald Welte702d8702008-12-26 20:25:35 +0000785 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100786 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 +0000787#endif
Harald Weltead384642008-12-26 10:20:07 +0000788 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000789
790 switch (oh->mdisc) {
791 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000792 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000793 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000794 case ABIS_OM_MDISC_MANUF:
795 rc = abis_nm_rcvmsg_manuf(msg);
796 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000797 case ABIS_OM_MDISC_MMI:
798 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100799 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000800 oh->mdisc);
801 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000802 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100803 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000804 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200805 rc = -EINVAL;
806 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000807 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200808err:
Harald Weltead384642008-12-26 10:20:07 +0000809 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000810 return rc;
811}
812
813#if 0
814/* initialized all resources */
815struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
816{
817 struct abis_nm_h *nmh;
818
819 nmh = malloc(sizeof(*nmh));
820 if (!nmh)
821 return NULL;
822
823 nmh->cfg = cfg;
824
825 return nmh;
826}
827
828/* free all resources */
829void abis_nm_fini(struct abis_nm_h *nmh)
830{
831 free(nmh);
832}
833#endif
834
835/* Here we are trying to define a high-level API that can be used by
836 * the actual BSC implementation. However, the architecture is currently
837 * still under design. Ideally the calls to this API would be synchronous,
838 * while the underlying stack behind the APi runs in a traditional select
839 * based state machine.
840 */
841
Harald Welte4724f992009-01-18 18:01:49 +0000842/* 6.2 Software Load: */
843enum sw_state {
844 SW_STATE_NONE,
845 SW_STATE_WAIT_INITACK,
846 SW_STATE_WAIT_SEGACK,
847 SW_STATE_WAIT_ENDACK,
848 SW_STATE_WAIT_ACTACK,
849 SW_STATE_ERROR,
850};
Harald Welte52b1f982008-12-23 20:25:15 +0000851
Harald Welte52b1f982008-12-23 20:25:15 +0000852struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000853 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800854 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000855 gsm_cbfn *cbfn;
856 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000857 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000858
Harald Welte52b1f982008-12-23 20:25:15 +0000859 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200860 uint8_t obj_class;
861 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000862
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200863 uint8_t file_id[255];
864 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000865
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200866 uint8_t file_version[255];
867 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000868
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200869 uint8_t window_size;
870 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000871
872 int fd;
873 FILE *stream;
874 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000875 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000876};
877
Harald Welte4724f992009-01-18 18:01:49 +0000878static struct abis_nm_sw g_sw;
879
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100880static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
881{
882 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
883 msgb_v_put(msg, NM_ATT_SW_DESCR);
884 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
885 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
886 sw->file_version);
887 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
888 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
889 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
890 sw->file_version);
891 } else {
892 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
893 }
894}
895
Harald Welte4724f992009-01-18 18:01:49 +0000896/* 6.2.1 / 8.3.1: Load Data Initiate */
897static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000898{
Harald Welte4724f992009-01-18 18:01:49 +0000899 struct abis_om_hdr *oh;
900 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200901 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000902
903 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
904 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
905 sw->obj_instance[0], sw->obj_instance[1],
906 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100907
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100908 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000909 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
910
911 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000912}
913
Harald Welte1602ade2009-01-29 21:12:39 +0000914static int is_last_line(FILE *stream)
915{
916 char next_seg_buf[256];
917 long pos;
918
919 /* check if we're sending the last line */
920 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200921
922 /* Did ftell fail? Then we are at the end for sure */
923 if (pos < 0)
924 return 1;
925
Harald Welte1602ade2009-01-29 21:12:39 +0000926 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +0100927 int rc = fseek(stream, pos, SEEK_SET);
928 if (rc < 0)
929 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000930 return 1;
931 }
932
933 fseek(stream, pos, SEEK_SET);
934 return 0;
935}
936
Harald Welte4724f992009-01-18 18:01:49 +0000937/* 6.2.2 / 8.3.2 Load Data Segment */
938static int sw_load_segment(struct abis_nm_sw *sw)
939{
940 struct abis_om_hdr *oh;
941 struct msgb *msg = nm_msgb_alloc();
942 char seg_buf[256];
943 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000944 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200945 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000946
947 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000948
949 switch (sw->bts->type) {
950 case GSM_BTS_TYPE_BS11:
951 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
952 perror("fgets reading segment");
953 return -EINVAL;
954 }
955 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000956
957 /* check if we're sending the last line */
958 sw->last_seg = is_last_line(sw->stream);
959 if (sw->last_seg)
960 seg_buf[1] = 0;
961 else
962 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000963
964 len = strlen(line_buf) + 2;
965 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200966 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000967 /* BS11 wants CR + LF in excess of the TLV length !?! */
968 tlv[1] -= 2;
969
970 /* we only now know the exact length for the OM hdr */
971 len = strlen(line_buf)+2;
972 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100973 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200974 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100975 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
976 if (len < 0) {
977 perror("read failed");
978 return -EINVAL;
979 }
980
981 if (len != IPACC_SEGMENT_SIZE)
982 sw->last_seg = 1;
983
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100984 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200985 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100986 len += 3;
987 break;
988 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000989 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100990 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000991 /* FIXME: Other BTS types */
992 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000993 }
Harald Welte4724f992009-01-18 18:01:49 +0000994
Harald Welte4724f992009-01-18 18:01:49 +0000995 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
996 sw->obj_instance[0], sw->obj_instance[1],
997 sw->obj_instance[2]);
998
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100999 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001000}
1001
1002/* 6.2.4 / 8.3.4 Load Data End */
1003static int sw_load_end(struct abis_nm_sw *sw)
1004{
1005 struct abis_om_hdr *oh;
1006 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001007 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001008
1009 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1010 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1011 sw->obj_instance[0], sw->obj_instance[1],
1012 sw->obj_instance[2]);
1013
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001014 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001015 return abis_nm_sendmsg(sw->bts, msg);
1016}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001017
Harald Welte52b1f982008-12-23 20:25:15 +00001018/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001019static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001020{
Harald Welte4724f992009-01-18 18:01:49 +00001021 struct abis_om_hdr *oh;
1022 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001023 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001024
Harald Welte4724f992009-01-18 18:01:49 +00001025 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1026 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1027 sw->obj_instance[0], sw->obj_instance[1],
1028 sw->obj_instance[2]);
1029
1030 /* FIXME: this is BS11 specific format */
1031 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1032 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1033 sw->file_version);
1034
1035 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001036}
Harald Welte4724f992009-01-18 18:01:49 +00001037
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001038struct sdp_firmware {
1039 char magic[4];
1040 char more_magic[4];
1041 unsigned int header_length;
1042 unsigned int file_length;
1043} __attribute__ ((packed));
1044
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001045static int parse_sdp_header(struct abis_nm_sw *sw)
1046{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001047 struct sdp_firmware firmware_header;
1048 int rc;
1049 struct stat stat;
1050
1051 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1052 if (rc != sizeof(firmware_header)) {
1053 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1054 return -1;
1055 }
1056
1057 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1058 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1059 return -1;
1060 }
1061
1062 if (firmware_header.more_magic[0] != 0x10 ||
1063 firmware_header.more_magic[1] != 0x02 ||
1064 firmware_header.more_magic[2] != 0x00 ||
1065 firmware_header.more_magic[3] != 0x00) {
1066 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1067 return -1;
1068 }
1069
1070
1071 if (fstat(sw->fd, &stat) == -1) {
1072 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1073 return -1;
1074 }
1075
1076 if (ntohl(firmware_header.file_length) != stat.st_size) {
1077 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1078 return -1;
1079 }
1080
1081 /* go back to the start as we checked the whole filesize.. */
1082 lseek(sw->fd, 0l, SEEK_SET);
1083 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1084 "There might be checksums in the file that are not\n"
1085 "verified and incomplete firmware might be flashed.\n"
1086 "There is absolutely no WARRANTY that flashing will\n"
1087 "work.\n");
1088 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001089}
1090
Harald Welte4724f992009-01-18 18:01:49 +00001091static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1092{
1093 char file_id[12+1];
1094 char file_version[80+1];
1095 int rc;
1096
1097 sw->fd = open(fname, O_RDONLY);
1098 if (sw->fd < 0)
1099 return sw->fd;
1100
1101 switch (sw->bts->type) {
1102 case GSM_BTS_TYPE_BS11:
1103 sw->stream = fdopen(sw->fd, "r");
1104 if (!sw->stream) {
1105 perror("fdopen");
1106 return -1;
1107 }
1108 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001109 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001110 file_id, file_version);
1111 if (rc != 2) {
1112 perror("parsing header line of software file");
1113 return -1;
1114 }
1115 strcpy((char *)sw->file_id, file_id);
1116 sw->file_id_len = strlen(file_id);
1117 strcpy((char *)sw->file_version, file_version);
1118 sw->file_version_len = strlen(file_version);
1119 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001120 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001121 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001122 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001123 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001124 rc = parse_sdp_header(sw);
1125 if (rc < 0) {
1126 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1127 return -1;
1128 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001129
1130 strcpy((char *)sw->file_id, "id");
1131 sw->file_id_len = 3;
1132 strcpy((char *)sw->file_version, "version");
1133 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001134 break;
Harald Welte4724f992009-01-18 18:01:49 +00001135 default:
1136 /* We don't know how to treat them yet */
1137 close(sw->fd);
1138 return -EINVAL;
1139 }
1140
1141 return 0;
1142}
1143
1144static void sw_close_file(struct abis_nm_sw *sw)
1145{
1146 switch (sw->bts->type) {
1147 case GSM_BTS_TYPE_BS11:
1148 fclose(sw->stream);
1149 break;
1150 default:
1151 close(sw->fd);
1152 break;
1153 }
1154}
1155
1156/* Fill the window */
1157static int sw_fill_window(struct abis_nm_sw *sw)
1158{
1159 int rc;
1160
1161 while (sw->seg_in_window < sw->window_size) {
1162 rc = sw_load_segment(sw);
1163 if (rc < 0)
1164 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001165 if (sw->last_seg)
1166 break;
Harald Welte4724f992009-01-18 18:01:49 +00001167 }
1168 return 0;
1169}
1170
1171/* callback function from abis_nm_rcvmsg() handler */
1172static int abis_nm_rcvmsg_sw(struct msgb *mb)
1173{
1174 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001175 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001176 int rc = -1;
1177 struct abis_nm_sw *sw = &g_sw;
1178 enum sw_state old_state = sw->state;
1179
Harald Welte3ffd1372009-02-01 22:15:49 +00001180 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001181
1182 switch (sw->state) {
1183 case SW_STATE_WAIT_INITACK:
1184 switch (foh->msg_type) {
1185 case NM_MT_LOAD_INIT_ACK:
1186 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001187 if (sw->cbfn)
1188 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1189 NM_MT_LOAD_INIT_ACK, mb,
1190 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001191 rc = sw_fill_window(sw);
1192 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001193 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001194 break;
1195 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001196 if (sw->forced) {
1197 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1198 "Init NACK\n");
1199 if (sw->cbfn)
1200 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1201 NM_MT_LOAD_INIT_ACK, mb,
1202 sw->cb_data, NULL);
1203 rc = sw_fill_window(sw);
1204 sw->state = SW_STATE_WAIT_SEGACK;
1205 } else {
1206 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001207 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001208 if (sw->cbfn)
1209 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1210 NM_MT_LOAD_INIT_NACK, mb,
1211 sw->cb_data, NULL);
1212 sw->state = SW_STATE_ERROR;
1213 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001214 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001215 break;
1216 }
1217 break;
1218 case SW_STATE_WAIT_SEGACK:
1219 switch (foh->msg_type) {
1220 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001221 if (sw->cbfn)
1222 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1223 NM_MT_LOAD_SEG_ACK, mb,
1224 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001225 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001226 if (!sw->last_seg) {
1227 /* fill window with more segments */
1228 rc = sw_fill_window(sw);
1229 sw->state = SW_STATE_WAIT_SEGACK;
1230 } else {
1231 /* end the transfer */
1232 sw->state = SW_STATE_WAIT_ENDACK;
1233 rc = sw_load_end(sw);
1234 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001235 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001236 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001237 case NM_MT_LOAD_ABORT:
1238 if (sw->cbfn)
1239 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1240 NM_MT_LOAD_ABORT, mb,
1241 sw->cb_data, NULL);
1242 break;
Harald Welte4724f992009-01-18 18:01:49 +00001243 }
1244 break;
1245 case SW_STATE_WAIT_ENDACK:
1246 switch (foh->msg_type) {
1247 case NM_MT_LOAD_END_ACK:
1248 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001249 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1250 sw->bts->nr);
1251 sw->state = SW_STATE_NONE;
1252 if (sw->cbfn)
1253 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1254 NM_MT_LOAD_END_ACK, mb,
1255 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001256 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001257 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001258 break;
1259 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001260 if (sw->forced) {
1261 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1262 "End NACK\n");
1263 sw->state = SW_STATE_NONE;
1264 if (sw->cbfn)
1265 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1266 NM_MT_LOAD_END_ACK, mb,
1267 sw->cb_data, NULL);
1268 } else {
1269 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001270 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001271 sw->state = SW_STATE_ERROR;
1272 if (sw->cbfn)
1273 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1274 NM_MT_LOAD_END_NACK, mb,
1275 sw->cb_data, NULL);
1276 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001277 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001278 break;
1279 }
1280 case SW_STATE_WAIT_ACTACK:
1281 switch (foh->msg_type) {
1282 case NM_MT_ACTIVATE_SW_ACK:
1283 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001284 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001285 sw->state = SW_STATE_NONE;
1286 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001287 if (sw->cbfn)
1288 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1289 NM_MT_ACTIVATE_SW_ACK, mb,
1290 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001291 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001292 break;
1293 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001294 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001295 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001296 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001297 if (sw->cbfn)
1298 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1299 NM_MT_ACTIVATE_SW_NACK, mb,
1300 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001301 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001302 break;
1303 }
1304 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001305 switch (foh->msg_type) {
1306 case NM_MT_ACTIVATE_SW_ACK:
1307 rc = 0;
1308 break;
1309 }
1310 break;
Harald Welte4724f992009-01-18 18:01:49 +00001311 case SW_STATE_ERROR:
1312 break;
1313 }
1314
1315 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001316 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001317 foh->msg_type, old_state, sw->state);
1318
1319 return rc;
1320}
1321
1322/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001323int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001324 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001325 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001326{
1327 struct abis_nm_sw *sw = &g_sw;
1328 int rc;
1329
Harald Welte5e4d1b32009-02-01 13:36:56 +00001330 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1331 bts->nr, fname);
1332
Harald Welte4724f992009-01-18 18:01:49 +00001333 if (sw->state != SW_STATE_NONE)
1334 return -EBUSY;
1335
1336 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001337 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001338
1339 switch (bts->type) {
1340 case GSM_BTS_TYPE_BS11:
1341 sw->obj_class = NM_OC_SITE_MANAGER;
1342 sw->obj_instance[0] = 0xff;
1343 sw->obj_instance[1] = 0xff;
1344 sw->obj_instance[2] = 0xff;
1345 break;
1346 case GSM_BTS_TYPE_NANOBTS:
1347 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001348 sw->obj_instance[0] = sw->bts->nr;
1349 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001350 sw->obj_instance[2] = 0xff;
1351 break;
1352 case GSM_BTS_TYPE_UNKNOWN:
1353 default:
1354 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1355 return -1;
1356 break;
1357 }
Harald Welte4724f992009-01-18 18:01:49 +00001358 sw->window_size = win_size;
1359 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001360 sw->cbfn = cbfn;
1361 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001362 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001363
1364 rc = sw_open_file(sw, fname);
1365 if (rc < 0) {
1366 sw->state = SW_STATE_NONE;
1367 return rc;
1368 }
1369
1370 return sw_load_init(sw);
1371}
Harald Welte52b1f982008-12-23 20:25:15 +00001372
Harald Welte1602ade2009-01-29 21:12:39 +00001373int abis_nm_software_load_status(struct gsm_bts *bts)
1374{
1375 struct abis_nm_sw *sw = &g_sw;
1376 struct stat st;
1377 int rc, percent;
1378
1379 rc = fstat(sw->fd, &st);
1380 if (rc < 0) {
1381 perror("ERROR during stat");
1382 return rc;
1383 }
1384
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001385 if (sw->stream)
1386 percent = (ftell(sw->stream) * 100) / st.st_size;
1387 else
1388 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001389 return percent;
1390}
1391
Harald Welte5e4d1b32009-02-01 13:36:56 +00001392/* Activate the specified software into the BTS */
1393int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1394 gsm_cbfn *cbfn, void *cb_data)
1395{
1396 struct abis_nm_sw *sw = &g_sw;
1397 int rc;
1398
1399 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1400 bts->nr, fname);
1401
1402 if (sw->state != SW_STATE_NONE)
1403 return -EBUSY;
1404
1405 sw->bts = bts;
1406 sw->obj_class = NM_OC_SITE_MANAGER;
1407 sw->obj_instance[0] = 0xff;
1408 sw->obj_instance[1] = 0xff;
1409 sw->obj_instance[2] = 0xff;
1410 sw->state = SW_STATE_WAIT_ACTACK;
1411 sw->cbfn = cbfn;
1412 sw->cb_data = cb_data;
1413
1414 /* Open the file in order to fill some sw struct members */
1415 rc = sw_open_file(sw, fname);
1416 if (rc < 0) {
1417 sw->state = SW_STATE_NONE;
1418 return rc;
1419 }
1420 sw_close_file(sw);
1421
1422 return sw_activate(sw);
1423}
1424
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001425static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1426 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001427{
Harald Welteadaf08b2009-01-18 11:08:10 +00001428 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001429 ch->bts_port = bts_port;
1430 ch->timeslot = ts_nr;
1431 ch->subslot = subslot_nr;
1432}
1433
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001434int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1435 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1436 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001437{
1438 struct abis_om_hdr *oh;
1439 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001440 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001441 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001442
1443 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1444 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1445 bts->bts_nr, trx_nr, 0xff);
1446
Harald Welte8470bf22008-12-25 23:28:35 +00001447 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001448
1449 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1450 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1451
1452 return abis_nm_sendmsg(bts, msg);
1453}
1454
1455/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1456int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001457 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001458{
Harald Welte8470bf22008-12-25 23:28:35 +00001459 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001460 struct abis_om_hdr *oh;
1461 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001462 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001463
1464 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001465 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001466 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1467
1468 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1469 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1470
1471 return abis_nm_sendmsg(bts, msg);
1472}
1473
1474#if 0
1475int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1476 struct abis_nm_abis_channel *chan)
1477{
1478}
1479#endif
1480
1481int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001482 uint8_t e1_port, uint8_t e1_timeslot,
1483 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001484{
1485 struct gsm_bts *bts = ts->trx->bts;
1486 struct abis_om_hdr *oh;
1487 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001488 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001489
1490 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1491 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001492 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001493
1494 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1495 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1496
Harald Weltef325eb42009-02-19 17:07:39 +00001497 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1498 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001499 e1_port, e1_timeslot, e1_subslot);
1500
Harald Welte52b1f982008-12-23 20:25:15 +00001501 return abis_nm_sendmsg(bts, msg);
1502}
1503
1504#if 0
1505int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1506 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001507 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001508{
1509}
1510#endif
1511
Harald Weltefe568f22012-08-14 19:15:57 +02001512/* Chapter 8.11.1 */
1513int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1514 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1515 uint8_t *attr, uint8_t attr_len)
1516{
1517 struct abis_om_hdr *oh;
1518 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001519
1520 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1521
1522 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1523 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1524 bts_nr, trx_nr, ts_nr);
1525 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1526
1527 return abis_nm_sendmsg(bts, msg);
1528}
1529
Harald Welte22af0db2009-02-14 15:41:08 +00001530/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001531int abis_nm_set_bts_attr(struct gsm_bts *bts, 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 BTS Attr (bts=%d)\n", bts->nr);
1538
1539 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001540 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 +00001541 cur = msgb_put(msg, attr_len);
1542 memcpy(cur, attr, attr_len);
1543
1544 return abis_nm_sendmsg(bts, msg);
1545}
1546
1547/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001548int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001549{
1550 struct abis_om_hdr *oh;
1551 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001552 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001553
1554 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1555
1556 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1557 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001558 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001559 cur = msgb_put(msg, attr_len);
1560 memcpy(cur, attr, attr_len);
1561
1562 return abis_nm_sendmsg(trx->bts, msg);
1563}
1564
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001565int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1566{
1567 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1568 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1569}
1570
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001571static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1572 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001573{
1574 int i;
1575
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001576 *reason = "Reason unknown";
1577
Harald Welte39c7deb2009-08-09 21:49:48 +02001578 /* As it turns out, the BS-11 has some very peculiar restrictions
1579 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301580 switch (ts->trx->bts->type) {
1581 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001582 switch (chan_comb) {
1583 case NM_CHANC_TCHHalf:
1584 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001585 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001586 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001587 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001588 return -EINVAL;
1589 case NM_CHANC_SDCCH:
1590 /* only one SDCCH/8 per TRX */
1591 for (i = 0; i < TRX_NR_TS; i++) {
1592 if (i == ts->nr)
1593 continue;
1594 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001595 NM_CHANC_SDCCH) {
1596 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001597 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001598 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001599 }
1600 /* not allowed for TS0 of BCCH-TRX */
1601 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001602 ts->nr == 0) {
1603 *reason = "SDCCH/8 must be on TS0.";
1604 return -EINVAL;
1605 }
1606
Harald Welte39c7deb2009-08-09 21:49:48 +02001607 /* not on the same TRX that has a BCCH+SDCCH4
1608 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001609 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001610 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001611 ts->trx->ts[0].nm_chan_comb == 8)) {
1612 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1613 return -EINVAL;
1614 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001615 break;
1616 case NM_CHANC_mainBCCH:
1617 case NM_CHANC_BCCHComb:
1618 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001619 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1620 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001621 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001622 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001623 break;
1624 case NM_CHANC_BCCH:
1625 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001626 if (ts->trx != ts->trx->bts->c0) {
1627 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001628 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001629 }
1630 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1631 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001632 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001633 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001634 break;
1635 case 8: /* this is not like 08.58, but in fact
1636 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1637 /* FIXME: only one CBCH allowed per cell */
1638 break;
1639 }
Harald Welted6575f92009-12-02 02:45:23 +05301640 break;
1641 case GSM_BTS_TYPE_NANOBTS:
1642 switch (ts->nr) {
1643 case 0:
1644 if (ts->trx->nr == 0) {
1645 /* only on TRX0 */
1646 switch (chan_comb) {
1647 case NM_CHANC_BCCH:
1648 case NM_CHANC_mainBCCH:
1649 case NM_CHANC_BCCHComb:
1650 return 0;
1651 break;
1652 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001653 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301654 return -EINVAL;
1655 }
1656 } else {
1657 switch (chan_comb) {
1658 case NM_CHANC_TCHFull:
1659 case NM_CHANC_TCHHalf:
1660 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1661 return 0;
1662 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001663 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301664 return -EINVAL;
1665 }
1666 }
1667 break;
1668 case 1:
1669 if (ts->trx->nr == 0) {
1670 switch (chan_comb) {
1671 case NM_CHANC_SDCCH_CBCH:
1672 if (ts->trx->ts[0].nm_chan_comb ==
1673 NM_CHANC_mainBCCH)
1674 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001675 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301676 return -EINVAL;
1677 case NM_CHANC_SDCCH:
1678 case NM_CHANC_TCHFull:
1679 case NM_CHANC_TCHHalf:
1680 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1681 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001682 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301683 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001684 default:
1685 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1686 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301687 }
1688 } else {
1689 switch (chan_comb) {
1690 case NM_CHANC_SDCCH:
1691 case NM_CHANC_TCHFull:
1692 case NM_CHANC_TCHHalf:
1693 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1694 return 0;
1695 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001696 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301697 return -EINVAL;
1698 }
1699 }
1700 break;
1701 case 2:
1702 case 3:
1703 case 4:
1704 case 5:
1705 case 6:
1706 case 7:
1707 switch (chan_comb) {
1708 case NM_CHANC_TCHFull:
1709 case NM_CHANC_TCHHalf:
1710 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1711 return 0;
1712 case NM_CHANC_IPAC_PDCH:
1713 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001714 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301715 if (ts->trx->nr == 0)
1716 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001717 else {
1718 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301719 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001720 }
Harald Welted6575f92009-12-02 02:45:23 +05301721 }
1722 break;
1723 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001724 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301725 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001726 case GSM_BTS_TYPE_OSMO_SYSMO:
1727 /* no known restrictions */
1728 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301729 default:
1730 /* unknown BTS type */
1731 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001732 }
1733 return 0;
1734}
1735
Harald Welte22af0db2009-02-14 15:41:08 +00001736/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001737int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001738{
1739 struct gsm_bts *bts = ts->trx->bts;
1740 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001741 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001742 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001743 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001744 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001745
1746 if (bts->type == GSM_BTS_TYPE_BS11)
1747 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001748
Harald Weltef325eb42009-02-19 17:07:39 +00001749 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001750 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001751 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001752 LOGP(DNM, LOGL_ERROR,
1753 "Invalid Channel Combination %d on %s. Reason: %s\n",
1754 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001755 return -EINVAL;
1756 }
1757 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001758
Harald Welte52b1f982008-12-23 20:25:15 +00001759 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001760 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001761 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001762 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001763 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001764 if (ts->hopping.enabled) {
1765 unsigned int i;
1766 uint8_t *len;
1767
Harald Welte6e0cd042009-09-12 13:05:33 +02001768 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1769 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001770
1771 /* build the ARFCN list */
1772 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1773 len = msgb_put(msg, 1);
1774 *len = 0;
1775 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1776 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1777 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001778 /* At least BS-11 wants a TLV16 here */
1779 if (bts->type == GSM_BTS_TYPE_BS11)
1780 *len += 1;
1781 else
1782 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001783 }
1784 }
Harald Weltee0590df2009-02-15 03:34:15 +00001785 }
Harald Welte1fe24122014-01-19 17:18:21 +01001786 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001787 if (bts->type == GSM_BTS_TYPE_BS11)
1788 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001789
1790 return abis_nm_sendmsg(bts, msg);
1791}
1792
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001793int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1794 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001795{
1796 struct abis_om_hdr *oh;
1797 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001798 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1799 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001800
1801 if (nack) {
1802 len += 2;
1803 msgtype = NM_MT_SW_ACT_REQ_NACK;
1804 }
Harald Welte34a99682009-02-13 02:41:40 +00001805
1806 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001807 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1808
Harald Welte34a99682009-02-13 02:41:40 +00001809 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001810 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001811 memcpy(ptr, attr, att_len);
1812 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001813 if (nack)
1814 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001815
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001816 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001817}
1818
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001819int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001820{
Harald Welte8470bf22008-12-25 23:28:35 +00001821 struct msgb *msg = nm_msgb_alloc();
1822 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001823 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001824
1825 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1826 fill_om_hdr(oh, len);
1827 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001828 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001829
1830 return abis_nm_sendmsg(bts, msg);
1831}
1832
1833/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001834static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001835{
1836 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001837 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001838
1839 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001840 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001841 0xff, 0xff, 0xff);
1842
1843 return abis_nm_sendmsg(bts, msg);
1844}
1845
Harald Welte34a99682009-02-13 02:41:40 +00001846/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001847int 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 +00001848{
1849 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001850 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001851 struct msgb *msg = nm_msgb_alloc();
1852
1853 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001854 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001855
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001856 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001857 DEBUGPC(DNM, "Sending OPSTART\n");
1858
Harald Welte34a99682009-02-13 02:41:40 +00001859 return abis_nm_sendmsg(bts, msg);
1860}
1861
1862/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001863int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1864 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001865{
1866 struct abis_om_hdr *oh;
1867 struct msgb *msg = nm_msgb_alloc();
1868
1869 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1870 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1871 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1872
1873 return abis_nm_sendmsg(bts, msg);
1874}
1875
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001876int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1877 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001878{
1879 struct abis_om_hdr *oh;
1880 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001881 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001882
1883 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1884 e1_port0, ts0, e1_port1, ts1);
1885
1886 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1887 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1888 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1889
1890 attr = msgb_put(msg, 3);
1891 attr[0] = NM_ATT_MDROP_LINK;
1892 attr[1] = e1_port0;
1893 attr[2] = ts0;
1894
1895 attr = msgb_put(msg, 3);
1896 attr[0] = NM_ATT_MDROP_NEXT;
1897 attr[1] = e1_port1;
1898 attr[2] = ts1;
1899
1900 return abis_nm_sendmsg(bts, msg);
1901}
Harald Welte34a99682009-02-13 02:41:40 +00001902
Harald Weltec7310382009-08-08 00:02:36 +02001903/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001904int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1905 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1906 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001907{
1908 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001909
Harald Welte15c61722011-05-22 22:45:37 +02001910 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001911
1912 if (!msg)
1913 msg = nm_msgb_alloc();
1914
1915 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1916 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1917 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1918 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001919 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001920
1921 return abis_nm_sendmsg(bts, msg);
1922}
1923
Harald Welte52b1f982008-12-23 20:25:15 +00001924int abis_nm_event_reports(struct gsm_bts *bts, int on)
1925{
1926 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001927 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001928 else
Harald Welte227d4072009-01-03 08:16:25 +00001929 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001930}
1931
Harald Welte47d88ae2009-01-04 12:02:08 +00001932/* Siemens (or BS-11) specific commands */
1933
Harald Welte3ffd1372009-02-01 22:15:49 +00001934int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1935{
1936 if (reconnect == 0)
1937 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1938 else
1939 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1940}
1941
Harald Welteb8427972009-02-05 19:27:17 +00001942int abis_nm_bs11_restart(struct gsm_bts *bts)
1943{
1944 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1945}
1946
1947
Harald Welte268bb402009-02-01 19:11:56 +00001948struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001949 uint16_t year;
1950 uint8_t month;
1951 uint8_t day;
1952 uint8_t hour;
1953 uint8_t min;
1954 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001955} __attribute__((packed));
1956
1957
1958void get_bs11_date_time(struct bs11_date_time *aet)
1959{
1960 time_t t;
1961 struct tm *tm;
1962
1963 t = time(NULL);
1964 tm = localtime(&t);
1965 aet->sec = tm->tm_sec;
1966 aet->min = tm->tm_min;
1967 aet->hour = tm->tm_hour;
1968 aet->day = tm->tm_mday;
1969 aet->month = tm->tm_mon;
1970 aet->year = htons(1900 + tm->tm_year);
1971}
1972
Harald Welte05188ee2009-01-18 11:39:08 +00001973int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001974{
Harald Welte4668fda2009-01-03 08:19:29 +00001975 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001976}
1977
Harald Welte05188ee2009-01-18 11:39:08 +00001978int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001979{
1980 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001981 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001982 else
Harald Welte4668fda2009-01-03 08:19:29 +00001983 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001984}
Harald Welte47d88ae2009-01-04 12:02:08 +00001985
Harald Welte05188ee2009-01-18 11:39:08 +00001986int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001987 enum abis_bs11_objtype type, uint8_t idx,
1988 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001989{
1990 struct abis_om_hdr *oh;
1991 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001992 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001993
1994 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001995 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001996 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001997 cur = msgb_put(msg, attr_len);
1998 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001999
2000 return abis_nm_sendmsg(bts, msg);
2001}
2002
Harald Welte78fc0d42009-02-19 02:50:57 +00002003int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002004 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002005{
2006 struct abis_om_hdr *oh;
2007 struct msgb *msg = nm_msgb_alloc();
2008
2009 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2010 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2011 NM_OC_BS11, type, 0, idx);
2012
2013 return abis_nm_sendmsg(bts, msg);
2014}
2015
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002016int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002017{
2018 struct abis_om_hdr *oh;
2019 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002020 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002021
2022 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002023 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002024 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2025 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002026
2027 return abis_nm_sendmsg(bts, msg);
2028}
2029
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002030int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002031{
2032 struct abis_om_hdr *oh;
2033 struct msgb *msg = nm_msgb_alloc();
2034
2035 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2036 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002037 idx, 0xff, 0xff);
2038
2039 return abis_nm_sendmsg(bts, msg);
2040}
2041
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002042int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002043{
2044 struct abis_om_hdr *oh;
2045 struct msgb *msg = nm_msgb_alloc();
2046
2047 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2048 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2049 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002050
2051 return abis_nm_sendmsg(bts, msg);
2052}
Harald Welte05188ee2009-01-18 11:39:08 +00002053
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002054static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002055int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2056{
2057 struct abis_om_hdr *oh;
2058 struct msgb *msg = nm_msgb_alloc();
2059
2060 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2061 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2062 0xff, 0xff, 0xff);
2063 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2064
2065 return abis_nm_sendmsg(bts, msg);
2066}
2067
Harald Welteb6c92ae2009-02-21 20:15:32 +00002068/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002069int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2070 uint8_t e1_timeslot, uint8_t e1_subslot,
2071 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002072{
2073 struct abis_om_hdr *oh;
2074 struct abis_nm_channel *ch;
2075 struct msgb *msg = nm_msgb_alloc();
2076
2077 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002078 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002079 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2080
2081 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2082 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002083 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002084
2085 return abis_nm_sendmsg(bts, msg);
2086}
2087
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002088int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002089{
2090 struct abis_om_hdr *oh;
2091 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002092
2093 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002094 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002095 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2096 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2097
2098 return abis_nm_sendmsg(trx->bts, msg);
2099}
2100
Harald Welte78fc0d42009-02-19 02:50:57 +00002101int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2102{
2103 struct abis_om_hdr *oh;
2104 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002105 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002106
2107 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2108 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2109 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2110 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2111
2112 return abis_nm_sendmsg(trx->bts, msg);
2113}
2114
Harald Welteaaf02d92009-04-29 13:25:57 +00002115int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2116{
2117 struct abis_om_hdr *oh;
2118 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002119 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002120
2121 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2122 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2123 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002124 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002125
2126 return abis_nm_sendmsg(bts, msg);
2127}
2128
Harald Welteef061952009-05-17 12:43:42 +00002129int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2130{
2131 struct abis_om_hdr *oh;
2132 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002133 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002134 NM_ATT_BS11_CCLK_TYPE };
2135
2136 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2137 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2138 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2139 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2140
2141 return abis_nm_sendmsg(bts, msg);
2142
2143}
Harald Welteaaf02d92009-04-29 13:25:57 +00002144
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002145//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002146
Harald Welte1bc09062009-01-18 14:17:52 +00002147int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002148{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002149 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2150}
2151
Daniel Willmann4b054c82010-01-07 00:46:26 +01002152int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2153{
2154 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2155}
2156
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002157int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002158{
Harald Welte05188ee2009-01-18 11:39:08 +00002159 struct abis_om_hdr *oh;
2160 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002161 struct bs11_date_time bdt;
2162
2163 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002164
2165 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002166 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002167 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002168 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002169 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002170 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002171 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002172 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002173 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002174 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002175 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002176 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002177 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002178 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002179 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002180 }
Harald Welte05188ee2009-01-18 11:39:08 +00002181
2182 return abis_nm_sendmsg(bts, msg);
2183}
Harald Welte1bc09062009-01-18 14:17:52 +00002184
2185int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2186{
2187 struct abis_om_hdr *oh;
2188 struct msgb *msg;
2189
2190 if (strlen(password) != 10)
2191 return -EINVAL;
2192
2193 msg = nm_msgb_alloc();
2194 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002195 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002196 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002197 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002198
2199 return abis_nm_sendmsg(bts, msg);
2200}
2201
Harald Weltee69f5fb2009-04-28 16:31:38 +00002202/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2203int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2204{
2205 struct abis_om_hdr *oh;
2206 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002207 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002208
2209 msg = nm_msgb_alloc();
2210 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2211 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2212 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002213
2214 if (locked)
2215 tlv_value = BS11_LI_PLL_LOCKED;
2216 else
2217 tlv_value = BS11_LI_PLL_STANDALONE;
2218
2219 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002220
2221 return abis_nm_sendmsg(bts, msg);
2222}
2223
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002224/* Set the calibration value of the PLL (work value/set value)
2225 * It depends on the login which one is changed */
2226int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2227{
2228 struct abis_om_hdr *oh;
2229 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002230 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002231
2232 msg = nm_msgb_alloc();
2233 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2234 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2235 BS11_OBJ_TRX1, 0x00, 0x00);
2236
2237 tlv_value[0] = value>>8;
2238 tlv_value[1] = value&0xff;
2239
2240 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2241
2242 return abis_nm_sendmsg(bts, msg);
2243}
2244
Harald Welte1bc09062009-01-18 14:17:52 +00002245int abis_nm_bs11_get_state(struct gsm_bts *bts)
2246{
2247 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2248}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002249
2250/* BS11 SWL */
2251
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002252void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002253
Harald Welte5e4d1b32009-02-01 13:36:56 +00002254struct abis_nm_bs11_sw {
2255 struct gsm_bts *bts;
2256 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002257 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002258 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002259 struct llist_head file_list;
2260 gsm_cbfn *user_cb; /* specified by the user */
2261};
2262static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2263
2264struct file_list_entry {
2265 struct llist_head list;
2266 char fname[PATH_MAX];
2267};
2268
2269struct file_list_entry *fl_dequeue(struct llist_head *queue)
2270{
2271 struct llist_head *lh;
2272
2273 if (llist_empty(queue))
2274 return NULL;
2275
2276 lh = queue->next;
2277 llist_del(lh);
2278
2279 return llist_entry(lh, struct file_list_entry, list);
2280}
2281
2282static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2283{
2284 char linebuf[255];
2285 struct llist_head *lh, *lh2;
2286 FILE *swl;
2287 int rc = 0;
2288
2289 swl = fopen(bs11_sw->swl_fname, "r");
2290 if (!swl)
2291 return -ENODEV;
2292
2293 /* zero the stale file list, if any */
2294 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2295 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002296 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002297 }
2298
2299 while (fgets(linebuf, sizeof(linebuf), swl)) {
2300 char file_id[12+1];
2301 char file_version[80+1];
2302 struct file_list_entry *fle;
2303 static char dir[PATH_MAX];
2304
2305 if (strlen(linebuf) < 4)
2306 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002307
Harald Welte5e4d1b32009-02-01 13:36:56 +00002308 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2309 if (rc < 0) {
2310 perror("ERR parsing SWL file");
2311 rc = -EINVAL;
2312 goto out;
2313 }
2314 if (rc < 2)
2315 continue;
2316
Harald Welte470ec292009-06-26 20:25:23 +02002317 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002318 if (!fle) {
2319 rc = -ENOMEM;
2320 goto out;
2321 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002322
2323 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002324 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002325 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2326 strcat(fle->fname, "/");
2327 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002328
2329 llist_add_tail(&fle->list, &bs11_sw->file_list);
2330 }
2331
2332out:
2333 fclose(swl);
2334 return rc;
2335}
2336
2337/* bs11 swload specific callback, passed to abis_nm core swload */
2338static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2339 struct msgb *msg, void *data, void *param)
2340{
2341 struct abis_nm_bs11_sw *bs11_sw = data;
2342 struct file_list_entry *fle;
2343 int rc = 0;
2344
Harald Welte5e4d1b32009-02-01 13:36:56 +00002345 switch (event) {
2346 case NM_MT_LOAD_END_ACK:
2347 fle = fl_dequeue(&bs11_sw->file_list);
2348 if (fle) {
2349 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002350 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002351 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002352 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002353 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002354 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002355 } else {
2356 /* activate the SWL */
2357 rc = abis_nm_software_activate(bs11_sw->bts,
2358 bs11_sw->swl_fname,
2359 bs11_swload_cbfn,
2360 bs11_sw);
2361 }
2362 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002363 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002364 case NM_MT_LOAD_END_NACK:
2365 case NM_MT_LOAD_INIT_ACK:
2366 case NM_MT_LOAD_INIT_NACK:
2367 case NM_MT_ACTIVATE_SW_NACK:
2368 case NM_MT_ACTIVATE_SW_ACK:
2369 default:
2370 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002371 if (bs11_sw->user_cb)
2372 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002373 break;
2374 }
2375
2376 return rc;
2377}
2378
2379/* Siemens provides a SWL file that is a mere listing of all the other
2380 * files that are part of a software release. We need to upload first
2381 * the list file, and then each file that is listed in the list file */
2382int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002383 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002384{
2385 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2386 struct file_list_entry *fle;
2387 int rc = 0;
2388
2389 INIT_LLIST_HEAD(&bs11_sw->file_list);
2390 bs11_sw->bts = bts;
2391 bs11_sw->win_size = win_size;
2392 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002393 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002394
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002395 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002396 rc = bs11_read_swl_file(bs11_sw);
2397 if (rc < 0)
2398 return rc;
2399
2400 /* dequeue next item in file list */
2401 fle = fl_dequeue(&bs11_sw->file_list);
2402 if (!fle)
2403 return -EINVAL;
2404
2405 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002406 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002407 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002408 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002409 return rc;
2410}
2411
Harald Welte5083b0b2009-02-02 19:20:52 +00002412#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002413static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002414 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2415 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2416 NM_ATT_BS11_LMT_USER_NAME,
2417
2418 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2419
2420 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2421
2422 NM_ATT_BS11_SW_LOAD_STORED };
2423
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002424static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002425 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2426 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2427 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2428 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002429#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002430
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002431static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002432 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2433 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002434 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002435
2436int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2437{
2438 struct abis_om_hdr *oh;
2439 struct msgb *msg = nm_msgb_alloc();
2440
2441 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2442 /* SiemensHW CCTRL object */
2443 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2444 0x03, 0x00, 0x00);
2445 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2446
2447 return abis_nm_sendmsg(bts, msg);
2448}
Harald Welte268bb402009-02-01 19:11:56 +00002449
2450int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2451{
2452 struct abis_om_hdr *oh;
2453 struct msgb *msg = nm_msgb_alloc();
2454 struct bs11_date_time aet;
2455
2456 get_bs11_date_time(&aet);
2457 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2458 /* SiemensHW CCTRL object */
2459 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2460 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002461 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002462
2463 return abis_nm_sendmsg(bts, msg);
2464}
Harald Welte5c1e4582009-02-15 11:57:29 +00002465
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002466int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002467{
2468 struct abis_om_hdr *oh;
2469 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002470 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002471
2472 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2473 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2474 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2475 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2476
2477 return abis_nm_sendmsg(bts, msg);
2478}
2479
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002480int 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 +02002481{
2482 struct abis_om_hdr *oh;
2483 struct msgb *msg = nm_msgb_alloc();
2484 struct bs11_date_time aet;
2485
2486 get_bs11_date_time(&aet);
2487 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2488 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2489 bport, 0xff, 0x02);
2490 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2491
2492 return abis_nm_sendmsg(bts, msg);
2493}
2494
Harald Welte5c1e4582009-02-15 11:57:29 +00002495/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002496static const char ipaccess_magic[] = "com.ipaccess";
2497
Harald Welte677c21f2009-02-17 13:22:23 +00002498
2499static int abis_nm_rx_ipacc(struct msgb *msg)
2500{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002501 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002502 struct abis_om_hdr *oh = msgb_l2(msg);
2503 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002504 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002505 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002506 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002507 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002508
2509 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002510 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002511 return -EINVAL;
2512 }
2513
Harald Welte193fefc2009-04-30 15:16:27 +00002514 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002515 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002516
Harald Welte15c61722011-05-22 22:45:37 +02002517 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002518
Harald Welte746d6092009-10-19 22:11:11 +02002519 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002520
Harald Welte677c21f2009-02-17 13:22:23 +00002521 switch (foh->msg_type) {
2522 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002523 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002524 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2525 memcpy(&addr,
2526 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2527
2528 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2529 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002530 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002531 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002532 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002533 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002534 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2535 DEBUGPC(DNM, "STREAM=0x%02x ",
2536 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002537 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002538 break;
2539 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002540 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002541 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002542 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002543 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002544 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002545 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002546 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002547 case NM_MT_IPACC_SET_NVATTR_ACK:
2548 DEBUGPC(DNM, "SET NVATTR ACK\n");
2549 /* FIXME: decode and show the actual attributes */
2550 break;
2551 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002552 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002553 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002554 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002555 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002556 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002557 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002558 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002559 case NM_MT_IPACC_GET_NVATTR_ACK:
2560 DEBUGPC(DNM, "GET NVATTR ACK\n");
2561 /* FIXME: decode and show the actual attributes */
2562 break;
2563 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002564 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002565 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002566 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002567 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002568 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002569 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002570 break;
Harald Welte15c44172009-10-08 20:15:24 +02002571 case NM_MT_IPACC_SET_ATTR_ACK:
2572 DEBUGPC(DNM, "SET ATTR ACK\n");
2573 break;
2574 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002575 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002576 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002577 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002578 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002579 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002580 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002581 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002582 default:
2583 DEBUGPC(DNM, "unknown\n");
2584 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002585 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002586
2587 /* signal handling */
2588 switch (foh->msg_type) {
2589 case NM_MT_IPACC_RSL_CONNECT_NACK:
2590 case NM_MT_IPACC_SET_NVATTR_NACK:
2591 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002592 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 +01002593 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002594 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002595 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002596 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002597 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 +01002598 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002599 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002600 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002601 default:
2602 break;
2603 }
2604
Harald Welte677c21f2009-02-17 13:22:23 +00002605 return 0;
2606}
2607
Harald Welte193fefc2009-04-30 15:16:27 +00002608/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002609int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2610 uint8_t obj_class, uint8_t bts_nr,
2611 uint8_t trx_nr, uint8_t ts_nr,
2612 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002613{
2614 struct msgb *msg = nm_msgb_alloc();
2615 struct abis_om_hdr *oh;
2616 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002617 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002618
2619 /* construct the 12.21 OM header, observe the erroneous length */
2620 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2621 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2622 oh->mdisc = ABIS_OM_MDISC_MANUF;
2623
2624 /* add the ip.access magic */
2625 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2626 *data++ = sizeof(ipaccess_magic);
2627 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2628
2629 /* fill the 12.21 FOM header */
2630 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2631 foh->msg_type = msg_type;
2632 foh->obj_class = obj_class;
2633 foh->obj_inst.bts_nr = bts_nr;
2634 foh->obj_inst.trx_nr = trx_nr;
2635 foh->obj_inst.ts_nr = ts_nr;
2636
2637 if (attr && attr_len) {
2638 data = msgb_put(msg, attr_len);
2639 memcpy(data, attr, attr_len);
2640 }
2641
2642 return abis_nm_sendmsg(bts, msg);
2643}
Harald Welte677c21f2009-02-17 13:22:23 +00002644
Harald Welte193fefc2009-04-30 15:16:27 +00002645/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002646int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002647 int attr_len)
2648{
Harald Welte2ef156d2010-01-07 20:39:42 +01002649 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2650 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002651 attr_len);
2652}
2653
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002654int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002655 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002656{
2657 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002658 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002659 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2660 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2661
2662 int attr_len = sizeof(attr);
2663
2664 ia.s_addr = htonl(ip);
2665 attr[1] = stream;
2666 attr[3] = port >> 8;
2667 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002668 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002669
2670 /* if ip == 0, we use the default IP */
2671 if (ip == 0)
2672 attr_len -= 5;
2673
2674 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002675 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002676
2677 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2678 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2679 trx->nr, 0xff, attr, attr_len);
2680}
2681
Harald Welte193fefc2009-04-30 15:16:27 +00002682/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002683int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002684{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002685 struct abis_om_hdr *oh;
2686 struct msgb *msg = nm_msgb_alloc();
2687
2688 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2689 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2690 trx->bts->nr, trx->nr, 0xff);
2691
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002692 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002693}
Harald Weltedaef5212009-10-24 10:20:41 +02002694
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002695int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2696 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2697 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002698{
2699 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2700 obj_class, bts_nr, trx_nr, ts_nr,
2701 attr, attr_len);
2702}
Harald Welte0f255852009-11-12 14:48:42 +01002703
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002704void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002705{
2706 /* we simply reuse the GSM48 function and overwrite the RAC
2707 * with the Cell ID */
2708 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002709 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002710}
2711
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002712void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2713{
2714 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2715
Harald Welted64c0bc2011-05-30 12:07:53 +02002716 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002717 if (!trx->bts || !trx->bts->oml_link)
2718 return;
2719
2720 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2721 trx->bts->bts_nr, trx->nr, 0xff,
2722 new_state);
2723}
2724
Harald Welte92b1fe42010-03-25 11:45:30 +08002725static const struct value_string ipacc_testres_names[] = {
2726 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2727 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2728 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2729 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2730 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2731 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002732};
2733
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002734const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002735{
Harald Welte92b1fe42010-03-25 11:45:30 +08002736 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002737}
2738
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002739void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002740{
2741 cid->mcc = (buf[0] & 0xf) * 100;
2742 cid->mcc += (buf[0] >> 4) * 10;
2743 cid->mcc += (buf[1] & 0xf) * 1;
2744
2745 if (buf[1] >> 4 == 0xf) {
2746 cid->mnc = (buf[2] & 0xf) * 10;
2747 cid->mnc += (buf[2] >> 4) * 1;
2748 } else {
2749 cid->mnc = (buf[2] & 0xf) * 100;
2750 cid->mnc += (buf[2] >> 4) * 10;
2751 cid->mnc += (buf[1] >> 4) * 1;
2752 }
2753
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002754 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2755 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002756}
2757
Harald Welte0f255852009-11-12 14:48:42 +01002758/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002759int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002760{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002761 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002762 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002763
Harald Welteaf109b92010-07-22 18:14:36 +02002764 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002765
2766 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2767 return -EINVAL;
2768 cur++;
2769
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002770 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002771 cur += 2;
2772
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002773 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002774 cur += 2;
2775
2776 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2777 binf->freq_qual = *cur >> 2;
2778
Harald Welteaf109b92010-07-22 18:14:36 +02002779 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002780 binf->arfcn |= *cur++;
2781
2782 if (binf->info_type & IPAC_BINF_RXLEV)
2783 binf->rx_lev = *cur & 0x3f;
2784 cur++;
2785
2786 if (binf->info_type & IPAC_BINF_RXQUAL)
2787 binf->rx_qual = *cur & 0x7;
2788 cur++;
2789
2790 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002791 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002792 cur += 2;
2793
2794 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002795 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002796 cur += 2;
2797
2798 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002799 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002800 cur += 4;
2801
Harald Weltea780a3d2010-07-30 22:34:42 +02002802#if 0
2803 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002804 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002805#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002806 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002807 cur++;
2808
Harald Welteb40a38f2009-11-13 11:56:05 +01002809 ipac_parse_cgi(&binf->cgi, cur);
2810 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002811
2812 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2813 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2814 cur += sizeof(binf->ba_list_si2);
2815 }
2816
2817 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2818 memcpy(binf->ba_list_si2bis, cur,
2819 sizeof(binf->ba_list_si2bis));
2820 cur += sizeof(binf->ba_list_si2bis);
2821 }
2822
2823 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2824 memcpy(binf->ba_list_si2ter, cur,
2825 sizeof(binf->ba_list_si2ter));
2826 cur += sizeof(binf->ba_list_si2ter);
2827 }
2828
2829 return 0;
2830}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002831
2832void abis_nm_clear_queue(struct gsm_bts *bts)
2833{
2834 struct msgb *msg;
2835
2836 while (!llist_empty(&bts->abis_queue)) {
2837 msg = msgb_dequeue(&bts->abis_queue);
2838 msgb_free(msg);
2839 }
2840
2841 bts->abis_nm_pend = 0;
2842}