blob: 019d03952a9753418e5398ec3ca4d16c516f83bc [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
Maxfa4b2b82017-05-29 11:48:29 +0200442static inline bool handle_attr(const struct gsm_bts *bts, enum bts_attribute id, uint8_t *val, uint8_t len)
Max07922cd2017-05-15 10:29:54 +0200443{
444 switch (id) {
445 case BTS_TYPE_VARIANT:
Maxfa4b2b82017-05-29 11:48:29 +0200446 LOGP(DNM, LOGL_NOTICE, "BTS%u reported variant: %s\n", bts->nr, val);
Max07922cd2017-05-15 10:29:54 +0200447 break;
448 case BTS_SUB_MODEL:
Maxfa4b2b82017-05-29 11:48:29 +0200449 LOGP(DNM, LOGL_NOTICE, "BTS%u reported submodel: %s\n", bts->nr, val);
Max07922cd2017-05-15 10:29:54 +0200450 break;
451 default:
452 return false;
453 }
454 return true;
455}
456
Maxfa4b2b82017-05-29 11:48:29 +0200457/* Parse Attribute Response Info - return pointer to the actual content */
458static inline uint8_t *parse_attr_resp_info_unreported(uint8_t bts_nr, uint8_t *ari, uint16_t ari_len, uint16_t *out_len)
459{
460 uint8_t num_unreported = ari[0], i;
461
462 DEBUGP(DNM, "BTS%u Get Attributes Response Info: %u bytes total with %u unreported attributes\n",
463 bts_nr, ari_len, num_unreported);
464
465 /* +1 because we have to account for number of unreported attributes, prefixing the list: */
466 for (i = 0; i < num_unreported; i++)
467 LOGP(DNM, LOGL_ERROR, "BTS%u Attribute %s is unreported\n",
468 bts_nr, get_value_string(abis_nm_att_names, ari[i + 1]));
469
470 /* the data starts right after the list of unreported attributes + space for length of that list */
471 *out_len = ari_len - (num_unreported + 2);
472
473 return ari + num_unreported + 1; /* we have to account for 1st byte with number of unreported attributes */
474}
475
Maxc0b43d92017-06-06 15:40:40 +0200476/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.30 Manufacturer Id */
477static inline uint8_t *parse_attr_resp_info_manuf_id(struct gsm_bts *bts, uint8_t *data, uint16_t *data_len)
478{
479 struct tlv_parsed tp;
480 uint16_t m_id_len = 0;
481 uint8_t adjust = 0, i;
482
483 abis_nm_tlv_parse(&tp, bts, data, *data_len);
484 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_ID, 2)) {
485 m_id_len = TLVP_LEN(&tp, NM_ATT_MANUF_ID);
486
Max68527922017-06-13 10:15:58 +0200487 /* log potential BTS feature vector overflow */
488 if (m_id_len > sizeof(bts->_features_data))
Maxc0b43d92017-06-06 15:40:40 +0200489 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: feature vector is truncated to %u bytes\n",
490 bts->nr, MAX_BTS_FEATURES/8);
Maxc0b43d92017-06-06 15:40:40 +0200491
Max68527922017-06-13 10:15:58 +0200492 /* check that max. expected BTS attribute is above given feature vector length */
493 if (m_id_len > OSMO_BYTES_FOR_BITS(_NUM_BTS_FEAT))
Maxc0b43d92017-06-06 15:40:40 +0200494 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: reported unexpectedly long (%u bytes) "
495 "feature vector - most likely it was compiled against newer BSC headers. "
496 "Consider upgrading your BSC to later version.\n",
497 bts->nr, m_id_len);
498
Max30d7bc32017-06-12 13:45:03 +0200499 memcpy(bts->_features_data, TLVP_VAL(&tp, NM_ATT_MANUF_ID), sizeof(bts->_features_data));
Maxc0b43d92017-06-06 15:40:40 +0200500 adjust = m_id_len + 3; /* adjust for parsed TL16V struct */
501
502 for (i = 0; i < _NUM_BTS_FEAT; i++)
503 if (gsm_bts_has_feature(bts, i) != gsm_btsmodel_has_feature(bts->model, i))
504 LOGP(DNM, LOGL_NOTICE, "BTS%u feature '%s' reported via OML does not match statically "
505 "set feature: %u != %u. Please fix.\n", bts->nr,
506 get_value_string(gsm_bts_features_descs, i),
507 gsm_bts_has_feature(bts, i), gsm_btsmodel_has_feature(bts->model, i));
508 }
509
510 *data_len -= adjust;
511
512 return data + adjust;
513}
514
Maxfa4b2b82017-05-29 11:48:29 +0200515/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.28 Manufacturer Dependent State */
516static inline uint8_t *parse_attr_resp_info_manuf_state(const struct gsm_bts_trx *trx, uint8_t *data, uint16_t *data_len)
517{
518 struct tlv_parsed tp;
519 const uint8_t *power;
520 uint8_t adjust = 0;
521
522 if (!trx) /* this attribute does not make sense on BTS level, only on TRX level */
523 return data;
524
525 abis_nm_tlv_parse(&tp, trx->bts, data, *data_len);
526 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_STATE, 1)) {
527 power = TLVP_VAL(&tp, NM_ATT_MANUF_STATE);
528 LOGP(DNM, LOGL_NOTICE, "%s Get Attributes Response: nominal power is %u\n", gsm_trx_name(trx), *power);
529 adjust = 2; /* adjust for parsed TV struct */
530 }
531
532 *data_len -= adjust;
533
534 return data + adjust;
535}
536
Max07922cd2017-05-15 10:29:54 +0200537/* Handle 3GPP TS 52.021 §9.4.64 Get Attribute Response Info */
Maxfa4b2b82017-05-29 11:48:29 +0200538static int abis_nm_rx_get_attr_resp(struct msgb *mb, const struct gsm_bts_trx *trx)
Max07922cd2017-05-15 10:29:54 +0200539{
540 struct abis_om_hdr *oh = msgb_l2(mb);
541 struct abis_om_fom_hdr *foh = msgb_l3(mb);
542 struct e1inp_sign_link *sign_link = mb->dst;
Maxfa4b2b82017-05-29 11:48:29 +0200543 struct gsm_bts *bts = trx ? trx->bts : sign_link->trx->bts;
Max07922cd2017-05-15 10:29:54 +0200544 struct tlv_parsed tp;
Maxfa4b2b82017-05-29 11:48:29 +0200545 uint8_t *data, i;
546 uint16_t data_len;
Max07922cd2017-05-15 10:29:54 +0200547 int rc;
548 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
549
550 abis_nm_debugp_foh(DNM, foh);
551
Maxfa4b2b82017-05-29 11:48:29 +0200552 DEBUGPC(DNM, "Get Attributes Response for BTS%u\n", bts->nr);
Max07922cd2017-05-15 10:29:54 +0200553
Maxfa4b2b82017-05-29 11:48:29 +0200554 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
555 if (!TLVP_PRES_LEN(&tp, NM_ATT_GET_ARI, 1)) {
556 LOGP(DNM, LOGL_ERROR, "BTS%u: Get Attributes Response without Response Info?!\n", bts->nr);
Max07922cd2017-05-15 10:29:54 +0200557 return -EINVAL;
558 }
559
Maxfa4b2b82017-05-29 11:48:29 +0200560 data = parse_attr_resp_info_unreported(bts->nr, TLVP_VAL(&tp, NM_ATT_GET_ARI), TLVP_LEN(&tp, NM_ATT_GET_ARI),
561 &data_len);
Max07922cd2017-05-15 10:29:54 +0200562
Maxfa4b2b82017-05-29 11:48:29 +0200563 data = parse_attr_resp_info_manuf_state(trx, data, &data_len);
Maxc0b43d92017-06-06 15:40:40 +0200564 data = parse_attr_resp_info_manuf_id(bts, data, &data_len);
Max07922cd2017-05-15 10:29:54 +0200565
Maxfa4b2b82017-05-29 11:48:29 +0200566 /* after parsing manufacturer-specific attributes there's list of replies in form of sw-conf structure: */
567 rc = abis_nm_get_sw_conf(data, data_len, &sw_descr[0], ARRAY_SIZE(sw_descr));
Max07922cd2017-05-15 10:29:54 +0200568 if (rc > 0) {
569 for (i = 0; i < rc; i++) {
Maxfa4b2b82017-05-29 11:48:29 +0200570 if (!handle_attr(bts, str2btsattr((const char *)sw_descr[i].file_id),
571 sw_descr[i].file_version, sw_descr[i].file_version_len))
572 LOGP(DNM, LOGL_NOTICE, "BTS%u: ARI reported sw[%d/%d]: %s is %s\n",
573 bts->nr, i, rc, sw_descr[i].file_id, sw_descr[i].file_version);
Max07922cd2017-05-15 10:29:54 +0200574 }
575 } else
Maxfa4b2b82017-05-29 11:48:29 +0200576 LOGP(DNM, LOGL_ERROR, "BTS%u: failed to parse SW-Config part of Get Attribute Response Info: %s\n",
577 bts->nr, strerror(-rc));
Max07922cd2017-05-15 10:29:54 +0200578
579 return 0;
580}
581
Maxc81178a2017-05-10 12:21:17 +0200582/* 3GPP TS 52.021 §6.2.5 */
Harald Welte59b04682009-06-10 05:40:52 +0800583static int abis_nm_rx_sw_act_req(struct msgb *mb)
584{
585 struct abis_om_hdr *oh = msgb_l2(mb);
586 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200587 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200588 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200589 const uint8_t *sw_config;
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100590 int ret, sw_config_len, len;
Maxc81178a2017-05-10 12:21:17 +0200591 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
Harald Welte59b04682009-06-10 05:40:52 +0800592
Harald Weltec61a90e2011-05-22 22:45:37 +0200593 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200594
595 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800596
Harald Welte3055e332010-03-14 15:37:43 +0800597 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800598
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200599 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800600 foh->obj_inst.bts_nr,
601 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800602 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800603 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100604 if (ret != 0) {
605 LOGP(DNM, LOGL_ERROR,
606 "Sending SW ActReq ACK failed: %d\n", ret);
607 return ret;
608 }
Harald Welte59b04682009-06-10 05:40:52 +0800609
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200610 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200611 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
612 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
613 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100614 LOGP(DNM, LOGL_ERROR,
615 "SW config not found! Can't continue.\n");
Mike Haben322fc582009-10-01 14:56:13 +0200616 return -EINVAL;
617 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200618 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200619 }
620
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100621 /* Parse up to two sw descriptions from the data */
Max82df6912017-03-24 21:04:57 +0100622 len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
623 ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100624 if (len <= 0) {
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100625 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100626 return -EINVAL;
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100627 }
Mike Haben322fc582009-10-01 14:56:13 +0200628
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100629 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
630 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
631
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200632 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800633 foh->obj_inst.bts_nr,
634 foh->obj_inst.trx_nr,
635 foh->obj_inst.ts_nr,
Max82df6912017-03-24 21:04:57 +0100636 &sw_descr[ret]);
Harald Welte59b04682009-06-10 05:40:52 +0800637}
638
639/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
640static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
641{
642 struct abis_om_hdr *oh = msgb_l2(mb);
643 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200644 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800645 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200646 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800647
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200648 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800649 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
650 return -EINVAL;
651
652 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
653
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200654 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800655}
656
657static int abis_nm_rx_lmt_event(struct msgb *mb)
658{
659 struct abis_om_hdr *oh = msgb_l2(mb);
660 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200661 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800662 struct tlv_parsed tp;
663
664 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200665 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800666 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
667 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200668 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800669 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
670 }
671 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
672 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200673 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800674 DEBUGPC(DNM, "Level=%u ", level);
675 }
676 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
677 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
678 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
679 DEBUGPC(DNM, "Username=%s ", name);
680 }
681 DEBUGPC(DNM, "\n");
682 /* FIXME: parse LMT LOGON TIME */
683 return 0;
684}
685
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200686void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100687{
688 int wait = 0;
689 struct msgb *msg;
690 /* the queue is empty */
691 while (!llist_empty(&bts->abis_queue)) {
692 msg = msgb_dequeue(&bts->abis_queue);
693 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200694 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100695
696 if (wait)
697 break;
698 }
699
700 bts->abis_nm_pend = wait;
701}
702
Harald Welte59b04682009-06-10 05:40:52 +0800703/* Receive a OML NM Message from BTS */
704static int abis_nm_rcvmsg_fom(struct msgb *mb)
705{
706 struct abis_om_hdr *oh = msgb_l2(mb);
707 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200708 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200709 uint8_t mt = foh->msg_type;
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100710 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
711 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100712 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800713
714 /* check for unsolicited message */
715 if (is_report(mt))
Maxab4b1502017-03-15 14:30:21 +0100716 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte59b04682009-06-10 05:40:52 +0800717
Harald Weltec61a90e2011-05-22 22:45:37 +0200718 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800719 return abis_nm_rcvmsg_sw(mb);
720
Harald Weltec61a90e2011-05-22 22:45:37 +0200721 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800722 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800723 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200724
Harald Weltec61a90e2011-05-22 22:45:37 +0200725 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200726
Harald Weltec61a90e2011-05-22 22:45:37 +0200727 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800728
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100729 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800730 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200731 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200732 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800733 else
734 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200735
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800736 nack_data.msg = mb;
737 nack_data.mt = mt;
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100738 nack_data.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200739 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100740 abis_nm_queue_send_next(bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200741 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800742 }
743#if 0
744 /* check if last message is to be acked */
745 if (is_ack_nack(nmh->last_msgtype)) {
746 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100747 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800748 /* we got our ACK, continue sending the next msg */
749 } else if (mt == MT_NACK(nmh->last_msgtype)) {
750 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100751 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800752 /* FIXME: somehow signal this to the caller */
753 } else {
754 /* really strange things happen */
755 return -EINVAL;
756 }
757 }
758#endif
759
760 switch (mt) {
761 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100762 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800763 break;
764 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100765 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800766 break;
767 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100768 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800769 break;
Max7efc2632017-04-04 19:21:24 +0200770 case NM_MT_OPSTART_ACK:
771 abis_nm_debugp_foh(DNM, foh);
772 DEBUGPC(DNM, "Opstart ACK\n");
773 break;
774 case NM_MT_SET_CHAN_ATTR_ACK:
775 abis_nm_debugp_foh(DNM, foh);
776 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
777 break;
778 case NM_MT_SET_RADIO_ATTR_ACK:
779 abis_nm_debugp_foh(DNM, foh);
780 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
781 break;
Harald Welte204317e2009-08-06 17:58:31 +0200782 case NM_MT_CONN_MDROP_LINK_ACK:
Max7efc2632017-04-04 19:21:24 +0200783 abis_nm_debugp_foh(DNM, foh);
784 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte204317e2009-08-06 17:58:31 +0200785 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100786 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200787 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100788 break;
789 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200790 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100791 break;
Harald Welte08011e22011-03-04 13:41:31 +0100792 case NM_MT_SET_BTS_ATTR_ACK:
Harald Welte08011e22011-03-04 13:41:31 +0100793 break;
Max07922cd2017-05-15 10:29:54 +0200794 case NM_MT_GET_ATTR_RESP:
Maxfa4b2b82017-05-29 11:48:29 +0200795 ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
Max07922cd2017-05-15 10:29:54 +0200796 break;
Max7efc2632017-04-04 19:21:24 +0200797 default:
798 abis_nm_debugp_foh(DNM, foh);
799 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
800 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +0800801 }
802
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100803 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100804 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800805}
806
807static int abis_nm_rx_ipacc(struct msgb *mb);
808
809static int abis_nm_rcvmsg_manuf(struct msgb *mb)
810{
811 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200812 struct e1inp_sign_link *sign_link = mb->dst;
813 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800814
815 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100816 case GSM_BTS_TYPE_NANOBTS:
Maxabf3eb12017-03-23 12:01:07 +0100817 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte59b04682009-06-10 05:40:52 +0800818 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200819 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800820 break;
821 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100822 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
823 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800824 rc = 0;
825 break;
826 }
827
828 return rc;
829}
830
831/* High-Level API */
832/* Entry-point where L2 OML from BTS enters the NM code */
833int abis_nm_rcvmsg(struct msgb *msg)
834{
835 struct abis_om_hdr *oh = msgb_l2(msg);
836 int rc = 0;
837
838 /* Various consistency checks */
839 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100840 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800841 oh->placement);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200842 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
843 rc = -EINVAL;
844 goto err;
845 }
Harald Welte59b04682009-06-10 05:40:52 +0800846 }
847 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100848 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800849 oh->sequence);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200850 rc = -EINVAL;
851 goto err;
Harald Welte59b04682009-06-10 05:40:52 +0800852 }
853#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200854 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800855 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
856 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100857 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800858 oh->length + sizeof(*oh), l2_len);
859 return -EINVAL;
860 }
861 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100862 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 +0800863#endif
864 msg->l3h = (unsigned char *)oh + sizeof(*oh);
865
866 switch (oh->mdisc) {
867 case ABIS_OM_MDISC_FOM:
868 rc = abis_nm_rcvmsg_fom(msg);
869 break;
870 case ABIS_OM_MDISC_MANUF:
871 rc = abis_nm_rcvmsg_manuf(msg);
872 break;
873 case ABIS_OM_MDISC_MMI:
874 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100875 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800876 oh->mdisc);
877 break;
878 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100879 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800880 oh->mdisc);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200881 rc = -EINVAL;
882 break;
Harald Welte59b04682009-06-10 05:40:52 +0800883 }
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200884err:
Harald Welte59b04682009-06-10 05:40:52 +0800885 msgb_free(msg);
886 return rc;
887}
888
889#if 0
890/* initialized all resources */
891struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
892{
893 struct abis_nm_h *nmh;
894
895 nmh = malloc(sizeof(*nmh));
896 if (!nmh)
897 return NULL;
898
899 nmh->cfg = cfg;
900
901 return nmh;
902}
903
904/* free all resources */
905void abis_nm_fini(struct abis_nm_h *nmh)
906{
907 free(nmh);
908}
909#endif
910
911/* Here we are trying to define a high-level API that can be used by
912 * the actual BSC implementation. However, the architecture is currently
913 * still under design. Ideally the calls to this API would be synchronous,
914 * while the underlying stack behind the APi runs in a traditional select
915 * based state machine.
916 */
917
918/* 6.2 Software Load: */
919enum sw_state {
920 SW_STATE_NONE,
921 SW_STATE_WAIT_INITACK,
922 SW_STATE_WAIT_SEGACK,
923 SW_STATE_WAIT_ENDACK,
924 SW_STATE_WAIT_ACTACK,
925 SW_STATE_ERROR,
926};
927
928struct abis_nm_sw {
929 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800930 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800931 gsm_cbfn *cbfn;
932 void *cb_data;
933 int forced;
934
935 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200936 uint8_t obj_class;
937 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800938
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200939 uint8_t file_id[255];
940 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800941
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200942 uint8_t file_version[255];
943 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800944
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200945 uint8_t window_size;
946 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800947
948 int fd;
949 FILE *stream;
950 enum sw_state state;
951 int last_seg;
952};
953
954static struct abis_nm_sw g_sw;
955
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100956static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
957{
958 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
959 msgb_v_put(msg, NM_ATT_SW_DESCR);
960 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
961 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
962 sw->file_version);
963 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
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 } else {
968 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
969 }
970}
971
Harald Welte59b04682009-06-10 05:40:52 +0800972/* 6.2.1 / 8.3.1: Load Data Initiate */
973static int sw_load_init(struct abis_nm_sw *sw)
974{
975 struct abis_om_hdr *oh;
976 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200977 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800978
979 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
980 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
981 sw->obj_instance[0], sw->obj_instance[1],
982 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100983
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100984 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800985 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
986
987 return abis_nm_sendmsg(sw->bts, msg);
988}
989
990static int is_last_line(FILE *stream)
991{
992 char next_seg_buf[256];
993 long pos;
994
995 /* check if we're sending the last line */
996 pos = ftell(stream);
Holger Hans Peter Freyther4c11d0b2014-04-04 11:48:32 +0200997
998 /* Did ftell fail? Then we are at the end for sure */
999 if (pos < 0)
1000 return 1;
1001
Harald Welte59b04682009-06-10 05:40:52 +08001002 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltead13b572016-11-26 14:11:16 +01001003 int rc = fseek(stream, pos, SEEK_SET);
1004 if (rc < 0)
1005 return rc;
Harald Welte59b04682009-06-10 05:40:52 +08001006 return 1;
1007 }
1008
1009 fseek(stream, pos, SEEK_SET);
1010 return 0;
1011}
1012
1013/* 6.2.2 / 8.3.2 Load Data Segment */
1014static int sw_load_segment(struct abis_nm_sw *sw)
1015{
1016 struct abis_om_hdr *oh;
1017 struct msgb *msg = nm_msgb_alloc();
1018 char seg_buf[256];
1019 char *line_buf = seg_buf+2;
1020 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +02001021 int len;
Harald Welte59b04682009-06-10 05:40:52 +08001022
1023 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1024
1025 switch (sw->bts->type) {
1026 case GSM_BTS_TYPE_BS11:
1027 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1028 perror("fgets reading segment");
1029 return -EINVAL;
1030 }
1031 seg_buf[0] = 0x00;
1032
1033 /* check if we're sending the last line */
1034 sw->last_seg = is_last_line(sw->stream);
1035 if (sw->last_seg)
1036 seg_buf[1] = 0;
1037 else
1038 seg_buf[1] = 1 + sw->seg_in_window++;
1039
1040 len = strlen(line_buf) + 2;
1041 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001042 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +08001043 /* BS11 wants CR + LF in excess of the TLV length !?! */
1044 tlv[1] -= 2;
1045
1046 /* we only now know the exact length for the OM hdr */
1047 len = strlen(line_buf)+2;
1048 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001049 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +02001050 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001051 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1052 if (len < 0) {
1053 perror("read failed");
1054 return -EINVAL;
1055 }
1056
1057 if (len != IPACC_SEGMENT_SIZE)
1058 sw->last_seg = 1;
1059
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001060 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001061 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001062 len += 3;
1063 break;
1064 }
Harald Welte59b04682009-06-10 05:40:52 +08001065 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001066 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001067 /* FIXME: Other BTS types */
1068 return -1;
1069 }
1070
1071 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1072 sw->obj_instance[0], sw->obj_instance[1],
1073 sw->obj_instance[2]);
1074
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001075 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001076}
1077
1078/* 6.2.4 / 8.3.4 Load Data End */
1079static int sw_load_end(struct abis_nm_sw *sw)
1080{
1081 struct abis_om_hdr *oh;
1082 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001083 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +08001084
1085 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1086 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1087 sw->obj_instance[0], sw->obj_instance[1],
1088 sw->obj_instance[2]);
1089
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001090 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001091 return abis_nm_sendmsg(sw->bts, msg);
1092}
1093
1094/* Activate the specified software into the BTS */
1095static int sw_activate(struct abis_nm_sw *sw)
1096{
1097 struct abis_om_hdr *oh;
1098 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001099 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +08001100
1101 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1102 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1103 sw->obj_instance[0], sw->obj_instance[1],
1104 sw->obj_instance[2]);
1105
1106 /* FIXME: this is BS11 specific format */
1107 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1108 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1109 sw->file_version);
1110
1111 return abis_nm_sendmsg(sw->bts, msg);
1112}
1113
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001114struct sdp_firmware {
1115 char magic[4];
1116 char more_magic[4];
1117 unsigned int header_length;
1118 unsigned int file_length;
1119} __attribute__ ((packed));
1120
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001121static int parse_sdp_header(struct abis_nm_sw *sw)
1122{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001123 struct sdp_firmware firmware_header;
1124 int rc;
1125 struct stat stat;
1126
1127 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1128 if (rc != sizeof(firmware_header)) {
1129 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1130 return -1;
1131 }
1132
1133 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1134 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1135 return -1;
1136 }
1137
1138 if (firmware_header.more_magic[0] != 0x10 ||
1139 firmware_header.more_magic[1] != 0x02 ||
1140 firmware_header.more_magic[2] != 0x00 ||
1141 firmware_header.more_magic[3] != 0x00) {
1142 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1143 return -1;
1144 }
1145
1146
1147 if (fstat(sw->fd, &stat) == -1) {
1148 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1149 return -1;
1150 }
1151
1152 if (ntohl(firmware_header.file_length) != stat.st_size) {
1153 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1154 return -1;
1155 }
1156
1157 /* go back to the start as we checked the whole filesize.. */
1158 lseek(sw->fd, 0l, SEEK_SET);
1159 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1160 "There might be checksums in the file that are not\n"
1161 "verified and incomplete firmware might be flashed.\n"
1162 "There is absolutely no WARRANTY that flashing will\n"
1163 "work.\n");
1164 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001165}
1166
Harald Welte59b04682009-06-10 05:40:52 +08001167static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1168{
1169 char file_id[12+1];
1170 char file_version[80+1];
1171 int rc;
1172
1173 sw->fd = open(fname, O_RDONLY);
1174 if (sw->fd < 0)
1175 return sw->fd;
1176
1177 switch (sw->bts->type) {
1178 case GSM_BTS_TYPE_BS11:
1179 sw->stream = fdopen(sw->fd, "r");
1180 if (!sw->stream) {
1181 perror("fdopen");
1182 return -1;
1183 }
1184 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001185 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001186 file_id, file_version);
1187 if (rc != 2) {
1188 perror("parsing header line of software file");
1189 return -1;
1190 }
1191 strcpy((char *)sw->file_id, file_id);
1192 sw->file_id_len = strlen(file_id);
1193 strcpy((char *)sw->file_version, file_version);
1194 sw->file_version_len = strlen(file_version);
1195 /* rewind to start of file */
1196 rewind(sw->stream);
1197 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001198 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001199 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001200 rc = parse_sdp_header(sw);
1201 if (rc < 0) {
1202 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1203 return -1;
1204 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001205
1206 strcpy((char *)sw->file_id, "id");
1207 sw->file_id_len = 3;
1208 strcpy((char *)sw->file_version, "version");
1209 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001210 break;
Harald Welte59b04682009-06-10 05:40:52 +08001211 default:
1212 /* We don't know how to treat them yet */
1213 close(sw->fd);
1214 return -EINVAL;
1215 }
1216
1217 return 0;
1218}
1219
1220static void sw_close_file(struct abis_nm_sw *sw)
1221{
1222 switch (sw->bts->type) {
1223 case GSM_BTS_TYPE_BS11:
1224 fclose(sw->stream);
1225 break;
1226 default:
1227 close(sw->fd);
1228 break;
1229 }
1230}
1231
1232/* Fill the window */
1233static int sw_fill_window(struct abis_nm_sw *sw)
1234{
1235 int rc;
1236
1237 while (sw->seg_in_window < sw->window_size) {
1238 rc = sw_load_segment(sw);
1239 if (rc < 0)
1240 return rc;
1241 if (sw->last_seg)
1242 break;
1243 }
1244 return 0;
1245}
1246
1247/* callback function from abis_nm_rcvmsg() handler */
1248static int abis_nm_rcvmsg_sw(struct msgb *mb)
1249{
1250 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001251 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001252 int rc = -1;
1253 struct abis_nm_sw *sw = &g_sw;
1254 enum sw_state old_state = sw->state;
1255
1256 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1257
1258 switch (sw->state) {
1259 case SW_STATE_WAIT_INITACK:
1260 switch (foh->msg_type) {
1261 case NM_MT_LOAD_INIT_ACK:
1262 /* fill window with segments */
1263 if (sw->cbfn)
1264 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1265 NM_MT_LOAD_INIT_ACK, mb,
1266 sw->cb_data, NULL);
1267 rc = sw_fill_window(sw);
1268 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001269 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001270 break;
1271 case NM_MT_LOAD_INIT_NACK:
1272 if (sw->forced) {
1273 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1274 "Init NACK\n");
1275 if (sw->cbfn)
1276 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1277 NM_MT_LOAD_INIT_ACK, mb,
1278 sw->cb_data, NULL);
1279 rc = sw_fill_window(sw);
1280 sw->state = SW_STATE_WAIT_SEGACK;
1281 } else {
1282 DEBUGP(DNM, "Software Load Init NACK\n");
1283 /* FIXME: cause */
1284 if (sw->cbfn)
1285 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1286 NM_MT_LOAD_INIT_NACK, mb,
1287 sw->cb_data, NULL);
1288 sw->state = SW_STATE_ERROR;
1289 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001290 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001291 break;
1292 }
1293 break;
1294 case SW_STATE_WAIT_SEGACK:
1295 switch (foh->msg_type) {
1296 case NM_MT_LOAD_SEG_ACK:
1297 if (sw->cbfn)
1298 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1299 NM_MT_LOAD_SEG_ACK, mb,
1300 sw->cb_data, NULL);
1301 sw->seg_in_window = 0;
1302 if (!sw->last_seg) {
1303 /* fill window with more segments */
1304 rc = sw_fill_window(sw);
1305 sw->state = SW_STATE_WAIT_SEGACK;
1306 } else {
1307 /* end the transfer */
1308 sw->state = SW_STATE_WAIT_ENDACK;
1309 rc = sw_load_end(sw);
1310 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001311 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001312 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001313 case NM_MT_LOAD_ABORT:
1314 if (sw->cbfn)
1315 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1316 NM_MT_LOAD_ABORT, mb,
1317 sw->cb_data, NULL);
1318 break;
Harald Welte59b04682009-06-10 05:40:52 +08001319 }
1320 break;
1321 case SW_STATE_WAIT_ENDACK:
1322 switch (foh->msg_type) {
1323 case NM_MT_LOAD_END_ACK:
1324 sw_close_file(sw);
1325 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1326 sw->bts->nr);
1327 sw->state = SW_STATE_NONE;
1328 if (sw->cbfn)
1329 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1330 NM_MT_LOAD_END_ACK, mb,
1331 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001332 rc = 0;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001333 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001334 break;
1335 case NM_MT_LOAD_END_NACK:
1336 if (sw->forced) {
1337 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1338 "End NACK\n");
1339 sw->state = SW_STATE_NONE;
1340 if (sw->cbfn)
1341 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1342 NM_MT_LOAD_END_ACK, mb,
1343 sw->cb_data, NULL);
1344 } else {
1345 DEBUGP(DNM, "Software Load End NACK\n");
1346 /* FIXME: cause */
1347 sw->state = SW_STATE_ERROR;
1348 if (sw->cbfn)
1349 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1350 NM_MT_LOAD_END_NACK, mb,
1351 sw->cb_data, NULL);
1352 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001353 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001354 break;
1355 }
1356 case SW_STATE_WAIT_ACTACK:
1357 switch (foh->msg_type) {
1358 case NM_MT_ACTIVATE_SW_ACK:
1359 /* we're done */
1360 DEBUGP(DNM, "Activate Software DONE!\n");
1361 sw->state = SW_STATE_NONE;
1362 rc = 0;
1363 if (sw->cbfn)
1364 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1365 NM_MT_ACTIVATE_SW_ACK, mb,
1366 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001367 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001368 break;
1369 case NM_MT_ACTIVATE_SW_NACK:
1370 DEBUGP(DNM, "Activate Software NACK\n");
1371 /* FIXME: cause */
1372 sw->state = SW_STATE_ERROR;
1373 if (sw->cbfn)
1374 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1375 NM_MT_ACTIVATE_SW_NACK, mb,
1376 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001377 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001378 break;
1379 }
1380 case SW_STATE_NONE:
1381 switch (foh->msg_type) {
1382 case NM_MT_ACTIVATE_SW_ACK:
1383 rc = 0;
1384 break;
1385 }
1386 break;
1387 case SW_STATE_ERROR:
1388 break;
1389 }
1390
1391 if (rc)
1392 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1393 foh->msg_type, old_state, sw->state);
1394
1395 return rc;
1396}
1397
1398/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001399int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001400 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001401 gsm_cbfn *cbfn, void *cb_data)
1402{
1403 struct abis_nm_sw *sw = &g_sw;
1404 int rc;
1405
1406 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1407 bts->nr, fname);
1408
1409 if (sw->state != SW_STATE_NONE)
1410 return -EBUSY;
1411
1412 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001413 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001414
1415 switch (bts->type) {
1416 case GSM_BTS_TYPE_BS11:
1417 sw->obj_class = NM_OC_SITE_MANAGER;
1418 sw->obj_instance[0] = 0xff;
1419 sw->obj_instance[1] = 0xff;
1420 sw->obj_instance[2] = 0xff;
1421 break;
1422 case GSM_BTS_TYPE_NANOBTS:
1423 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001424 sw->obj_instance[0] = sw->bts->nr;
1425 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001426 sw->obj_instance[2] = 0xff;
1427 break;
1428 case GSM_BTS_TYPE_UNKNOWN:
1429 default:
1430 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1431 return -1;
1432 break;
1433 }
Harald Welte59b04682009-06-10 05:40:52 +08001434 sw->window_size = win_size;
1435 sw->state = SW_STATE_WAIT_INITACK;
1436 sw->cbfn = cbfn;
1437 sw->cb_data = cb_data;
1438 sw->forced = forced;
1439
1440 rc = sw_open_file(sw, fname);
1441 if (rc < 0) {
1442 sw->state = SW_STATE_NONE;
1443 return rc;
1444 }
1445
1446 return sw_load_init(sw);
1447}
1448
1449int abis_nm_software_load_status(struct gsm_bts *bts)
1450{
1451 struct abis_nm_sw *sw = &g_sw;
1452 struct stat st;
1453 int rc, percent;
1454
1455 rc = fstat(sw->fd, &st);
1456 if (rc < 0) {
1457 perror("ERROR during stat");
1458 return rc;
1459 }
1460
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001461 if (sw->stream)
1462 percent = (ftell(sw->stream) * 100) / st.st_size;
1463 else
1464 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001465 return percent;
1466}
1467
1468/* Activate the specified software into the BTS */
1469int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1470 gsm_cbfn *cbfn, void *cb_data)
1471{
1472 struct abis_nm_sw *sw = &g_sw;
1473 int rc;
1474
1475 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1476 bts->nr, fname);
1477
1478 if (sw->state != SW_STATE_NONE)
1479 return -EBUSY;
1480
1481 sw->bts = bts;
1482 sw->obj_class = NM_OC_SITE_MANAGER;
1483 sw->obj_instance[0] = 0xff;
1484 sw->obj_instance[1] = 0xff;
1485 sw->obj_instance[2] = 0xff;
1486 sw->state = SW_STATE_WAIT_ACTACK;
1487 sw->cbfn = cbfn;
1488 sw->cb_data = cb_data;
1489
1490 /* Open the file in order to fill some sw struct members */
1491 rc = sw_open_file(sw, fname);
1492 if (rc < 0) {
1493 sw->state = SW_STATE_NONE;
1494 return rc;
1495 }
1496 sw_close_file(sw);
1497
1498 return sw_activate(sw);
1499}
1500
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001501static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1502 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001503{
1504 ch->attrib = NM_ATT_ABIS_CHANNEL;
1505 ch->bts_port = bts_port;
1506 ch->timeslot = ts_nr;
1507 ch->subslot = subslot_nr;
1508}
1509
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001510int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1511 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1512 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001513{
1514 struct abis_om_hdr *oh;
1515 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001516 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001517 struct msgb *msg = nm_msgb_alloc();
1518
1519 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1520 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1521 bts->bts_nr, trx_nr, 0xff);
1522
1523 msgb_tv_put(msg, NM_ATT_TEI, tei);
1524
1525 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1526 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1527
1528 return abis_nm_sendmsg(bts, msg);
1529}
1530
1531/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1532int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001533 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001534{
1535 struct gsm_bts *bts = trx->bts;
1536 struct abis_om_hdr *oh;
1537 struct abis_nm_channel *ch;
1538 struct msgb *msg = nm_msgb_alloc();
1539
1540 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1541 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1542 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1543
1544 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1545 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1546
1547 return abis_nm_sendmsg(bts, msg);
1548}
1549
1550#if 0
1551int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1552 struct abis_nm_abis_channel *chan)
1553{
1554}
1555#endif
1556
1557int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001558 uint8_t e1_port, uint8_t e1_timeslot,
1559 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001560{
1561 struct gsm_bts *bts = ts->trx->bts;
1562 struct abis_om_hdr *oh;
1563 struct abis_nm_channel *ch;
1564 struct msgb *msg = nm_msgb_alloc();
1565
1566 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1567 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1568 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1569
1570 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1571 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1572
1573 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1574 gsm_ts_name(ts),
1575 e1_port, e1_timeslot, e1_subslot);
1576
1577 return abis_nm_sendmsg(bts, msg);
1578}
1579
1580#if 0
1581int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1582 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001583 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001584{
1585}
1586#endif
1587
Maxc81178a2017-05-10 12:21:17 +02001588/* 3GPP TS 52.021 § 8.11.1 */
1589int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1590 const uint8_t *attr, uint8_t attr_len)
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001591{
1592 struct abis_om_hdr *oh;
1593 struct msgb *msg = nm_msgb_alloc();
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001594
1595 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1596
1597 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1598 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1599 bts_nr, trx_nr, ts_nr);
1600 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1601
1602 return abis_nm_sendmsg(bts, msg);
1603}
1604
Harald Welte59b04682009-06-10 05:40:52 +08001605/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001606int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001607{
1608 struct abis_om_hdr *oh;
1609 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001610 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001611
1612 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1613
1614 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1615 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1616 cur = msgb_put(msg, attr_len);
1617 memcpy(cur, attr, attr_len);
1618
1619 return abis_nm_sendmsg(bts, msg);
1620}
1621
1622/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001623int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001624{
1625 struct abis_om_hdr *oh;
1626 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001627 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001628
1629 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1630
1631 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1632 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1633 trx->bts->bts_nr, trx->nr, 0xff);
1634 cur = msgb_put(msg, attr_len);
1635 memcpy(cur, attr, attr_len);
1636
1637 return abis_nm_sendmsg(trx->bts, msg);
1638}
1639
Holger Hans Peter Freyther1f672322014-03-26 14:24:42 +01001640int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1641{
1642 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1643 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1644}
1645
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001646static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1647 const char **reason)
Harald Weltef2eb2782009-08-09 21:49:48 +02001648{
1649 int i;
1650
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001651 *reason = "Reason unknown";
1652
Harald Weltef2eb2782009-08-09 21:49:48 +02001653 /* As it turns out, the BS-11 has some very peculiar restrictions
1654 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301655 switch (ts->trx->bts->type) {
1656 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001657 switch (chan_comb) {
1658 case NM_CHANC_TCHHalf:
1659 case NM_CHANC_TCHHalf2:
Neels Hofmeyr5af61132016-07-14 03:09:56 +02001660 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Weltef2eb2782009-08-09 21:49:48 +02001661 /* not supported */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001662 *reason = "TCH/H is not supported.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001663 return -EINVAL;
1664 case NM_CHANC_SDCCH:
1665 /* only one SDCCH/8 per TRX */
1666 for (i = 0; i < TRX_NR_TS; i++) {
1667 if (i == ts->nr)
1668 continue;
1669 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001670 NM_CHANC_SDCCH) {
1671 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001672 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001673 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001674 }
1675 /* not allowed for TS0 of BCCH-TRX */
1676 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001677 ts->nr == 0) {
1678 *reason = "SDCCH/8 must be on TS0.";
1679 return -EINVAL;
1680 }
1681
Harald Weltef2eb2782009-08-09 21:49:48 +02001682 /* not on the same TRX that has a BCCH+SDCCH4
1683 * combination */
Holger Hans Peter Freytherfca3eb92013-01-08 19:30:14 +01001684 if (ts->trx != ts->trx->bts->c0 &&
Harald Weltef2eb2782009-08-09 21:49:48 +02001685 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001686 ts->trx->ts[0].nm_chan_comb == 8)) {
1687 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1688 return -EINVAL;
1689 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001690 break;
1691 case NM_CHANC_mainBCCH:
1692 case NM_CHANC_BCCHComb:
1693 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001694 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1695 *reason = "Main BCCH must be on TS0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001696 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001697 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001698 break;
1699 case NM_CHANC_BCCH:
1700 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001701 if (ts->trx != ts->trx->bts->c0) {
1702 *reason = "BCCH must be on C0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001703 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001704 }
1705 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1706 *reason = "BCCH must be on TS 2/4/6.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001707 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001708 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001709 break;
1710 case 8: /* this is not like 08.58, but in fact
1711 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1712 /* FIXME: only one CBCH allowed per cell */
1713 break;
1714 }
Harald Welte76ba8812009-12-02 02:45:23 +05301715 break;
1716 case GSM_BTS_TYPE_NANOBTS:
1717 switch (ts->nr) {
1718 case 0:
1719 if (ts->trx->nr == 0) {
1720 /* only on TRX0 */
1721 switch (chan_comb) {
1722 case NM_CHANC_BCCH:
1723 case NM_CHANC_mainBCCH:
1724 case NM_CHANC_BCCHComb:
1725 return 0;
1726 break;
1727 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001728 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301729 return -EINVAL;
1730 }
1731 } else {
1732 switch (chan_comb) {
1733 case NM_CHANC_TCHFull:
1734 case NM_CHANC_TCHHalf:
1735 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1736 return 0;
1737 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001738 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welte76ba8812009-12-02 02:45:23 +05301739 return -EINVAL;
1740 }
1741 }
1742 break;
1743 case 1:
1744 if (ts->trx->nr == 0) {
1745 switch (chan_comb) {
1746 case NM_CHANC_SDCCH_CBCH:
1747 if (ts->trx->ts[0].nm_chan_comb ==
1748 NM_CHANC_mainBCCH)
1749 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001750 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301751 return -EINVAL;
1752 case NM_CHANC_SDCCH:
1753 case NM_CHANC_TCHFull:
1754 case NM_CHANC_TCHHalf:
1755 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1756 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr5af61132016-07-14 03:09:56 +02001757 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte76ba8812009-12-02 02:45:23 +05301758 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001759 default:
1760 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1761 return -EINVAL;
Harald Welte76ba8812009-12-02 02:45:23 +05301762 }
1763 } else {
1764 switch (chan_comb) {
1765 case NM_CHANC_SDCCH:
1766 case NM_CHANC_TCHFull:
1767 case NM_CHANC_TCHHalf:
1768 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1769 return 0;
1770 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001771 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301772 return -EINVAL;
1773 }
1774 }
1775 break;
1776 case 2:
1777 case 3:
1778 case 4:
1779 case 5:
1780 case 6:
1781 case 7:
1782 switch (chan_comb) {
1783 case NM_CHANC_TCHFull:
1784 case NM_CHANC_TCHHalf:
1785 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1786 return 0;
1787 case NM_CHANC_IPAC_PDCH:
1788 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr5af61132016-07-14 03:09:56 +02001789 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte76ba8812009-12-02 02:45:23 +05301790 if (ts->trx->nr == 0)
1791 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001792 else {
1793 *reason = "PDCH must be on TRX0.";
Harald Welte76ba8812009-12-02 02:45:23 +05301794 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001795 }
Harald Welte76ba8812009-12-02 02:45:23 +05301796 }
1797 break;
1798 }
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001799 *reason = "Unknown combination";
Harald Welte76ba8812009-12-02 02:45:23 +05301800 return -EINVAL;
Maxabf3eb12017-03-23 12:01:07 +01001801 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte35ac0e42012-07-02 19:51:55 +02001802 /* no known restrictions */
1803 return 0;
Harald Welte76ba8812009-12-02 02:45:23 +05301804 default:
1805 /* unknown BTS type */
1806 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001807 }
1808 return 0;
1809}
1810
Harald Welte59b04682009-06-10 05:40:52 +08001811/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001812int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001813{
1814 struct gsm_bts *bts = ts->trx->bts;
1815 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001816 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001817 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001818 uint8_t len = 2 + 2;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001819 const char *reason = NULL;
Harald Welte59b04682009-06-10 05:40:52 +08001820
1821 if (bts->type == GSM_BTS_TYPE_BS11)
1822 len += 4 + 2 + 2 + 3;
1823
1824 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001825 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Weltef2eb2782009-08-09 21:49:48 +02001826 msgb_free(msg);
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001827 LOGP(DNM, LOGL_ERROR,
1828 "Invalid Channel Combination %d on %s. Reason: %s\n",
1829 chan_comb, gsm_ts_name(ts), reason);
Harald Weltef2eb2782009-08-09 21:49:48 +02001830 return -EINVAL;
1831 }
1832 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001833
1834 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1835 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1836 NM_OC_CHANNEL, bts->bts_nr,
1837 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001838 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001839 if (ts->hopping.enabled) {
1840 unsigned int i;
1841 uint8_t *len;
1842
Harald Welte67104d12009-09-12 13:05:33 +02001843 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1844 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001845
1846 /* build the ARFCN list */
1847 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1848 len = msgb_put(msg, 1);
1849 *len = 0;
1850 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1851 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1852 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001853 /* At least BS-11 wants a TLV16 here */
1854 if (bts->type == GSM_BTS_TYPE_BS11)
1855 *len += 1;
1856 else
1857 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001858 }
1859 }
Harald Welte59b04682009-06-10 05:40:52 +08001860 }
Harald Welte025e6c92014-01-19 17:18:21 +01001861 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001862 if (bts->type == GSM_BTS_TYPE_BS11)
1863 msgb_tlv_put(msg, 0x59, 1, &zero);
1864
1865 return abis_nm_sendmsg(bts, msg);
1866}
1867
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001868int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1869 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001870{
1871 struct abis_om_hdr *oh;
1872 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001873 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1874 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001875
1876 if (nack) {
1877 len += 2;
1878 msgtype = NM_MT_SW_ACT_REQ_NACK;
1879 }
1880
1881 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1882 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1883
1884 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001885 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001886 memcpy(ptr, attr, att_len);
1887 }
1888 if (nack)
1889 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1890
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001891 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001892}
1893
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001894int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001895{
1896 struct msgb *msg = nm_msgb_alloc();
1897 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001898 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001899
1900 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1901 fill_om_hdr(oh, len);
1902 data = msgb_put(msg, len);
1903 memcpy(data, rawmsg, len);
1904
1905 return abis_nm_sendmsg(bts, msg);
1906}
1907
1908/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001909static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001910{
1911 struct abis_om_hdr *oh;
1912 struct msgb *msg = nm_msgb_alloc();
1913
1914 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1915 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1916 0xff, 0xff, 0xff);
1917
1918 return abis_nm_sendmsg(bts, msg);
1919}
1920
1921/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001922int 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 +08001923{
1924 struct abis_om_hdr *oh;
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +02001925 struct abis_om_fom_hdr *foh;
Harald Welte59b04682009-06-10 05:40:52 +08001926 struct msgb *msg = nm_msgb_alloc();
1927
Harald Welte59b04682009-06-10 05:40:52 +08001928 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +02001929 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte59b04682009-06-10 05:40:52 +08001930
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +02001931 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +02001932 DEBUGPC(DNM, "Sending OPSTART\n");
1933
Harald Welte59b04682009-06-10 05:40:52 +08001934 return abis_nm_sendmsg(bts, msg);
1935}
1936
1937/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001938int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1939 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001940{
1941 struct abis_om_hdr *oh;
1942 struct msgb *msg = nm_msgb_alloc();
1943
1944 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1945 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1946 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1947
1948 return abis_nm_sendmsg(bts, msg);
1949}
1950
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001951int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1952 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001953{
1954 struct abis_om_hdr *oh;
1955 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001956 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001957
1958 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1959 e1_port0, ts0, e1_port1, ts1);
1960
1961 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1962 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1963 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1964
1965 attr = msgb_put(msg, 3);
1966 attr[0] = NM_ATT_MDROP_LINK;
1967 attr[1] = e1_port0;
1968 attr[2] = ts0;
1969
1970 attr = msgb_put(msg, 3);
1971 attr[0] = NM_ATT_MDROP_NEXT;
1972 attr[1] = e1_port1;
1973 attr[2] = ts1;
1974
1975 return abis_nm_sendmsg(bts, msg);
1976}
Harald Welte59b04682009-06-10 05:40:52 +08001977
Harald Welte0bf8e302009-08-08 00:02:36 +02001978/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001979int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1980 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1981 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001982{
1983 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001984
Harald Weltec61a90e2011-05-22 22:45:37 +02001985 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001986
1987 if (!msg)
1988 msg = nm_msgb_alloc();
1989
1990 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1991 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1992 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1993 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001994 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001995
1996 return abis_nm_sendmsg(bts, msg);
1997}
1998
Harald Welte59b04682009-06-10 05:40:52 +08001999int abis_nm_event_reports(struct gsm_bts *bts, int on)
2000{
2001 if (on == 0)
2002 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2003 else
2004 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2005}
2006
2007/* Siemens (or BS-11) specific commands */
2008
2009int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2010{
2011 if (reconnect == 0)
2012 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2013 else
2014 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2015}
2016
2017int abis_nm_bs11_restart(struct gsm_bts *bts)
2018{
2019 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2020}
2021
2022
2023struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002024 uint16_t year;
2025 uint8_t month;
2026 uint8_t day;
2027 uint8_t hour;
2028 uint8_t min;
2029 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08002030} __attribute__((packed));
2031
2032
2033void get_bs11_date_time(struct bs11_date_time *aet)
2034{
2035 time_t t;
2036 struct tm *tm;
2037
2038 t = time(NULL);
2039 tm = localtime(&t);
2040 aet->sec = tm->tm_sec;
2041 aet->min = tm->tm_min;
2042 aet->hour = tm->tm_hour;
2043 aet->day = tm->tm_mday;
2044 aet->month = tm->tm_mon;
2045 aet->year = htons(1900 + tm->tm_year);
2046}
2047
2048int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2049{
2050 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2051}
2052
2053int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2054{
2055 if (begin)
2056 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2057 else
2058 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2059}
2060
2061int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002062 enum abis_bs11_objtype type, uint8_t idx,
2063 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08002064{
2065 struct abis_om_hdr *oh;
2066 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002067 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08002068
2069 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2070 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2071 NM_OC_BS11, type, 0, idx);
2072 cur = msgb_put(msg, attr_len);
2073 memcpy(cur, attr, attr_len);
2074
2075 return abis_nm_sendmsg(bts, msg);
2076}
2077
2078int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002079 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08002080{
2081 struct abis_om_hdr *oh;
2082 struct msgb *msg = nm_msgb_alloc();
2083
2084 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2085 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2086 NM_OC_BS11, type, 0, idx);
2087
2088 return abis_nm_sendmsg(bts, msg);
2089}
2090
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002091int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08002092{
2093 struct abis_om_hdr *oh;
2094 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002095 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08002096
2097 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2098 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2099 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2100 msgb_tlv_put(msg, 0x99, 1, &zero);
2101
2102 return abis_nm_sendmsg(bts, msg);
2103}
2104
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002105int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08002106{
2107 struct abis_om_hdr *oh;
2108 struct msgb *msg = nm_msgb_alloc();
2109
2110 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2111 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002112 idx, 0xff, 0xff);
2113
2114 return abis_nm_sendmsg(bts, msg);
2115}
2116
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002117int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02002118{
2119 struct abis_om_hdr *oh;
2120 struct msgb *msg = nm_msgb_alloc();
2121
2122 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2123 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2124 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002125
2126 return abis_nm_sendmsg(bts, msg);
2127}
2128
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002129static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08002130int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2131{
2132 struct abis_om_hdr *oh;
2133 struct msgb *msg = nm_msgb_alloc();
2134
2135 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2136 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2137 0xff, 0xff, 0xff);
2138 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2139
2140 return abis_nm_sendmsg(bts, msg);
2141}
2142
2143/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002144int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2145 uint8_t e1_timeslot, uint8_t e1_subslot,
2146 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08002147{
2148 struct abis_om_hdr *oh;
2149 struct abis_nm_channel *ch;
2150 struct msgb *msg = nm_msgb_alloc();
2151
2152 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2153 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2154 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2155
2156 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2157 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2158 msgb_tv_put(msg, NM_ATT_TEI, tei);
2159
2160 return abis_nm_sendmsg(bts, msg);
2161}
2162
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002163int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08002164{
2165 struct abis_om_hdr *oh;
2166 struct msgb *msg = nm_msgb_alloc();
2167
2168 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2169 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2170 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2171 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2172
2173 return abis_nm_sendmsg(trx->bts, msg);
2174}
2175
2176int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2177{
2178 struct abis_om_hdr *oh;
2179 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002180 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08002181
2182 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2183 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2184 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2185 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2186
2187 return abis_nm_sendmsg(trx->bts, msg);
2188}
2189
2190int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2191{
2192 struct abis_om_hdr *oh;
2193 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002194 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08002195
2196 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2197 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2198 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2199 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2200
2201 return abis_nm_sendmsg(bts, msg);
2202}
2203
2204int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2205{
2206 struct abis_om_hdr *oh;
2207 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002208 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08002209 NM_ATT_BS11_CCLK_TYPE };
2210
2211 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2212 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2213 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2214 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2215
2216 return abis_nm_sendmsg(bts, msg);
2217
2218}
2219
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002220//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002221
2222int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2223{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002224 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2225}
2226
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002227int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2228{
2229 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2230}
2231
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002232int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002233{
Harald Welte59b04682009-06-10 05:40:52 +08002234 struct abis_om_hdr *oh;
2235 struct msgb *msg = nm_msgb_alloc();
2236 struct bs11_date_time bdt;
2237
2238 get_bs11_date_time(&bdt);
2239
2240 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2241 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002242 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002243 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002244 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2245 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2246 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002247 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08002248 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002249 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002250 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002251 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002252 } else {
2253 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2254 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2255 }
2256
2257 return abis_nm_sendmsg(bts, msg);
2258}
2259
2260int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2261{
2262 struct abis_om_hdr *oh;
2263 struct msgb *msg;
2264
2265 if (strlen(password) != 10)
2266 return -EINVAL;
2267
2268 msg = nm_msgb_alloc();
2269 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2270 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2271 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002272 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002273
2274 return abis_nm_sendmsg(bts, msg);
2275}
2276
2277/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2278int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2279{
2280 struct abis_om_hdr *oh;
2281 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002282 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002283
2284 msg = nm_msgb_alloc();
2285 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2286 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2287 BS11_OBJ_LI, 0x00, 0x00);
2288
2289 if (locked)
2290 tlv_value = BS11_LI_PLL_LOCKED;
2291 else
2292 tlv_value = BS11_LI_PLL_STANDALONE;
2293
2294 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2295
2296 return abis_nm_sendmsg(bts, msg);
2297}
2298
Daniel Willmann10b07db2010-01-07 00:54:01 +01002299/* Set the calibration value of the PLL (work value/set value)
2300 * It depends on the login which one is changed */
2301int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2302{
2303 struct abis_om_hdr *oh;
2304 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002305 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002306
2307 msg = nm_msgb_alloc();
2308 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2309 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2310 BS11_OBJ_TRX1, 0x00, 0x00);
2311
2312 tlv_value[0] = value>>8;
2313 tlv_value[1] = value&0xff;
2314
2315 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2316
2317 return abis_nm_sendmsg(bts, msg);
2318}
2319
Harald Welte59b04682009-06-10 05:40:52 +08002320int abis_nm_bs11_get_state(struct gsm_bts *bts)
2321{
2322 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2323}
2324
2325/* BS11 SWL */
2326
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002327void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002328
Harald Welte59b04682009-06-10 05:40:52 +08002329struct abis_nm_bs11_sw {
2330 struct gsm_bts *bts;
2331 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002332 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002333 int forced;
2334 struct llist_head file_list;
2335 gsm_cbfn *user_cb; /* specified by the user */
2336};
2337static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2338
2339struct file_list_entry {
2340 struct llist_head list;
2341 char fname[PATH_MAX];
2342};
2343
2344struct file_list_entry *fl_dequeue(struct llist_head *queue)
2345{
2346 struct llist_head *lh;
2347
2348 if (llist_empty(queue))
2349 return NULL;
2350
2351 lh = queue->next;
2352 llist_del(lh);
2353
2354 return llist_entry(lh, struct file_list_entry, list);
2355}
2356
2357static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2358{
2359 char linebuf[255];
2360 struct llist_head *lh, *lh2;
2361 FILE *swl;
2362 int rc = 0;
2363
2364 swl = fopen(bs11_sw->swl_fname, "r");
2365 if (!swl)
2366 return -ENODEV;
2367
2368 /* zero the stale file list, if any */
2369 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2370 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002371 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002372 }
2373
2374 while (fgets(linebuf, sizeof(linebuf), swl)) {
2375 char file_id[12+1];
2376 char file_version[80+1];
2377 struct file_list_entry *fle;
2378 static char dir[PATH_MAX];
2379
2380 if (strlen(linebuf) < 4)
2381 continue;
2382
2383 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2384 if (rc < 0) {
2385 perror("ERR parsing SWL file");
2386 rc = -EINVAL;
2387 goto out;
2388 }
2389 if (rc < 2)
2390 continue;
2391
Harald Welte857e00d2009-06-26 20:25:23 +02002392 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002393 if (!fle) {
2394 rc = -ENOMEM;
2395 goto out;
2396 }
Harald Welte59b04682009-06-10 05:40:52 +08002397
2398 /* construct new filename */
Neels Hofmeyr5644c2b2017-01-13 03:12:08 +01002399 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte59b04682009-06-10 05:40:52 +08002400 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2401 strcat(fle->fname, "/");
2402 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2403
2404 llist_add_tail(&fle->list, &bs11_sw->file_list);
2405 }
2406
2407out:
2408 fclose(swl);
2409 return rc;
2410}
2411
2412/* bs11 swload specific callback, passed to abis_nm core swload */
2413static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2414 struct msgb *msg, void *data, void *param)
2415{
2416 struct abis_nm_bs11_sw *bs11_sw = data;
2417 struct file_list_entry *fle;
2418 int rc = 0;
2419
2420 switch (event) {
2421 case NM_MT_LOAD_END_ACK:
2422 fle = fl_dequeue(&bs11_sw->file_list);
2423 if (fle) {
2424 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002425 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002426 bs11_sw->win_size,
2427 bs11_sw->forced,
2428 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002429 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002430 } else {
2431 /* activate the SWL */
2432 rc = abis_nm_software_activate(bs11_sw->bts,
2433 bs11_sw->swl_fname,
2434 bs11_swload_cbfn,
2435 bs11_sw);
2436 }
2437 break;
2438 case NM_MT_LOAD_SEG_ACK:
2439 case NM_MT_LOAD_END_NACK:
2440 case NM_MT_LOAD_INIT_ACK:
2441 case NM_MT_LOAD_INIT_NACK:
2442 case NM_MT_ACTIVATE_SW_NACK:
2443 case NM_MT_ACTIVATE_SW_ACK:
2444 default:
2445 /* fallthrough to the user callback */
2446 if (bs11_sw->user_cb)
2447 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2448 break;
2449 }
2450
2451 return rc;
2452}
2453
2454/* Siemens provides a SWL file that is a mere listing of all the other
2455 * files that are part of a software release. We need to upload first
2456 * the list file, and then each file that is listed in the list file */
2457int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002458 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002459{
2460 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2461 struct file_list_entry *fle;
2462 int rc = 0;
2463
2464 INIT_LLIST_HEAD(&bs11_sw->file_list);
2465 bs11_sw->bts = bts;
2466 bs11_sw->win_size = win_size;
2467 bs11_sw->user_cb = cbfn;
2468 bs11_sw->forced = forced;
2469
Neels Hofmeyr5644c2b2017-01-13 03:12:08 +01002470 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte59b04682009-06-10 05:40:52 +08002471 rc = bs11_read_swl_file(bs11_sw);
2472 if (rc < 0)
2473 return rc;
2474
2475 /* dequeue next item in file list */
2476 fle = fl_dequeue(&bs11_sw->file_list);
2477 if (!fle)
2478 return -EINVAL;
2479
2480 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002481 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002482 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002483 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002484 return rc;
2485}
2486
2487#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002488static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002489 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2490 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2491 NM_ATT_BS11_LMT_USER_NAME,
2492
2493 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2494
2495 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2496
2497 NM_ATT_BS11_SW_LOAD_STORED };
2498
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002499static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002500 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2501 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2502 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2503 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2504#endif
2505
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002506static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002507 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2508 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2509 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2510
2511int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2512{
2513 struct abis_om_hdr *oh;
2514 struct msgb *msg = nm_msgb_alloc();
2515
2516 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2517 /* SiemensHW CCTRL object */
2518 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2519 0x03, 0x00, 0x00);
2520 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2521
2522 return abis_nm_sendmsg(bts, msg);
2523}
2524
2525int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2526{
2527 struct abis_om_hdr *oh;
2528 struct msgb *msg = nm_msgb_alloc();
2529 struct bs11_date_time aet;
2530
2531 get_bs11_date_time(&aet);
2532 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2533 /* SiemensHW CCTRL object */
2534 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2535 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002536 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002537
2538 return abis_nm_sendmsg(bts, msg);
2539}
2540
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002541int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002542{
2543 struct abis_om_hdr *oh;
2544 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002545 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002546
2547 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2548 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2549 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2550 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2551
2552 return abis_nm_sendmsg(bts, msg);
2553}
2554
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002555int 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 +02002556{
2557 struct abis_om_hdr *oh;
2558 struct msgb *msg = nm_msgb_alloc();
2559 struct bs11_date_time aet;
2560
2561 get_bs11_date_time(&aet);
2562 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2563 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2564 bport, 0xff, 0x02);
2565 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2566
2567 return abis_nm_sendmsg(bts, msg);
2568}
2569
Harald Welte59b04682009-06-10 05:40:52 +08002570/* ip.access nanoBTS specific commands */
2571static const char ipaccess_magic[] = "com.ipaccess";
2572
2573
2574static int abis_nm_rx_ipacc(struct msgb *msg)
2575{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002576 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002577 struct abis_om_hdr *oh = msgb_l2(msg);
2578 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002579 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002580 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002581 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002582 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002583
2584 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002585 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002586 return -EINVAL;
2587 }
2588
2589 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002590 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002591
Harald Weltec61a90e2011-05-22 22:45:37 +02002592 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002593
Harald Welte5aeedd42009-10-19 22:11:11 +02002594 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002595
2596 switch (foh->msg_type) {
2597 case NM_MT_IPACC_RSL_CONNECT_ACK:
2598 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002599 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2600 memcpy(&addr,
2601 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2602
2603 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2604 }
Harald Welte4206d982009-07-12 09:33:54 +02002605 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002606 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002607 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002608 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002609 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2610 DEBUGPC(DNM, "STREAM=0x%02x ",
2611 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002612 DEBUGPC(DNM, "\n");
2613 break;
2614 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002615 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002616 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002617 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002618 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002619 else
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002620 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002621 break;
2622 case NM_MT_IPACC_SET_NVATTR_ACK:
2623 DEBUGPC(DNM, "SET NVATTR ACK\n");
2624 /* FIXME: decode and show the actual attributes */
2625 break;
2626 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002627 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002628 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002629 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002630 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002631 else
Harald Weltede4477a2009-12-24 12:20:20 +01002632 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002633 break;
Harald Welte21460f02009-07-03 11:26:45 +02002634 case NM_MT_IPACC_GET_NVATTR_ACK:
2635 DEBUGPC(DNM, "GET NVATTR ACK\n");
2636 /* FIXME: decode and show the actual attributes */
2637 break;
2638 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002639 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002640 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002641 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002642 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002643 else
Harald Weltede4477a2009-12-24 12:20:20 +01002644 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002645 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002646 case NM_MT_IPACC_SET_ATTR_ACK:
2647 DEBUGPC(DNM, "SET ATTR ACK\n");
2648 break;
2649 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002650 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002651 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002652 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002653 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002654 else
Harald Weltede4477a2009-12-24 12:20:20 +01002655 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002656 break;
Harald Welte59b04682009-06-10 05:40:52 +08002657 default:
2658 DEBUGPC(DNM, "unknown\n");
2659 break;
2660 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002661
2662 /* signal handling */
2663 switch (foh->msg_type) {
2664 case NM_MT_IPACC_RSL_CONNECT_NACK:
2665 case NM_MT_IPACC_SET_NVATTR_NACK:
2666 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002667 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 +01002668 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002669 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002670 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002671 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002672 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 +01002673 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002674 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002675 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002676 default:
2677 break;
2678 }
2679
Harald Welte59b04682009-06-10 05:40:52 +08002680 return 0;
2681}
2682
2683/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002684int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2685 uint8_t obj_class, uint8_t bts_nr,
2686 uint8_t trx_nr, uint8_t ts_nr,
2687 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002688{
2689 struct msgb *msg = nm_msgb_alloc();
2690 struct abis_om_hdr *oh;
2691 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002692 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002693
2694 /* construct the 12.21 OM header, observe the erroneous length */
2695 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2696 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2697 oh->mdisc = ABIS_OM_MDISC_MANUF;
2698
2699 /* add the ip.access magic */
2700 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2701 *data++ = sizeof(ipaccess_magic);
2702 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2703
2704 /* fill the 12.21 FOM header */
2705 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2706 foh->msg_type = msg_type;
2707 foh->obj_class = obj_class;
2708 foh->obj_inst.bts_nr = bts_nr;
2709 foh->obj_inst.trx_nr = trx_nr;
2710 foh->obj_inst.ts_nr = ts_nr;
2711
2712 if (attr && attr_len) {
2713 data = msgb_put(msg, attr_len);
2714 memcpy(data, attr, attr_len);
2715 }
2716
2717 return abis_nm_sendmsg(bts, msg);
2718}
2719
2720/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002721int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002722 int attr_len)
2723{
Harald Weltef12c1052010-01-07 20:39:42 +01002724 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2725 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002726 attr_len);
2727}
2728
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002729int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002730 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002731{
2732 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002733 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002734 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2735 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2736
2737 int attr_len = sizeof(attr);
2738
2739 ia.s_addr = htonl(ip);
2740 attr[1] = stream;
2741 attr[3] = port >> 8;
2742 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002743 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002744
2745 /* if ip == 0, we use the default IP */
2746 if (ip == 0)
2747 attr_len -= 5;
2748
2749 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002750 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002751
2752 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2753 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2754 trx->nr, 0xff, attr, attr_len);
2755}
2756
Harald Welte59b04682009-06-10 05:40:52 +08002757/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002758int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002759{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002760 struct abis_om_hdr *oh;
2761 struct msgb *msg = nm_msgb_alloc();
2762
2763 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2764 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2765 trx->bts->nr, trx->nr, 0xff);
2766
Holger Hans Peter Freytherc26d1172016-03-16 14:27:29 +01002767 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002768}
Harald Welte0dfc6232009-10-24 10:20:41 +02002769
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002770int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2771 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2772 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002773{
2774 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2775 obj_class, bts_nr, trx_nr, ts_nr,
2776 attr, attr_len);
2777}
Harald Weltebeeae412009-11-12 14:48:42 +01002778
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002779void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002780{
2781 /* we simply reuse the GSM48 function and overwrite the RAC
2782 * with the Cell ID */
2783 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002784 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002785}
2786
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002787void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2788{
2789 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2790
Harald Welte69f6f812011-05-30 12:07:53 +02002791 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002792 if (!trx->bts || !trx->bts->oml_link)
2793 return;
2794
2795 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2796 trx->bts->bts_nr, trx->nr, 0xff,
2797 new_state);
2798}
2799
Harald Welte453141f2010-03-25 11:45:30 +08002800static const struct value_string ipacc_testres_names[] = {
2801 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2802 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2803 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2804 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2805 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2806 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002807};
2808
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002809const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002810{
Harald Welte453141f2010-03-25 11:45:30 +08002811 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002812}
2813
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002814void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002815{
2816 cid->mcc = (buf[0] & 0xf) * 100;
2817 cid->mcc += (buf[0] >> 4) * 10;
2818 cid->mcc += (buf[1] & 0xf) * 1;
2819
2820 if (buf[1] >> 4 == 0xf) {
2821 cid->mnc = (buf[2] & 0xf) * 10;
2822 cid->mnc += (buf[2] >> 4) * 1;
2823 } else {
2824 cid->mnc = (buf[2] & 0xf) * 100;
2825 cid->mnc += (buf[2] >> 4) * 10;
2826 cid->mnc += (buf[1] >> 4) * 1;
2827 }
2828
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002829 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2830 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002831}
2832
Harald Weltebeeae412009-11-12 14:48:42 +01002833/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002834int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002835{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002836 uint8_t *cur = buf;
Holger Hans Peter Freyther1a9f3ee2012-09-11 11:55:03 +02002837 uint16_t len __attribute__((unused));
Harald Weltebeeae412009-11-12 14:48:42 +01002838
Harald Welteb784df82010-07-22 18:14:36 +02002839 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002840
2841 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2842 return -EINVAL;
2843 cur++;
2844
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002845 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002846 cur += 2;
2847
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002848 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002849 cur += 2;
2850
2851 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2852 binf->freq_qual = *cur >> 2;
2853
Harald Welteb784df82010-07-22 18:14:36 +02002854 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002855 binf->arfcn |= *cur++;
2856
2857 if (binf->info_type & IPAC_BINF_RXLEV)
2858 binf->rx_lev = *cur & 0x3f;
2859 cur++;
2860
2861 if (binf->info_type & IPAC_BINF_RXQUAL)
2862 binf->rx_qual = *cur & 0x7;
2863 cur++;
2864
2865 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002866 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002867 cur += 2;
2868
2869 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002870 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002871 cur += 2;
2872
2873 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002874 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002875 cur += 4;
2876
Harald Welte22cb81f2010-07-30 22:34:42 +02002877#if 0
2878 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002879 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002880#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002881 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002882 cur++;
2883
Harald Weltebfc21092009-11-13 11:56:05 +01002884 ipac_parse_cgi(&binf->cgi, cur);
2885 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002886
2887 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2888 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2889 cur += sizeof(binf->ba_list_si2);
2890 }
2891
2892 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2893 memcpy(binf->ba_list_si2bis, cur,
2894 sizeof(binf->ba_list_si2bis));
2895 cur += sizeof(binf->ba_list_si2bis);
2896 }
2897
2898 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2899 memcpy(binf->ba_list_si2ter, cur,
2900 sizeof(binf->ba_list_si2ter));
2901 cur += sizeof(binf->ba_list_si2ter);
2902 }
2903
2904 return 0;
2905}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002906
2907void abis_nm_clear_queue(struct gsm_bts *bts)
2908{
2909 struct msgb *msg;
2910
2911 while (!llist_empty(&bts->abis_queue)) {
2912 msg = msgb_dequeue(&bts->abis_queue);
2913 msgb_free(msg);
2914 }
2915
2916 bts->abis_nm_pend = 0;
2917}