blob: 5212f6a40ba64cc49fd8c991b0c2b4a4002fac73 [file] [log] [blame]
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte59b04682009-06-10 05:40:52 +08002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-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 Welte59b04682009-06-10 05:40:52 +080011 * (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 Welte0e3e88e2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080017 *
Harald Welte0e3e88e2011-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 Welte59b04682009-06-10 05:40:52 +080020 *
21 */
22
23
24#include <errno.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30#include <time.h>
31#include <limits.h>
32
Harald Welte59b04682009-06-10 05:40:52 +080033#include <sys/stat.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
Max5a9d8bc2017-01-11 11:51:28 +010040#include <osmocom/gsm/protocol/gsm_12_21.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010041#include <osmocom/gsm/tlv.h>
Harald Weltec61a90e2011-05-22 22:45:37 +020042#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010043#include <osmocom/core/talloc.h>
Neels Hofmeyr5644c2b2017-01-13 03:12:08 +010044#include <osmocom/core/utils.h>
Harald Welte59b04682009-06-10 05:40:52 +080045#include <openbsc/abis_nm.h>
46#include <openbsc/misdn.h>
47#include <openbsc/signal.h>
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +020048#include <osmocom/abis/e1_input.h>
Harald Welte59b04682009-06-10 05:40:52 +080049
50#define OM_ALLOC_SIZE 1024
51#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010052#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080053
Holger Hans Peter Freyther7eb8a9a2011-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 Welte59b04682009-06-10 05:40:52 +080055{
Harald Welte59698fb2010-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 Welte59b04682009-06-10 05:40:52 +080059}
60
61static 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
73#if 0
74/* 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}
79#endif
80
81/* is this msgtype a report ? */
82static int is_report(enum abis_nm_msgtype mt)
83{
Harald Weltec61a90e2011-05-22 22:45:37 +020084 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte59b04682009-06-10 05:40:52 +080085}
86
87#define MT_ACK(x) (x+1)
88#define MT_NACK(x) (x+2)
89
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020090static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte59b04682009-06-10 05:40:52 +080091{
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 Freytherffd0f222014-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 Freyther7eb8a9a2011-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 Welte59b04682009-06-10 05:40:52 +0800101{
102 struct abis_om_fom_hdr *foh =
103 (struct abis_om_fom_hdr *) oh->data;
104
105 fill_om_hdr(oh, len+sizeof(*foh));
106 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 Freytherffd0f222014-04-04 12:56:34 +0200111 return foh;
Harald Welte59b04682009-06-10 05:40:52 +0800112}
113
114static struct msgb *nm_msgb_alloc(void)
115{
Harald Welte9cfc9352009-06-26 19:39:35 +0200116 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
117 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800118}
119
Harald Welte607044f2011-09-26 23:43:23 +0200120int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200121{
Pablo Neira Ayuso42e41df2011-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 Ayuso42e41df2011-08-17 22:44:07 +0200129 return abis_sendmsg(msg);
130}
131
Harald Welte59b04682009-06-10 05:40:52 +0800132/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100133static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800134{
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200135 msg->dst = bts->oml_link;
Harald Welte59b04682009-06-10 05:40:52 +0800136
Holger Hans Peter Freyther2a6bffe2010-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 Welte607044f2011-09-26 23:43:23 +0200140 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-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 Welte59b04682009-06-10 05:40:52 +0800158}
159
160static int abis_nm_rcvmsg_sw(struct msgb *mb);
161
Sylvain Munautca3e04f2010-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 Welte59b04682009-06-10 05:40:52 +0800169/* 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 Freyther7eb8a9a2011-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 Welte59b04682009-06-10 05:40:52 +0800173{
174 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100175 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800176
Harald Weltea348c082011-03-06 21:20:38 +0100177 memset(&nsd, 0, sizeof(nsd));
178
Harald Weltec6ed9282011-06-06 18:31:20 +0200179 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100180 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100181 return -EINVAL;
Harald Weltec6ed9282011-06-06 18:31:20 +0200182 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800183 if (!nm_state)
184 return -1;
185
186 new_state = *nm_state;
187 new_state.administrative = adm_state;
188
Harald Welteb03c4482011-03-06 22:11:32 +0100189 nsd.bts = bts;
Harald Welte4c826f72011-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 Ayusoef717c62011-05-06 12:12:31 +0200194 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800195
196 nm_state->administrative = adm_state;
197
Harald Welte4c826f72011-01-14 15:55:42 +0100198 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800199}
200
201static int abis_nm_rx_statechg_rep(struct msgb *mb)
202{
203 struct abis_om_hdr *oh = msgb_l2(mb);
204 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200205 struct e1inp_sign_link *sign_link = mb->dst;
206 struct gsm_bts *bts = sign_link->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +0800207 struct tlv_parsed tp;
208 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800209
210 DEBUGPC(DNM, "STATE CHG: ");
211
212 memset(&new_state, 0, sizeof(new_state));
213
Harald Weltec6ed9282011-06-06 18:31:20 +0200214 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800215 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100216 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800217 return -EINVAL;
218 }
219
220 new_state = *nm_state;
221
Harald Welte59698fb2010-01-10 18:01:52 +0100222 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800223 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
224 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200225 DEBUGPC(DNM, "OP_STATE=%s ",
226 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800227 }
228 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
229 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 Weltec61a90e2011-05-22 22:45:37 +0200233 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
234 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800235 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100236 } else
237 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800238 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
239 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200240 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200241 get_value_string(abis_nm_adm_state_names,
242 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800243 }
244 DEBUGPC(DNM, "\n");
245
Holger Hans Peter Freyther677bb2f2009-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 Welte59b04682009-06-10 05:40:52 +0800249 /* Update the operational state of a given object in our in-memory data
250 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100251 struct nm_statechg_signal_data nsd;
Harald Weltec6ed9282011-06-06 18:31:20 +0200252 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Welte4c826f72011-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 Welteb03c4482011-03-06 22:11:32 +0100257 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200258 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-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 Welte59b04682009-06-10 05:40:52 +0800263 }
264#if 0
265 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 }
272#endif
273 return 0;
274}
275
Maxab4b1502017-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
Maxc9f43c12017-04-10 16:47:17 +0200305static inline void handle_manufact_report(struct gsm_bts *bts, const uint8_t *p_val, const char *type,
Maxab4b1502017-03-15 14:30:21 +0100306 const char *severity, const char *text)
307{
308 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
309
310 switch (cause) {
311 case OSMO_EVT_PCU_VERS:
Maxc9f43c12017-04-10 16:47:17 +0200312 if (text) {
313 LOGPC(DNM, LOGL_NOTICE, "BTS %u reported connected PCU version %s\n", bts->nr, text);
314 osmo_strlcpy(bts->pcu_version, text, sizeof(bts->pcu_version));
315 } else {
316 LOGPC(DNM, LOGL_ERROR, "BTS %u reported PCU disconnection.\n", bts->nr);
317 bts->pcu_version[0] = '\0';
318 }
Maxab4b1502017-03-15 14:30:21 +0100319 break;
320 default:
321 log_oml_fail_rep(bts, type, severity, p_val, text);
322 };
323}
324
Maxc9f43c12017-04-10 16:47:17 +0200325static int rx_fail_evt_rep(struct msgb *mb, struct gsm_bts *bts)
Harald Welte59b04682009-06-10 05:40:52 +0800326{
327 struct abis_om_hdr *oh = msgb_l2(mb);
328 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200329 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800330 struct tlv_parsed tp;
Maxab4b1502017-03-15 14:30:21 +0100331 int rc = 0;
332 const uint8_t *p_val = NULL;
333 char *p_text = NULL;
334 const char *e_type = NULL, *severity = NULL;
Harald Welte59b04682009-06-10 05:40:52 +0800335
Maxab4b1502017-03-15 14:30:21 +0100336 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data,
337 oh->length-sizeof(*foh));
Max5a9d8bc2017-01-11 11:51:28 +0100338
Dieter Spaarf5888a72011-02-18 11:06:51 +0100339 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
340 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
Maxab4b1502017-03-15 14:30:21 +0100341 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val,
342 TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100343 }
Harald Welte59b04682009-06-10 05:40:52 +0800344
Maxab4b1502017-03-15 14:30:21 +0100345 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
346 e_type = abis_nm_event_type_name(*TLVP_VAL(&tp,
347 NM_ATT_EVENT_TYPE));
Harald Welte59b04682009-06-10 05:40:52 +0800348
Maxab4b1502017-03-15 14:30:21 +0100349 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
350 severity = abis_nm_severity_name(*TLVP_VAL(&tp,
351 NM_ATT_SEVERITY));
352
353 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
354 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
355
356 switch (p_val[0]) {
357 case NM_PCAUSE_T_MANUF:
358 handle_manufact_report(bts, p_val, e_type, severity,
359 p_text);
360 break;
361 default:
362 log_oml_fail_rep(bts, e_type, severity, p_val, p_text);
363 };
364 } else {
365 LOGPC(DNM, LOGL_ERROR, "BTS%u: Failure Event Report without "
366 "Probable Cause?!\n", bts->nr);
367 rc = -EINVAL;
368 }
369
370 if (p_text)
371 talloc_free(p_text);
372
373 return rc;
Harald Welte59b04682009-06-10 05:40:52 +0800374}
375
Maxab4b1502017-03-15 14:30:21 +0100376static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts)
Harald Welte59b04682009-06-10 05:40:52 +0800377{
378 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200379 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800380
Harald Weltec61a90e2011-05-22 22:45:37 +0200381 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800382
383 //nmh->cfg->report_cb(mb, foh);
384
385 switch (mt) {
386 case NM_MT_STATECHG_EVENT_REP:
387 return abis_nm_rx_statechg_rep(mb);
388 break;
389 case NM_MT_SW_ACTIVATED_REP:
390 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200391 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800392 break;
393 case NM_MT_FAILURE_EVENT_REP:
Maxab4b1502017-03-15 14:30:21 +0100394 rx_fail_evt_rep(mb, bts);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200395 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800396 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200397 case NM_MT_TEST_REP:
398 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200399 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200400 break;
Harald Welte59b04682009-06-10 05:40:52 +0800401 default:
402 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
403 break;
404
405 };
406
407 return 0;
408}
409
410/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200411static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
Max82df6912017-03-24 21:04:57 +0100412 uint8_t i2, const struct abis_nm_sw_desc *sw_desc)
Harald Welte59b04682009-06-10 05:40:52 +0800413{
414 struct abis_om_hdr *oh;
415 struct msgb *msg = nm_msgb_alloc();
Max82df6912017-03-24 21:04:57 +0100416 uint16_t len = abis_nm_sw_desc_len(sw_desc, true);
Harald Welte59b04682009-06-10 05:40:52 +0800417
418 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
419 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
Max82df6912017-03-24 21:04:57 +0100420 abis_nm_put_sw_desc(msg, sw_desc, true);
Harald Welte59b04682009-06-10 05:40:52 +0800421
422 return abis_nm_sendmsg(bts, msg);
423}
424
Max82df6912017-03-24 21:04:57 +0100425int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw_descr,
426 const size_t size)
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100427{
428 int res = 0;
429 int i;
430
431 for (i = 1; i < size; ++i) {
Max82df6912017-03-24 21:04:57 +0100432 if (memcmp(sw_descr[res].file_version, sw_descr[i].file_version,
433 OSMO_MIN(sw_descr[i].file_version_len,
434 sw_descr[res].file_version_len)) < 0) {
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100435 res = i;
436 }
437 }
438
439 return res;
440}
441
Maxc81178a2017-05-10 12:21:17 +0200442/* 3GPP TS 52.021 §6.2.5 */
Harald Welte59b04682009-06-10 05:40:52 +0800443static int abis_nm_rx_sw_act_req(struct msgb *mb)
444{
445 struct abis_om_hdr *oh = msgb_l2(mb);
446 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200447 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200448 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200449 const uint8_t *sw_config;
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100450 int ret, sw_config_len, len;
Maxc81178a2017-05-10 12:21:17 +0200451 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
Harald Welte59b04682009-06-10 05:40:52 +0800452
Harald Weltec61a90e2011-05-22 22:45:37 +0200453 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200454
455 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800456
Harald Welte3055e332010-03-14 15:37:43 +0800457 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800458
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200459 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800460 foh->obj_inst.bts_nr,
461 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800462 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800463 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100464 if (ret != 0) {
465 LOGP(DNM, LOGL_ERROR,
466 "Sending SW ActReq ACK failed: %d\n", ret);
467 return ret;
468 }
Harald Welte59b04682009-06-10 05:40:52 +0800469
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200470 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200471 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
472 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
473 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100474 LOGP(DNM, LOGL_ERROR,
475 "SW config not found! Can't continue.\n");
Mike Haben322fc582009-10-01 14:56:13 +0200476 return -EINVAL;
477 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200478 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200479 }
480
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100481 /* Parse up to two sw descriptions from the data */
Max82df6912017-03-24 21:04:57 +0100482 len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
483 ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100484 if (len <= 0) {
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100485 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100486 return -EINVAL;
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100487 }
Mike Haben322fc582009-10-01 14:56:13 +0200488
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100489 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
490 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
491
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200492 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800493 foh->obj_inst.bts_nr,
494 foh->obj_inst.trx_nr,
495 foh->obj_inst.ts_nr,
Max82df6912017-03-24 21:04:57 +0100496 &sw_descr[ret]);
Harald Welte59b04682009-06-10 05:40:52 +0800497}
498
499/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
500static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
501{
502 struct abis_om_hdr *oh = msgb_l2(mb);
503 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200504 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800505 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200506 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800507
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200508 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800509 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
510 return -EINVAL;
511
512 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
513
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200514 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800515}
516
517static int abis_nm_rx_lmt_event(struct msgb *mb)
518{
519 struct abis_om_hdr *oh = msgb_l2(mb);
520 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200521 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800522 struct tlv_parsed tp;
523
524 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200525 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800526 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
527 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200528 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800529 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
530 }
531 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
532 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200533 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800534 DEBUGPC(DNM, "Level=%u ", level);
535 }
536 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
537 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
538 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
539 DEBUGPC(DNM, "Username=%s ", name);
540 }
541 DEBUGPC(DNM, "\n");
542 /* FIXME: parse LMT LOGON TIME */
543 return 0;
544}
545
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200546void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100547{
548 int wait = 0;
549 struct msgb *msg;
550 /* the queue is empty */
551 while (!llist_empty(&bts->abis_queue)) {
552 msg = msgb_dequeue(&bts->abis_queue);
553 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200554 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100555
556 if (wait)
557 break;
558 }
559
560 bts->abis_nm_pend = wait;
561}
562
Harald Welte59b04682009-06-10 05:40:52 +0800563/* Receive a OML NM Message from BTS */
564static int abis_nm_rcvmsg_fom(struct msgb *mb)
565{
566 struct abis_om_hdr *oh = msgb_l2(mb);
567 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200568 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200569 uint8_t mt = foh->msg_type;
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100570 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
571 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100572 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800573
574 /* check for unsolicited message */
575 if (is_report(mt))
Maxab4b1502017-03-15 14:30:21 +0100576 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte59b04682009-06-10 05:40:52 +0800577
Harald Weltec61a90e2011-05-22 22:45:37 +0200578 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800579 return abis_nm_rcvmsg_sw(mb);
580
Harald Weltec61a90e2011-05-22 22:45:37 +0200581 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800582 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800583 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200584
Harald Weltec61a90e2011-05-22 22:45:37 +0200585 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200586
Harald Weltec61a90e2011-05-22 22:45:37 +0200587 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800588
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100589 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800590 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200591 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200592 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800593 else
594 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200595
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800596 nack_data.msg = mb;
597 nack_data.mt = mt;
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100598 nack_data.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200599 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100600 abis_nm_queue_send_next(bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200601 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800602 }
603#if 0
604 /* check if last message is to be acked */
605 if (is_ack_nack(nmh->last_msgtype)) {
606 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100607 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800608 /* we got our ACK, continue sending the next msg */
609 } else if (mt == MT_NACK(nmh->last_msgtype)) {
610 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100611 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800612 /* FIXME: somehow signal this to the caller */
613 } else {
614 /* really strange things happen */
615 return -EINVAL;
616 }
617 }
618#endif
619
620 switch (mt) {
621 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100622 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800623 break;
624 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100625 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800626 break;
627 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100628 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800629 break;
Max7efc2632017-04-04 19:21:24 +0200630 case NM_MT_OPSTART_ACK:
631 abis_nm_debugp_foh(DNM, foh);
632 DEBUGPC(DNM, "Opstart ACK\n");
633 break;
634 case NM_MT_SET_CHAN_ATTR_ACK:
635 abis_nm_debugp_foh(DNM, foh);
636 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
637 break;
638 case NM_MT_SET_RADIO_ATTR_ACK:
639 abis_nm_debugp_foh(DNM, foh);
640 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
641 break;
Harald Welte204317e2009-08-06 17:58:31 +0200642 case NM_MT_CONN_MDROP_LINK_ACK:
Max7efc2632017-04-04 19:21:24 +0200643 abis_nm_debugp_foh(DNM, foh);
644 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte204317e2009-08-06 17:58:31 +0200645 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100646 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200647 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100648 break;
649 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200650 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100651 break;
Harald Welte08011e22011-03-04 13:41:31 +0100652 case NM_MT_SET_BTS_ATTR_ACK:
Harald Welte08011e22011-03-04 13:41:31 +0100653 break;
Max7efc2632017-04-04 19:21:24 +0200654 default:
655 abis_nm_debugp_foh(DNM, foh);
656 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
657 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +0800658 }
659
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100660 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100661 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800662}
663
664static int abis_nm_rx_ipacc(struct msgb *mb);
665
666static int abis_nm_rcvmsg_manuf(struct msgb *mb)
667{
668 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200669 struct e1inp_sign_link *sign_link = mb->dst;
670 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800671
672 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100673 case GSM_BTS_TYPE_NANOBTS:
Maxabf3eb12017-03-23 12:01:07 +0100674 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte59b04682009-06-10 05:40:52 +0800675 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200676 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800677 break;
678 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100679 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
680 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800681 rc = 0;
682 break;
683 }
684
685 return rc;
686}
687
688/* High-Level API */
689/* Entry-point where L2 OML from BTS enters the NM code */
690int abis_nm_rcvmsg(struct msgb *msg)
691{
692 struct abis_om_hdr *oh = msgb_l2(msg);
693 int rc = 0;
694
695 /* Various consistency checks */
696 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100697 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800698 oh->placement);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200699 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
700 rc = -EINVAL;
701 goto err;
702 }
Harald Welte59b04682009-06-10 05:40:52 +0800703 }
704 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100705 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800706 oh->sequence);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200707 rc = -EINVAL;
708 goto err;
Harald Welte59b04682009-06-10 05:40:52 +0800709 }
710#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200711 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800712 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
713 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100714 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800715 oh->length + sizeof(*oh), l2_len);
716 return -EINVAL;
717 }
718 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100719 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 Welte59b04682009-06-10 05:40:52 +0800720#endif
721 msg->l3h = (unsigned char *)oh + sizeof(*oh);
722
723 switch (oh->mdisc) {
724 case ABIS_OM_MDISC_FOM:
725 rc = abis_nm_rcvmsg_fom(msg);
726 break;
727 case ABIS_OM_MDISC_MANUF:
728 rc = abis_nm_rcvmsg_manuf(msg);
729 break;
730 case ABIS_OM_MDISC_MMI:
731 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100732 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800733 oh->mdisc);
734 break;
735 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100736 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800737 oh->mdisc);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200738 rc = -EINVAL;
739 break;
Harald Welte59b04682009-06-10 05:40:52 +0800740 }
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200741err:
Harald Welte59b04682009-06-10 05:40:52 +0800742 msgb_free(msg);
743 return rc;
744}
745
746#if 0
747/* initialized all resources */
748struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
749{
750 struct abis_nm_h *nmh;
751
752 nmh = malloc(sizeof(*nmh));
753 if (!nmh)
754 return NULL;
755
756 nmh->cfg = cfg;
757
758 return nmh;
759}
760
761/* free all resources */
762void abis_nm_fini(struct abis_nm_h *nmh)
763{
764 free(nmh);
765}
766#endif
767
768/* Here we are trying to define a high-level API that can be used by
769 * the actual BSC implementation. However, the architecture is currently
770 * still under design. Ideally the calls to this API would be synchronous,
771 * while the underlying stack behind the APi runs in a traditional select
772 * based state machine.
773 */
774
775/* 6.2 Software Load: */
776enum sw_state {
777 SW_STATE_NONE,
778 SW_STATE_WAIT_INITACK,
779 SW_STATE_WAIT_SEGACK,
780 SW_STATE_WAIT_ENDACK,
781 SW_STATE_WAIT_ACTACK,
782 SW_STATE_ERROR,
783};
784
785struct abis_nm_sw {
786 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800787 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800788 gsm_cbfn *cbfn;
789 void *cb_data;
790 int forced;
791
792 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200793 uint8_t obj_class;
794 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800795
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200796 uint8_t file_id[255];
797 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800798
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200799 uint8_t file_version[255];
800 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800801
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200802 uint8_t window_size;
803 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800804
805 int fd;
806 FILE *stream;
807 enum sw_state state;
808 int last_seg;
809};
810
811static struct abis_nm_sw g_sw;
812
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100813static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
814{
815 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
816 msgb_v_put(msg, NM_ATT_SW_DESCR);
817 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
818 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
819 sw->file_version);
820 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
821 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
822 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
823 sw->file_version);
824 } else {
825 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
826 }
827}
828
Harald Welte59b04682009-06-10 05:40:52 +0800829/* 6.2.1 / 8.3.1: Load Data Initiate */
830static int sw_load_init(struct abis_nm_sw *sw)
831{
832 struct abis_om_hdr *oh;
833 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200834 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800835
836 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
837 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
838 sw->obj_instance[0], sw->obj_instance[1],
839 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100840
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100841 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800842 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
843
844 return abis_nm_sendmsg(sw->bts, msg);
845}
846
847static int is_last_line(FILE *stream)
848{
849 char next_seg_buf[256];
850 long pos;
851
852 /* check if we're sending the last line */
853 pos = ftell(stream);
Holger Hans Peter Freyther4c11d0b2014-04-04 11:48:32 +0200854
855 /* Did ftell fail? Then we are at the end for sure */
856 if (pos < 0)
857 return 1;
858
Harald Welte59b04682009-06-10 05:40:52 +0800859 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltead13b572016-11-26 14:11:16 +0100860 int rc = fseek(stream, pos, SEEK_SET);
861 if (rc < 0)
862 return rc;
Harald Welte59b04682009-06-10 05:40:52 +0800863 return 1;
864 }
865
866 fseek(stream, pos, SEEK_SET);
867 return 0;
868}
869
870/* 6.2.2 / 8.3.2 Load Data Segment */
871static int sw_load_segment(struct abis_nm_sw *sw)
872{
873 struct abis_om_hdr *oh;
874 struct msgb *msg = nm_msgb_alloc();
875 char seg_buf[256];
876 char *line_buf = seg_buf+2;
877 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +0200878 int len;
Harald Welte59b04682009-06-10 05:40:52 +0800879
880 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
881
882 switch (sw->bts->type) {
883 case GSM_BTS_TYPE_BS11:
884 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
885 perror("fgets reading segment");
886 return -EINVAL;
887 }
888 seg_buf[0] = 0x00;
889
890 /* check if we're sending the last line */
891 sw->last_seg = is_last_line(sw->stream);
892 if (sw->last_seg)
893 seg_buf[1] = 0;
894 else
895 seg_buf[1] = 1 + sw->seg_in_window++;
896
897 len = strlen(line_buf) + 2;
898 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200899 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800900 /* BS11 wants CR + LF in excess of the TLV length !?! */
901 tlv[1] -= 2;
902
903 /* we only now know the exact length for the OM hdr */
904 len = strlen(line_buf)+2;
905 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100906 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200907 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100908 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
909 if (len < 0) {
910 perror("read failed");
911 return -EINVAL;
912 }
913
914 if (len != IPACC_SEGMENT_SIZE)
915 sw->last_seg = 1;
916
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100917 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200918 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100919 len += 3;
920 break;
921 }
Harald Welte59b04682009-06-10 05:40:52 +0800922 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100923 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800924 /* FIXME: Other BTS types */
925 return -1;
926 }
927
928 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
929 sw->obj_instance[0], sw->obj_instance[1],
930 sw->obj_instance[2]);
931
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100932 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800933}
934
935/* 6.2.4 / 8.3.4 Load Data End */
936static int sw_load_end(struct abis_nm_sw *sw)
937{
938 struct abis_om_hdr *oh;
939 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200940 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800941
942 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
943 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
944 sw->obj_instance[0], sw->obj_instance[1],
945 sw->obj_instance[2]);
946
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100947 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800948 return abis_nm_sendmsg(sw->bts, msg);
949}
950
951/* Activate the specified software into the BTS */
952static int sw_activate(struct abis_nm_sw *sw)
953{
954 struct abis_om_hdr *oh;
955 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200956 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800957
958 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
959 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
960 sw->obj_instance[0], sw->obj_instance[1],
961 sw->obj_instance[2]);
962
963 /* FIXME: this is BS11 specific format */
964 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
965 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
966 sw->file_version);
967
968 return abis_nm_sendmsg(sw->bts, msg);
969}
970
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100971struct sdp_firmware {
972 char magic[4];
973 char more_magic[4];
974 unsigned int header_length;
975 unsigned int file_length;
976} __attribute__ ((packed));
977
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100978static int parse_sdp_header(struct abis_nm_sw *sw)
979{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100980 struct sdp_firmware firmware_header;
981 int rc;
982 struct stat stat;
983
984 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
985 if (rc != sizeof(firmware_header)) {
986 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
987 return -1;
988 }
989
990 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
991 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
992 return -1;
993 }
994
995 if (firmware_header.more_magic[0] != 0x10 ||
996 firmware_header.more_magic[1] != 0x02 ||
997 firmware_header.more_magic[2] != 0x00 ||
998 firmware_header.more_magic[3] != 0x00) {
999 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1000 return -1;
1001 }
1002
1003
1004 if (fstat(sw->fd, &stat) == -1) {
1005 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1006 return -1;
1007 }
1008
1009 if (ntohl(firmware_header.file_length) != stat.st_size) {
1010 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1011 return -1;
1012 }
1013
1014 /* go back to the start as we checked the whole filesize.. */
1015 lseek(sw->fd, 0l, SEEK_SET);
1016 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1017 "There might be checksums in the file that are not\n"
1018 "verified and incomplete firmware might be flashed.\n"
1019 "There is absolutely no WARRANTY that flashing will\n"
1020 "work.\n");
1021 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001022}
1023
Harald Welte59b04682009-06-10 05:40:52 +08001024static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1025{
1026 char file_id[12+1];
1027 char file_version[80+1];
1028 int rc;
1029
1030 sw->fd = open(fname, O_RDONLY);
1031 if (sw->fd < 0)
1032 return sw->fd;
1033
1034 switch (sw->bts->type) {
1035 case GSM_BTS_TYPE_BS11:
1036 sw->stream = fdopen(sw->fd, "r");
1037 if (!sw->stream) {
1038 perror("fdopen");
1039 return -1;
1040 }
1041 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001042 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001043 file_id, file_version);
1044 if (rc != 2) {
1045 perror("parsing header line of software file");
1046 return -1;
1047 }
1048 strcpy((char *)sw->file_id, file_id);
1049 sw->file_id_len = strlen(file_id);
1050 strcpy((char *)sw->file_version, file_version);
1051 sw->file_version_len = strlen(file_version);
1052 /* rewind to start of file */
1053 rewind(sw->stream);
1054 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001055 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001056 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001057 rc = parse_sdp_header(sw);
1058 if (rc < 0) {
1059 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1060 return -1;
1061 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001062
1063 strcpy((char *)sw->file_id, "id");
1064 sw->file_id_len = 3;
1065 strcpy((char *)sw->file_version, "version");
1066 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001067 break;
Harald Welte59b04682009-06-10 05:40:52 +08001068 default:
1069 /* We don't know how to treat them yet */
1070 close(sw->fd);
1071 return -EINVAL;
1072 }
1073
1074 return 0;
1075}
1076
1077static void sw_close_file(struct abis_nm_sw *sw)
1078{
1079 switch (sw->bts->type) {
1080 case GSM_BTS_TYPE_BS11:
1081 fclose(sw->stream);
1082 break;
1083 default:
1084 close(sw->fd);
1085 break;
1086 }
1087}
1088
1089/* Fill the window */
1090static int sw_fill_window(struct abis_nm_sw *sw)
1091{
1092 int rc;
1093
1094 while (sw->seg_in_window < sw->window_size) {
1095 rc = sw_load_segment(sw);
1096 if (rc < 0)
1097 return rc;
1098 if (sw->last_seg)
1099 break;
1100 }
1101 return 0;
1102}
1103
1104/* callback function from abis_nm_rcvmsg() handler */
1105static int abis_nm_rcvmsg_sw(struct msgb *mb)
1106{
1107 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001108 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001109 int rc = -1;
1110 struct abis_nm_sw *sw = &g_sw;
1111 enum sw_state old_state = sw->state;
1112
1113 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1114
1115 switch (sw->state) {
1116 case SW_STATE_WAIT_INITACK:
1117 switch (foh->msg_type) {
1118 case NM_MT_LOAD_INIT_ACK:
1119 /* fill window with segments */
1120 if (sw->cbfn)
1121 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1122 NM_MT_LOAD_INIT_ACK, mb,
1123 sw->cb_data, NULL);
1124 rc = sw_fill_window(sw);
1125 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001126 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001127 break;
1128 case NM_MT_LOAD_INIT_NACK:
1129 if (sw->forced) {
1130 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1131 "Init NACK\n");
1132 if (sw->cbfn)
1133 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1134 NM_MT_LOAD_INIT_ACK, mb,
1135 sw->cb_data, NULL);
1136 rc = sw_fill_window(sw);
1137 sw->state = SW_STATE_WAIT_SEGACK;
1138 } else {
1139 DEBUGP(DNM, "Software Load Init NACK\n");
1140 /* FIXME: cause */
1141 if (sw->cbfn)
1142 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1143 NM_MT_LOAD_INIT_NACK, mb,
1144 sw->cb_data, NULL);
1145 sw->state = SW_STATE_ERROR;
1146 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001147 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001148 break;
1149 }
1150 break;
1151 case SW_STATE_WAIT_SEGACK:
1152 switch (foh->msg_type) {
1153 case NM_MT_LOAD_SEG_ACK:
1154 if (sw->cbfn)
1155 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1156 NM_MT_LOAD_SEG_ACK, mb,
1157 sw->cb_data, NULL);
1158 sw->seg_in_window = 0;
1159 if (!sw->last_seg) {
1160 /* fill window with more segments */
1161 rc = sw_fill_window(sw);
1162 sw->state = SW_STATE_WAIT_SEGACK;
1163 } else {
1164 /* end the transfer */
1165 sw->state = SW_STATE_WAIT_ENDACK;
1166 rc = sw_load_end(sw);
1167 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001168 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001169 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001170 case NM_MT_LOAD_ABORT:
1171 if (sw->cbfn)
1172 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1173 NM_MT_LOAD_ABORT, mb,
1174 sw->cb_data, NULL);
1175 break;
Harald Welte59b04682009-06-10 05:40:52 +08001176 }
1177 break;
1178 case SW_STATE_WAIT_ENDACK:
1179 switch (foh->msg_type) {
1180 case NM_MT_LOAD_END_ACK:
1181 sw_close_file(sw);
1182 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1183 sw->bts->nr);
1184 sw->state = SW_STATE_NONE;
1185 if (sw->cbfn)
1186 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1187 NM_MT_LOAD_END_ACK, mb,
1188 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001189 rc = 0;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001190 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001191 break;
1192 case NM_MT_LOAD_END_NACK:
1193 if (sw->forced) {
1194 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1195 "End NACK\n");
1196 sw->state = SW_STATE_NONE;
1197 if (sw->cbfn)
1198 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1199 NM_MT_LOAD_END_ACK, mb,
1200 sw->cb_data, NULL);
1201 } else {
1202 DEBUGP(DNM, "Software Load End NACK\n");
1203 /* FIXME: cause */
1204 sw->state = SW_STATE_ERROR;
1205 if (sw->cbfn)
1206 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1207 NM_MT_LOAD_END_NACK, mb,
1208 sw->cb_data, NULL);
1209 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001210 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001211 break;
1212 }
1213 case SW_STATE_WAIT_ACTACK:
1214 switch (foh->msg_type) {
1215 case NM_MT_ACTIVATE_SW_ACK:
1216 /* we're done */
1217 DEBUGP(DNM, "Activate Software DONE!\n");
1218 sw->state = SW_STATE_NONE;
1219 rc = 0;
1220 if (sw->cbfn)
1221 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1222 NM_MT_ACTIVATE_SW_ACK, mb,
1223 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001224 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001225 break;
1226 case NM_MT_ACTIVATE_SW_NACK:
1227 DEBUGP(DNM, "Activate Software NACK\n");
1228 /* FIXME: cause */
1229 sw->state = SW_STATE_ERROR;
1230 if (sw->cbfn)
1231 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1232 NM_MT_ACTIVATE_SW_NACK, mb,
1233 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001234 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001235 break;
1236 }
1237 case SW_STATE_NONE:
1238 switch (foh->msg_type) {
1239 case NM_MT_ACTIVATE_SW_ACK:
1240 rc = 0;
1241 break;
1242 }
1243 break;
1244 case SW_STATE_ERROR:
1245 break;
1246 }
1247
1248 if (rc)
1249 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1250 foh->msg_type, old_state, sw->state);
1251
1252 return rc;
1253}
1254
1255/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001256int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001257 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001258 gsm_cbfn *cbfn, void *cb_data)
1259{
1260 struct abis_nm_sw *sw = &g_sw;
1261 int rc;
1262
1263 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1264 bts->nr, fname);
1265
1266 if (sw->state != SW_STATE_NONE)
1267 return -EBUSY;
1268
1269 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001270 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001271
1272 switch (bts->type) {
1273 case GSM_BTS_TYPE_BS11:
1274 sw->obj_class = NM_OC_SITE_MANAGER;
1275 sw->obj_instance[0] = 0xff;
1276 sw->obj_instance[1] = 0xff;
1277 sw->obj_instance[2] = 0xff;
1278 break;
1279 case GSM_BTS_TYPE_NANOBTS:
1280 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001281 sw->obj_instance[0] = sw->bts->nr;
1282 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001283 sw->obj_instance[2] = 0xff;
1284 break;
1285 case GSM_BTS_TYPE_UNKNOWN:
1286 default:
1287 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1288 return -1;
1289 break;
1290 }
Harald Welte59b04682009-06-10 05:40:52 +08001291 sw->window_size = win_size;
1292 sw->state = SW_STATE_WAIT_INITACK;
1293 sw->cbfn = cbfn;
1294 sw->cb_data = cb_data;
1295 sw->forced = forced;
1296
1297 rc = sw_open_file(sw, fname);
1298 if (rc < 0) {
1299 sw->state = SW_STATE_NONE;
1300 return rc;
1301 }
1302
1303 return sw_load_init(sw);
1304}
1305
1306int abis_nm_software_load_status(struct gsm_bts *bts)
1307{
1308 struct abis_nm_sw *sw = &g_sw;
1309 struct stat st;
1310 int rc, percent;
1311
1312 rc = fstat(sw->fd, &st);
1313 if (rc < 0) {
1314 perror("ERROR during stat");
1315 return rc;
1316 }
1317
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001318 if (sw->stream)
1319 percent = (ftell(sw->stream) * 100) / st.st_size;
1320 else
1321 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001322 return percent;
1323}
1324
1325/* Activate the specified software into the BTS */
1326int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1327 gsm_cbfn *cbfn, void *cb_data)
1328{
1329 struct abis_nm_sw *sw = &g_sw;
1330 int rc;
1331
1332 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1333 bts->nr, fname);
1334
1335 if (sw->state != SW_STATE_NONE)
1336 return -EBUSY;
1337
1338 sw->bts = bts;
1339 sw->obj_class = NM_OC_SITE_MANAGER;
1340 sw->obj_instance[0] = 0xff;
1341 sw->obj_instance[1] = 0xff;
1342 sw->obj_instance[2] = 0xff;
1343 sw->state = SW_STATE_WAIT_ACTACK;
1344 sw->cbfn = cbfn;
1345 sw->cb_data = cb_data;
1346
1347 /* Open the file in order to fill some sw struct members */
1348 rc = sw_open_file(sw, fname);
1349 if (rc < 0) {
1350 sw->state = SW_STATE_NONE;
1351 return rc;
1352 }
1353 sw_close_file(sw);
1354
1355 return sw_activate(sw);
1356}
1357
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001358static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1359 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001360{
1361 ch->attrib = NM_ATT_ABIS_CHANNEL;
1362 ch->bts_port = bts_port;
1363 ch->timeslot = ts_nr;
1364 ch->subslot = subslot_nr;
1365}
1366
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001367int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1368 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1369 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001370{
1371 struct abis_om_hdr *oh;
1372 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001373 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001374 struct msgb *msg = nm_msgb_alloc();
1375
1376 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1377 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1378 bts->bts_nr, trx_nr, 0xff);
1379
1380 msgb_tv_put(msg, NM_ATT_TEI, tei);
1381
1382 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1383 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1384
1385 return abis_nm_sendmsg(bts, msg);
1386}
1387
1388/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1389int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001390 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001391{
1392 struct gsm_bts *bts = trx->bts;
1393 struct abis_om_hdr *oh;
1394 struct abis_nm_channel *ch;
1395 struct msgb *msg = nm_msgb_alloc();
1396
1397 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1398 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1399 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1400
1401 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1402 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1403
1404 return abis_nm_sendmsg(bts, msg);
1405}
1406
1407#if 0
1408int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1409 struct abis_nm_abis_channel *chan)
1410{
1411}
1412#endif
1413
1414int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001415 uint8_t e1_port, uint8_t e1_timeslot,
1416 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001417{
1418 struct gsm_bts *bts = ts->trx->bts;
1419 struct abis_om_hdr *oh;
1420 struct abis_nm_channel *ch;
1421 struct msgb *msg = nm_msgb_alloc();
1422
1423 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1424 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1425 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1426
1427 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1428 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1429
1430 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1431 gsm_ts_name(ts),
1432 e1_port, e1_timeslot, e1_subslot);
1433
1434 return abis_nm_sendmsg(bts, msg);
1435}
1436
1437#if 0
1438int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1439 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001440 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001441{
1442}
1443#endif
1444
Maxc81178a2017-05-10 12:21:17 +02001445/* 3GPP TS 52.021 § 8.11.1 */
1446int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1447 const uint8_t *attr, uint8_t attr_len)
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001448{
1449 struct abis_om_hdr *oh;
1450 struct msgb *msg = nm_msgb_alloc();
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001451
1452 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1453
1454 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1455 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1456 bts_nr, trx_nr, ts_nr);
1457 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1458
1459 return abis_nm_sendmsg(bts, msg);
1460}
1461
Harald Welte59b04682009-06-10 05:40:52 +08001462/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001463int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001464{
1465 struct abis_om_hdr *oh;
1466 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001467 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001468
1469 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1470
1471 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1472 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1473 cur = msgb_put(msg, attr_len);
1474 memcpy(cur, attr, attr_len);
1475
1476 return abis_nm_sendmsg(bts, msg);
1477}
1478
1479/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001480int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001481{
1482 struct abis_om_hdr *oh;
1483 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001484 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001485
1486 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1487
1488 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1489 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1490 trx->bts->bts_nr, trx->nr, 0xff);
1491 cur = msgb_put(msg, attr_len);
1492 memcpy(cur, attr, attr_len);
1493
1494 return abis_nm_sendmsg(trx->bts, msg);
1495}
1496
Holger Hans Peter Freyther1f672322014-03-26 14:24:42 +01001497int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1498{
1499 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1500 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1501}
1502
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001503static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1504 const char **reason)
Harald Weltef2eb2782009-08-09 21:49:48 +02001505{
1506 int i;
1507
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001508 *reason = "Reason unknown";
1509
Harald Weltef2eb2782009-08-09 21:49:48 +02001510 /* As it turns out, the BS-11 has some very peculiar restrictions
1511 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301512 switch (ts->trx->bts->type) {
1513 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001514 switch (chan_comb) {
1515 case NM_CHANC_TCHHalf:
1516 case NM_CHANC_TCHHalf2:
Neels Hofmeyr5af61132016-07-14 03:09:56 +02001517 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Weltef2eb2782009-08-09 21:49:48 +02001518 /* not supported */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001519 *reason = "TCH/H is not supported.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001520 return -EINVAL;
1521 case NM_CHANC_SDCCH:
1522 /* only one SDCCH/8 per TRX */
1523 for (i = 0; i < TRX_NR_TS; i++) {
1524 if (i == ts->nr)
1525 continue;
1526 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001527 NM_CHANC_SDCCH) {
1528 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001529 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001530 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001531 }
1532 /* not allowed for TS0 of BCCH-TRX */
1533 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001534 ts->nr == 0) {
1535 *reason = "SDCCH/8 must be on TS0.";
1536 return -EINVAL;
1537 }
1538
Harald Weltef2eb2782009-08-09 21:49:48 +02001539 /* not on the same TRX that has a BCCH+SDCCH4
1540 * combination */
Holger Hans Peter Freytherfca3eb92013-01-08 19:30:14 +01001541 if (ts->trx != ts->trx->bts->c0 &&
Harald Weltef2eb2782009-08-09 21:49:48 +02001542 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001543 ts->trx->ts[0].nm_chan_comb == 8)) {
1544 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1545 return -EINVAL;
1546 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001547 break;
1548 case NM_CHANC_mainBCCH:
1549 case NM_CHANC_BCCHComb:
1550 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001551 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1552 *reason = "Main BCCH must be on TS0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001553 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001554 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001555 break;
1556 case NM_CHANC_BCCH:
1557 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001558 if (ts->trx != ts->trx->bts->c0) {
1559 *reason = "BCCH must be on C0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001560 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001561 }
1562 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1563 *reason = "BCCH must be on TS 2/4/6.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001564 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001565 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001566 break;
1567 case 8: /* this is not like 08.58, but in fact
1568 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1569 /* FIXME: only one CBCH allowed per cell */
1570 break;
1571 }
Harald Welte76ba8812009-12-02 02:45:23 +05301572 break;
1573 case GSM_BTS_TYPE_NANOBTS:
1574 switch (ts->nr) {
1575 case 0:
1576 if (ts->trx->nr == 0) {
1577 /* only on TRX0 */
1578 switch (chan_comb) {
1579 case NM_CHANC_BCCH:
1580 case NM_CHANC_mainBCCH:
1581 case NM_CHANC_BCCHComb:
1582 return 0;
1583 break;
1584 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001585 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301586 return -EINVAL;
1587 }
1588 } else {
1589 switch (chan_comb) {
1590 case NM_CHANC_TCHFull:
1591 case NM_CHANC_TCHHalf:
1592 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1593 return 0;
1594 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001595 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welte76ba8812009-12-02 02:45:23 +05301596 return -EINVAL;
1597 }
1598 }
1599 break;
1600 case 1:
1601 if (ts->trx->nr == 0) {
1602 switch (chan_comb) {
1603 case NM_CHANC_SDCCH_CBCH:
1604 if (ts->trx->ts[0].nm_chan_comb ==
1605 NM_CHANC_mainBCCH)
1606 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001607 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301608 return -EINVAL;
1609 case NM_CHANC_SDCCH:
1610 case NM_CHANC_TCHFull:
1611 case NM_CHANC_TCHHalf:
1612 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1613 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr5af61132016-07-14 03:09:56 +02001614 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte76ba8812009-12-02 02:45:23 +05301615 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001616 default:
1617 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1618 return -EINVAL;
Harald Welte76ba8812009-12-02 02:45:23 +05301619 }
1620 } else {
1621 switch (chan_comb) {
1622 case NM_CHANC_SDCCH:
1623 case NM_CHANC_TCHFull:
1624 case NM_CHANC_TCHHalf:
1625 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1626 return 0;
1627 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001628 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301629 return -EINVAL;
1630 }
1631 }
1632 break;
1633 case 2:
1634 case 3:
1635 case 4:
1636 case 5:
1637 case 6:
1638 case 7:
1639 switch (chan_comb) {
1640 case NM_CHANC_TCHFull:
1641 case NM_CHANC_TCHHalf:
1642 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1643 return 0;
1644 case NM_CHANC_IPAC_PDCH:
1645 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr5af61132016-07-14 03:09:56 +02001646 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte76ba8812009-12-02 02:45:23 +05301647 if (ts->trx->nr == 0)
1648 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001649 else {
1650 *reason = "PDCH must be on TRX0.";
Harald Welte76ba8812009-12-02 02:45:23 +05301651 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001652 }
Harald Welte76ba8812009-12-02 02:45:23 +05301653 }
1654 break;
1655 }
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001656 *reason = "Unknown combination";
Harald Welte76ba8812009-12-02 02:45:23 +05301657 return -EINVAL;
Maxabf3eb12017-03-23 12:01:07 +01001658 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte35ac0e42012-07-02 19:51:55 +02001659 /* no known restrictions */
1660 return 0;
Harald Welte76ba8812009-12-02 02:45:23 +05301661 default:
1662 /* unknown BTS type */
1663 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001664 }
1665 return 0;
1666}
1667
Harald Welte59b04682009-06-10 05:40:52 +08001668/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001669int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001670{
1671 struct gsm_bts *bts = ts->trx->bts;
1672 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001673 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001674 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001675 uint8_t len = 2 + 2;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001676 const char *reason = NULL;
Harald Welte59b04682009-06-10 05:40:52 +08001677
1678 if (bts->type == GSM_BTS_TYPE_BS11)
1679 len += 4 + 2 + 2 + 3;
1680
1681 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001682 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Weltef2eb2782009-08-09 21:49:48 +02001683 msgb_free(msg);
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001684 LOGP(DNM, LOGL_ERROR,
1685 "Invalid Channel Combination %d on %s. Reason: %s\n",
1686 chan_comb, gsm_ts_name(ts), reason);
Harald Weltef2eb2782009-08-09 21:49:48 +02001687 return -EINVAL;
1688 }
1689 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001690
1691 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1692 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1693 NM_OC_CHANNEL, bts->bts_nr,
1694 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001695 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001696 if (ts->hopping.enabled) {
1697 unsigned int i;
1698 uint8_t *len;
1699
Harald Welte67104d12009-09-12 13:05:33 +02001700 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1701 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001702
1703 /* build the ARFCN list */
1704 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1705 len = msgb_put(msg, 1);
1706 *len = 0;
1707 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1708 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1709 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001710 /* At least BS-11 wants a TLV16 here */
1711 if (bts->type == GSM_BTS_TYPE_BS11)
1712 *len += 1;
1713 else
1714 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001715 }
1716 }
Harald Welte59b04682009-06-10 05:40:52 +08001717 }
Harald Welte025e6c92014-01-19 17:18:21 +01001718 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001719 if (bts->type == GSM_BTS_TYPE_BS11)
1720 msgb_tlv_put(msg, 0x59, 1, &zero);
1721
1722 return abis_nm_sendmsg(bts, msg);
1723}
1724
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001725int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1726 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001727{
1728 struct abis_om_hdr *oh;
1729 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001730 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1731 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001732
1733 if (nack) {
1734 len += 2;
1735 msgtype = NM_MT_SW_ACT_REQ_NACK;
1736 }
1737
1738 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1739 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1740
1741 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001742 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001743 memcpy(ptr, attr, att_len);
1744 }
1745 if (nack)
1746 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1747
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001748 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001749}
1750
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001751int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001752{
1753 struct msgb *msg = nm_msgb_alloc();
1754 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001755 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001756
1757 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1758 fill_om_hdr(oh, len);
1759 data = msgb_put(msg, len);
1760 memcpy(data, rawmsg, len);
1761
1762 return abis_nm_sendmsg(bts, msg);
1763}
1764
1765/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001766static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001767{
1768 struct abis_om_hdr *oh;
1769 struct msgb *msg = nm_msgb_alloc();
1770
1771 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1772 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1773 0xff, 0xff, 0xff);
1774
1775 return abis_nm_sendmsg(bts, msg);
1776}
1777
1778/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001779int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
Harald Welte59b04682009-06-10 05:40:52 +08001780{
1781 struct abis_om_hdr *oh;
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +02001782 struct abis_om_fom_hdr *foh;
Harald Welte59b04682009-06-10 05:40:52 +08001783 struct msgb *msg = nm_msgb_alloc();
1784
Harald Welte59b04682009-06-10 05:40:52 +08001785 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +02001786 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte59b04682009-06-10 05:40:52 +08001787
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +02001788 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +02001789 DEBUGPC(DNM, "Sending OPSTART\n");
1790
Harald Welte59b04682009-06-10 05:40:52 +08001791 return abis_nm_sendmsg(bts, msg);
1792}
1793
1794/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001795int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1796 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001797{
1798 struct abis_om_hdr *oh;
1799 struct msgb *msg = nm_msgb_alloc();
1800
1801 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1802 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1803 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1804
1805 return abis_nm_sendmsg(bts, msg);
1806}
1807
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001808int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1809 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001810{
1811 struct abis_om_hdr *oh;
1812 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001813 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001814
1815 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1816 e1_port0, ts0, e1_port1, ts1);
1817
1818 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1819 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1820 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1821
1822 attr = msgb_put(msg, 3);
1823 attr[0] = NM_ATT_MDROP_LINK;
1824 attr[1] = e1_port0;
1825 attr[2] = ts0;
1826
1827 attr = msgb_put(msg, 3);
1828 attr[0] = NM_ATT_MDROP_NEXT;
1829 attr[1] = e1_port1;
1830 attr[2] = ts1;
1831
1832 return abis_nm_sendmsg(bts, msg);
1833}
Harald Welte59b04682009-06-10 05:40:52 +08001834
Harald Welte0bf8e302009-08-08 00:02:36 +02001835/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001836int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1837 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1838 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001839{
1840 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001841
Harald Weltec61a90e2011-05-22 22:45:37 +02001842 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001843
1844 if (!msg)
1845 msg = nm_msgb_alloc();
1846
1847 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1848 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1849 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1850 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001851 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001852
1853 return abis_nm_sendmsg(bts, msg);
1854}
1855
Harald Welte59b04682009-06-10 05:40:52 +08001856int abis_nm_event_reports(struct gsm_bts *bts, int on)
1857{
1858 if (on == 0)
1859 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1860 else
1861 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1862}
1863
1864/* Siemens (or BS-11) specific commands */
1865
1866int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1867{
1868 if (reconnect == 0)
1869 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1870 else
1871 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1872}
1873
1874int abis_nm_bs11_restart(struct gsm_bts *bts)
1875{
1876 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1877}
1878
1879
1880struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001881 uint16_t year;
1882 uint8_t month;
1883 uint8_t day;
1884 uint8_t hour;
1885 uint8_t min;
1886 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001887} __attribute__((packed));
1888
1889
1890void get_bs11_date_time(struct bs11_date_time *aet)
1891{
1892 time_t t;
1893 struct tm *tm;
1894
1895 t = time(NULL);
1896 tm = localtime(&t);
1897 aet->sec = tm->tm_sec;
1898 aet->min = tm->tm_min;
1899 aet->hour = tm->tm_hour;
1900 aet->day = tm->tm_mday;
1901 aet->month = tm->tm_mon;
1902 aet->year = htons(1900 + tm->tm_year);
1903}
1904
1905int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1906{
1907 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1908}
1909
1910int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1911{
1912 if (begin)
1913 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1914 else
1915 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1916}
1917
1918int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001919 enum abis_bs11_objtype type, uint8_t idx,
1920 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001921{
1922 struct abis_om_hdr *oh;
1923 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001924 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001925
1926 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1927 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1928 NM_OC_BS11, type, 0, idx);
1929 cur = msgb_put(msg, attr_len);
1930 memcpy(cur, attr, attr_len);
1931
1932 return abis_nm_sendmsg(bts, msg);
1933}
1934
1935int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001936 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001937{
1938 struct abis_om_hdr *oh;
1939 struct msgb *msg = nm_msgb_alloc();
1940
1941 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1942 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1943 NM_OC_BS11, type, 0, idx);
1944
1945 return abis_nm_sendmsg(bts, msg);
1946}
1947
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001948int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001949{
1950 struct abis_om_hdr *oh;
1951 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001952 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001953
1954 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1955 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1956 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1957 msgb_tlv_put(msg, 0x99, 1, &zero);
1958
1959 return abis_nm_sendmsg(bts, msg);
1960}
1961
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001962int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001963{
1964 struct abis_om_hdr *oh;
1965 struct msgb *msg = nm_msgb_alloc();
1966
1967 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1968 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001969 idx, 0xff, 0xff);
1970
1971 return abis_nm_sendmsg(bts, msg);
1972}
1973
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001974int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001975{
1976 struct abis_om_hdr *oh;
1977 struct msgb *msg = nm_msgb_alloc();
1978
1979 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1980 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1981 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001982
1983 return abis_nm_sendmsg(bts, msg);
1984}
1985
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001986static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001987int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1988{
1989 struct abis_om_hdr *oh;
1990 struct msgb *msg = nm_msgb_alloc();
1991
1992 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1993 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1994 0xff, 0xff, 0xff);
1995 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1996
1997 return abis_nm_sendmsg(bts, msg);
1998}
1999
2000/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002001int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2002 uint8_t e1_timeslot, uint8_t e1_subslot,
2003 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08002004{
2005 struct abis_om_hdr *oh;
2006 struct abis_nm_channel *ch;
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, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2011 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2012
2013 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2014 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2015 msgb_tv_put(msg, NM_ATT_TEI, tei);
2016
2017 return abis_nm_sendmsg(bts, msg);
2018}
2019
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002020int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08002021{
2022 struct abis_om_hdr *oh;
2023 struct msgb *msg = nm_msgb_alloc();
2024
2025 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2026 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2027 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2028 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2029
2030 return abis_nm_sendmsg(trx->bts, msg);
2031}
2032
2033int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2034{
2035 struct abis_om_hdr *oh;
2036 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002037 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08002038
2039 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2040 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2041 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2042 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2043
2044 return abis_nm_sendmsg(trx->bts, msg);
2045}
2046
2047int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2048{
2049 struct abis_om_hdr *oh;
2050 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002051 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08002052
2053 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2054 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2055 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2056 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2057
2058 return abis_nm_sendmsg(bts, msg);
2059}
2060
2061int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2062{
2063 struct abis_om_hdr *oh;
2064 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002065 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08002066 NM_ATT_BS11_CCLK_TYPE };
2067
2068 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2069 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2070 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2071 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2072
2073 return abis_nm_sendmsg(bts, msg);
2074
2075}
2076
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002077//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002078
2079int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2080{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002081 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2082}
2083
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002084int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2085{
2086 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2087}
2088
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002089int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002090{
Harald Welte59b04682009-06-10 05:40:52 +08002091 struct abis_om_hdr *oh;
2092 struct msgb *msg = nm_msgb_alloc();
2093 struct bs11_date_time bdt;
2094
2095 get_bs11_date_time(&bdt);
2096
2097 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2098 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002099 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002100 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002101 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2102 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2103 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002104 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08002105 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002106 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002107 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002108 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002109 } else {
2110 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2111 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2112 }
2113
2114 return abis_nm_sendmsg(bts, msg);
2115}
2116
2117int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2118{
2119 struct abis_om_hdr *oh;
2120 struct msgb *msg;
2121
2122 if (strlen(password) != 10)
2123 return -EINVAL;
2124
2125 msg = nm_msgb_alloc();
2126 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2127 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2128 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002129 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002130
2131 return abis_nm_sendmsg(bts, msg);
2132}
2133
2134/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2135int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2136{
2137 struct abis_om_hdr *oh;
2138 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002139 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002140
2141 msg = nm_msgb_alloc();
2142 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2143 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2144 BS11_OBJ_LI, 0x00, 0x00);
2145
2146 if (locked)
2147 tlv_value = BS11_LI_PLL_LOCKED;
2148 else
2149 tlv_value = BS11_LI_PLL_STANDALONE;
2150
2151 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2152
2153 return abis_nm_sendmsg(bts, msg);
2154}
2155
Daniel Willmann10b07db2010-01-07 00:54:01 +01002156/* Set the calibration value of the PLL (work value/set value)
2157 * It depends on the login which one is changed */
2158int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2159{
2160 struct abis_om_hdr *oh;
2161 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002162 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002163
2164 msg = nm_msgb_alloc();
2165 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2166 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2167 BS11_OBJ_TRX1, 0x00, 0x00);
2168
2169 tlv_value[0] = value>>8;
2170 tlv_value[1] = value&0xff;
2171
2172 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2173
2174 return abis_nm_sendmsg(bts, msg);
2175}
2176
Harald Welte59b04682009-06-10 05:40:52 +08002177int abis_nm_bs11_get_state(struct gsm_bts *bts)
2178{
2179 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2180}
2181
2182/* BS11 SWL */
2183
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002184void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002185
Harald Welte59b04682009-06-10 05:40:52 +08002186struct abis_nm_bs11_sw {
2187 struct gsm_bts *bts;
2188 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002189 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002190 int forced;
2191 struct llist_head file_list;
2192 gsm_cbfn *user_cb; /* specified by the user */
2193};
2194static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2195
2196struct file_list_entry {
2197 struct llist_head list;
2198 char fname[PATH_MAX];
2199};
2200
2201struct file_list_entry *fl_dequeue(struct llist_head *queue)
2202{
2203 struct llist_head *lh;
2204
2205 if (llist_empty(queue))
2206 return NULL;
2207
2208 lh = queue->next;
2209 llist_del(lh);
2210
2211 return llist_entry(lh, struct file_list_entry, list);
2212}
2213
2214static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2215{
2216 char linebuf[255];
2217 struct llist_head *lh, *lh2;
2218 FILE *swl;
2219 int rc = 0;
2220
2221 swl = fopen(bs11_sw->swl_fname, "r");
2222 if (!swl)
2223 return -ENODEV;
2224
2225 /* zero the stale file list, if any */
2226 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2227 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002228 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002229 }
2230
2231 while (fgets(linebuf, sizeof(linebuf), swl)) {
2232 char file_id[12+1];
2233 char file_version[80+1];
2234 struct file_list_entry *fle;
2235 static char dir[PATH_MAX];
2236
2237 if (strlen(linebuf) < 4)
2238 continue;
2239
2240 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2241 if (rc < 0) {
2242 perror("ERR parsing SWL file");
2243 rc = -EINVAL;
2244 goto out;
2245 }
2246 if (rc < 2)
2247 continue;
2248
Harald Welte857e00d2009-06-26 20:25:23 +02002249 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002250 if (!fle) {
2251 rc = -ENOMEM;
2252 goto out;
2253 }
Harald Welte59b04682009-06-10 05:40:52 +08002254
2255 /* construct new filename */
Neels Hofmeyr5644c2b2017-01-13 03:12:08 +01002256 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte59b04682009-06-10 05:40:52 +08002257 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2258 strcat(fle->fname, "/");
2259 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2260
2261 llist_add_tail(&fle->list, &bs11_sw->file_list);
2262 }
2263
2264out:
2265 fclose(swl);
2266 return rc;
2267}
2268
2269/* bs11 swload specific callback, passed to abis_nm core swload */
2270static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2271 struct msgb *msg, void *data, void *param)
2272{
2273 struct abis_nm_bs11_sw *bs11_sw = data;
2274 struct file_list_entry *fle;
2275 int rc = 0;
2276
2277 switch (event) {
2278 case NM_MT_LOAD_END_ACK:
2279 fle = fl_dequeue(&bs11_sw->file_list);
2280 if (fle) {
2281 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002282 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002283 bs11_sw->win_size,
2284 bs11_sw->forced,
2285 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002286 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002287 } else {
2288 /* activate the SWL */
2289 rc = abis_nm_software_activate(bs11_sw->bts,
2290 bs11_sw->swl_fname,
2291 bs11_swload_cbfn,
2292 bs11_sw);
2293 }
2294 break;
2295 case NM_MT_LOAD_SEG_ACK:
2296 case NM_MT_LOAD_END_NACK:
2297 case NM_MT_LOAD_INIT_ACK:
2298 case NM_MT_LOAD_INIT_NACK:
2299 case NM_MT_ACTIVATE_SW_NACK:
2300 case NM_MT_ACTIVATE_SW_ACK:
2301 default:
2302 /* fallthrough to the user callback */
2303 if (bs11_sw->user_cb)
2304 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2305 break;
2306 }
2307
2308 return rc;
2309}
2310
2311/* Siemens provides a SWL file that is a mere listing of all the other
2312 * files that are part of a software release. We need to upload first
2313 * the list file, and then each file that is listed in the list file */
2314int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002315 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002316{
2317 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2318 struct file_list_entry *fle;
2319 int rc = 0;
2320
2321 INIT_LLIST_HEAD(&bs11_sw->file_list);
2322 bs11_sw->bts = bts;
2323 bs11_sw->win_size = win_size;
2324 bs11_sw->user_cb = cbfn;
2325 bs11_sw->forced = forced;
2326
Neels Hofmeyr5644c2b2017-01-13 03:12:08 +01002327 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte59b04682009-06-10 05:40:52 +08002328 rc = bs11_read_swl_file(bs11_sw);
2329 if (rc < 0)
2330 return rc;
2331
2332 /* dequeue next item in file list */
2333 fle = fl_dequeue(&bs11_sw->file_list);
2334 if (!fle)
2335 return -EINVAL;
2336
2337 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002338 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002339 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002340 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002341 return rc;
2342}
2343
2344#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002345static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002346 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2347 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2348 NM_ATT_BS11_LMT_USER_NAME,
2349
2350 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2351
2352 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2353
2354 NM_ATT_BS11_SW_LOAD_STORED };
2355
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002356static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002357 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2358 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2359 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2360 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2361#endif
2362
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002363static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002364 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2365 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2366 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2367
2368int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2369{
2370 struct abis_om_hdr *oh;
2371 struct msgb *msg = nm_msgb_alloc();
2372
2373 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2374 /* SiemensHW CCTRL object */
2375 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2376 0x03, 0x00, 0x00);
2377 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2378
2379 return abis_nm_sendmsg(bts, msg);
2380}
2381
2382int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2383{
2384 struct abis_om_hdr *oh;
2385 struct msgb *msg = nm_msgb_alloc();
2386 struct bs11_date_time aet;
2387
2388 get_bs11_date_time(&aet);
2389 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2390 /* SiemensHW CCTRL object */
2391 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2392 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002393 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002394
2395 return abis_nm_sendmsg(bts, msg);
2396}
2397
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002398int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002399{
2400 struct abis_om_hdr *oh;
2401 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002402 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002403
2404 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2405 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2406 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2407 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2408
2409 return abis_nm_sendmsg(bts, msg);
2410}
2411
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002412int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg)
Daniel Willmann5655afe2009-08-10 11:49:36 +02002413{
2414 struct abis_om_hdr *oh;
2415 struct msgb *msg = nm_msgb_alloc();
2416 struct bs11_date_time aet;
2417
2418 get_bs11_date_time(&aet);
2419 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2420 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2421 bport, 0xff, 0x02);
2422 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2423
2424 return abis_nm_sendmsg(bts, msg);
2425}
2426
Harald Welte59b04682009-06-10 05:40:52 +08002427/* ip.access nanoBTS specific commands */
2428static const char ipaccess_magic[] = "com.ipaccess";
2429
2430
2431static int abis_nm_rx_ipacc(struct msgb *msg)
2432{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002433 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002434 struct abis_om_hdr *oh = msgb_l2(msg);
2435 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002436 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002437 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002438 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002439 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002440
2441 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002442 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002443 return -EINVAL;
2444 }
2445
2446 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002447 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002448
Harald Weltec61a90e2011-05-22 22:45:37 +02002449 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002450
Harald Welte5aeedd42009-10-19 22:11:11 +02002451 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002452
2453 switch (foh->msg_type) {
2454 case NM_MT_IPACC_RSL_CONNECT_ACK:
2455 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002456 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2457 memcpy(&addr,
2458 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2459
2460 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2461 }
Harald Welte4206d982009-07-12 09:33:54 +02002462 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002463 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002464 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002465 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002466 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2467 DEBUGPC(DNM, "STREAM=0x%02x ",
2468 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002469 DEBUGPC(DNM, "\n");
2470 break;
2471 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002472 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002473 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002474 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002475 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002476 else
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002477 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002478 break;
2479 case NM_MT_IPACC_SET_NVATTR_ACK:
2480 DEBUGPC(DNM, "SET NVATTR ACK\n");
2481 /* FIXME: decode and show the actual attributes */
2482 break;
2483 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002484 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002485 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002486 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002487 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002488 else
Harald Weltede4477a2009-12-24 12:20:20 +01002489 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002490 break;
Harald Welte21460f02009-07-03 11:26:45 +02002491 case NM_MT_IPACC_GET_NVATTR_ACK:
2492 DEBUGPC(DNM, "GET NVATTR ACK\n");
2493 /* FIXME: decode and show the actual attributes */
2494 break;
2495 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002496 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002497 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002498 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002499 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002500 else
Harald Weltede4477a2009-12-24 12:20:20 +01002501 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002502 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002503 case NM_MT_IPACC_SET_ATTR_ACK:
2504 DEBUGPC(DNM, "SET ATTR ACK\n");
2505 break;
2506 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002507 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002508 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002509 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002510 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002511 else
Harald Weltede4477a2009-12-24 12:20:20 +01002512 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002513 break;
Harald Welte59b04682009-06-10 05:40:52 +08002514 default:
2515 DEBUGPC(DNM, "unknown\n");
2516 break;
2517 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002518
2519 /* signal handling */
2520 switch (foh->msg_type) {
2521 case NM_MT_IPACC_RSL_CONNECT_NACK:
2522 case NM_MT_IPACC_SET_NVATTR_NACK:
2523 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002524 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002525 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002526 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002527 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002528 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002529 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002530 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002531 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002532 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002533 default:
2534 break;
2535 }
2536
Harald Welte59b04682009-06-10 05:40:52 +08002537 return 0;
2538}
2539
2540/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002541int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2542 uint8_t obj_class, uint8_t bts_nr,
2543 uint8_t trx_nr, uint8_t ts_nr,
2544 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002545{
2546 struct msgb *msg = nm_msgb_alloc();
2547 struct abis_om_hdr *oh;
2548 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002549 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002550
2551 /* construct the 12.21 OM header, observe the erroneous length */
2552 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2553 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2554 oh->mdisc = ABIS_OM_MDISC_MANUF;
2555
2556 /* add the ip.access magic */
2557 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2558 *data++ = sizeof(ipaccess_magic);
2559 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2560
2561 /* fill the 12.21 FOM header */
2562 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2563 foh->msg_type = msg_type;
2564 foh->obj_class = obj_class;
2565 foh->obj_inst.bts_nr = bts_nr;
2566 foh->obj_inst.trx_nr = trx_nr;
2567 foh->obj_inst.ts_nr = ts_nr;
2568
2569 if (attr && attr_len) {
2570 data = msgb_put(msg, attr_len);
2571 memcpy(data, attr, attr_len);
2572 }
2573
2574 return abis_nm_sendmsg(bts, msg);
2575}
2576
2577/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002578int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002579 int attr_len)
2580{
Harald Weltef12c1052010-01-07 20:39:42 +01002581 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2582 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002583 attr_len);
2584}
2585
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002586int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002587 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002588{
2589 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002590 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002591 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2592 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2593
2594 int attr_len = sizeof(attr);
2595
2596 ia.s_addr = htonl(ip);
2597 attr[1] = stream;
2598 attr[3] = port >> 8;
2599 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002600 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002601
2602 /* if ip == 0, we use the default IP */
2603 if (ip == 0)
2604 attr_len -= 5;
2605
2606 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002607 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002608
2609 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2610 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2611 trx->nr, 0xff, attr, attr_len);
2612}
2613
Harald Welte59b04682009-06-10 05:40:52 +08002614/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002615int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002616{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002617 struct abis_om_hdr *oh;
2618 struct msgb *msg = nm_msgb_alloc();
2619
2620 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2621 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2622 trx->bts->nr, trx->nr, 0xff);
2623
Holger Hans Peter Freytherc26d1172016-03-16 14:27:29 +01002624 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002625}
Harald Welte0dfc6232009-10-24 10:20:41 +02002626
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002627int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2628 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2629 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002630{
2631 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2632 obj_class, bts_nr, trx_nr, ts_nr,
2633 attr, attr_len);
2634}
Harald Weltebeeae412009-11-12 14:48:42 +01002635
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002636void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002637{
2638 /* we simply reuse the GSM48 function and overwrite the RAC
2639 * with the Cell ID */
2640 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002641 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002642}
2643
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002644void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2645{
2646 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2647
Harald Welte69f6f812011-05-30 12:07:53 +02002648 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002649 if (!trx->bts || !trx->bts->oml_link)
2650 return;
2651
2652 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2653 trx->bts->bts_nr, trx->nr, 0xff,
2654 new_state);
2655}
2656
Harald Welte453141f2010-03-25 11:45:30 +08002657static const struct value_string ipacc_testres_names[] = {
2658 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2659 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2660 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2661 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2662 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2663 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002664};
2665
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002666const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002667{
Harald Welte453141f2010-03-25 11:45:30 +08002668 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002669}
2670
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002671void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002672{
2673 cid->mcc = (buf[0] & 0xf) * 100;
2674 cid->mcc += (buf[0] >> 4) * 10;
2675 cid->mcc += (buf[1] & 0xf) * 1;
2676
2677 if (buf[1] >> 4 == 0xf) {
2678 cid->mnc = (buf[2] & 0xf) * 10;
2679 cid->mnc += (buf[2] >> 4) * 1;
2680 } else {
2681 cid->mnc = (buf[2] & 0xf) * 100;
2682 cid->mnc += (buf[2] >> 4) * 10;
2683 cid->mnc += (buf[1] >> 4) * 1;
2684 }
2685
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002686 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2687 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002688}
2689
Harald Weltebeeae412009-11-12 14:48:42 +01002690/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002691int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002692{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002693 uint8_t *cur = buf;
Holger Hans Peter Freyther1a9f3ee2012-09-11 11:55:03 +02002694 uint16_t len __attribute__((unused));
Harald Weltebeeae412009-11-12 14:48:42 +01002695
Harald Welteb784df82010-07-22 18:14:36 +02002696 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002697
2698 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2699 return -EINVAL;
2700 cur++;
2701
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002702 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002703 cur += 2;
2704
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002705 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002706 cur += 2;
2707
2708 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2709 binf->freq_qual = *cur >> 2;
2710
Harald Welteb784df82010-07-22 18:14:36 +02002711 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002712 binf->arfcn |= *cur++;
2713
2714 if (binf->info_type & IPAC_BINF_RXLEV)
2715 binf->rx_lev = *cur & 0x3f;
2716 cur++;
2717
2718 if (binf->info_type & IPAC_BINF_RXQUAL)
2719 binf->rx_qual = *cur & 0x7;
2720 cur++;
2721
2722 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002723 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002724 cur += 2;
2725
2726 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002727 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002728 cur += 2;
2729
2730 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002731 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002732 cur += 4;
2733
Harald Welte22cb81f2010-07-30 22:34:42 +02002734#if 0
2735 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002736 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002737#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002738 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002739 cur++;
2740
Harald Weltebfc21092009-11-13 11:56:05 +01002741 ipac_parse_cgi(&binf->cgi, cur);
2742 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002743
2744 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2745 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2746 cur += sizeof(binf->ba_list_si2);
2747 }
2748
2749 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2750 memcpy(binf->ba_list_si2bis, cur,
2751 sizeof(binf->ba_list_si2bis));
2752 cur += sizeof(binf->ba_list_si2bis);
2753 }
2754
2755 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2756 memcpy(binf->ba_list_si2ter, cur,
2757 sizeof(binf->ba_list_si2ter));
2758 cur += sizeof(binf->ba_list_si2ter);
2759 }
2760
2761 return 0;
2762}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002763
2764void abis_nm_clear_queue(struct gsm_bts *bts)
2765{
2766 struct msgb *msg;
2767
2768 while (!llist_empty(&bts->abis_queue)) {
2769 msg = msgb_dequeue(&bts->abis_queue);
2770 msgb_free(msg);
2771 }
2772
2773 bts->abis_nm_pend = 0;
2774}