blob: 0c723e83d627b6d1b052197fb44ac6f045bcfde3 [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000043#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte52b1f982008-12-23 20:25:15 +000047
Harald Welte8470bf22008-12-25 23:28:35 +000048#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000051
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020052int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +000053{
Harald Welte39315c42010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000057}
Harald Weltee0590df2009-02-15 03:34:15 +000058
Harald Welte52b1f982008-12-23 20:25:15 +000059static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
Holger Freytherca362a62009-01-04 21:05:01 +000071#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000072/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
Holger Freytherca362a62009-01-04 21:05:01 +000077#endif
Harald Welte52b1f982008-12-23 20:25:15 +000078
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Welte15c61722011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +020096static struct abis_om_fom_hdr *fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020097 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +000099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
Harald Welte702d8702008-12-26 20:25:35 +0000103 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200109 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000110}
111
Harald Welte8470bf22008-12-25 23:28:35 +0000112static struct msgb *nm_msgb_alloc(void)
113{
Harald Welte966636f2009-06-26 19:39:35 +0200114 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
115 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000116}
117
Harald Welte15eae8d2011-09-26 23:43:23 +0200118int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200119{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200120 msg->l2h = msg->data;
121
122 if (!msg->dst) {
123 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
124 return -EINVAL;
125 }
126
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200127 return abis_sendmsg(msg);
128}
129
Harald Welte52b1f982008-12-23 20:25:15 +0000130/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100131static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000132{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200133 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000134
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100135 /* queue OML messages */
136 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
137 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200138 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100139 } else {
140 msgb_enqueue(&bts->abis_queue, msg);
141 return 0;
142 }
143
144}
145
146int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
147{
148 OBSC_NM_W_ACK_CB(msg) = 1;
149 return abis_nm_queue_msg(bts, msg);
150}
151
152static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
153{
154 OBSC_NM_W_ACK_CB(msg) = 0;
155 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000156}
157
Harald Welte4724f992009-01-18 18:01:49 +0000158static int abis_nm_rcvmsg_sw(struct msgb *mb);
159
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100160int nm_is_running(struct gsm_nm_state *s) {
161 return (s->operational == NM_OPSTATE_ENABLED) && (
162 (s->availability == NM_AVSTATE_OK) ||
163 (s->availability == 0xff)
164 );
165}
166
Harald Weltee0590df2009-02-15 03:34:15 +0000167/* Update the administrative state of a given object in our in-memory data
168 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200169static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
170 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000171{
Harald Welteaeedeb42009-05-01 13:08:14 +0000172 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100173 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000174
Harald Welteaf9b8102011-03-06 21:20:38 +0100175 memset(&nsd, 0, sizeof(nsd));
176
Harald Welte978714d2011-06-06 18:31:20 +0200177 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100178 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100179 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200180 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000181 if (!nm_state)
182 return -1;
183
184 new_state = *nm_state;
185 new_state.administrative = adm_state;
186
Harald Weltef38ca9a2011-03-06 22:11:32 +0100187 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100188 nsd.obj_class = obj_class;
189 nsd.old_state = nm_state;
190 nsd.new_state = &new_state;
191 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200192 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000193
194 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000195
Harald Weltef338a032011-01-14 15:55:42 +0100196 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000197}
198
Harald Welte97ed1e72009-02-06 13:38:02 +0000199static int abis_nm_rx_statechg_rep(struct msgb *mb)
200{
Harald Weltee0590df2009-02-15 03:34:15 +0000201 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000202 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200203 struct e1inp_sign_link *sign_link = mb->dst;
204 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000205 struct tlv_parsed tp;
206 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000207
Harald Welte23897662009-05-01 14:52:51 +0000208 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000209
Harald Welte8b697c72009-06-05 19:18:45 +0000210 memset(&new_state, 0, sizeof(new_state));
211
Harald Welte978714d2011-06-06 18:31:20 +0200212 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000213 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100214 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000215 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000216 }
Harald Weltee0590df2009-02-15 03:34:15 +0000217
218 new_state = *nm_state;
219
Harald Welte39315c42010-01-10 18:01:52 +0100220 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000221 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
222 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200223 DEBUGPC(DNM, "OP_STATE=%s ",
224 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000225 }
226 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000227 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
228 new_state.availability = 0xff;
229 else
230 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200231 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
232 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000233 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100234 } else
235 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000236 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
237 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200238 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200239 get_value_string(abis_nm_adm_state_names,
240 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000241 }
242 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000243
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100244 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
245 new_state.operational != nm_state->operational ||
246 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000247 /* Update the operational state of a given object in our in-memory data
248 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100249 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200250 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100251 nsd.obj_class = foh->obj_class;
252 nsd.old_state = nm_state;
253 nsd.new_state = &new_state;
254 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100255 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200256 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100257 nm_state->operational = new_state.operational;
258 nm_state->availability = new_state.availability;
259 if (nm_state->administrative == 0)
260 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000261 }
262#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000263 if (op_state == 1) {
264 /* try to enable objects that are disabled */
265 abis_nm_opstart(bts, foh->obj_class,
266 foh->obj_inst.bts_nr,
267 foh->obj_inst.trx_nr,
268 foh->obj_inst.ts_nr);
269 }
Harald Weltee0590df2009-02-15 03:34:15 +0000270#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000271 return 0;
272}
273
Harald Welte0db97b22009-05-01 17:22:47 +0000274static int rx_fail_evt_rep(struct msgb *mb)
275{
276 struct abis_om_hdr *oh = msgb_l2(mb);
277 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200278 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000279 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100280 const uint8_t *p_val;
281 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000282
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200283 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000284
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200285 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000286
287 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200288 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
289 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000290 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200291 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
292 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100293 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
294 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200295 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100296 }
297 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
298 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
299 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
300 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200301 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100302 talloc_free(p_text);
303 }
304 }
Harald Welte0db97b22009-05-01 17:22:47 +0000305
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200306 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000307
308 return 0;
309}
310
Harald Welte97ed1e72009-02-06 13:38:02 +0000311static int abis_nm_rcvmsg_report(struct msgb *mb)
312{
313 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200314 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000315
Harald Welte15c61722011-05-22 22:45:37 +0200316 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000317
Harald Welte97ed1e72009-02-06 13:38:02 +0000318 //nmh->cfg->report_cb(mb, foh);
319
320 switch (mt) {
321 case NM_MT_STATECHG_EVENT_REP:
322 return abis_nm_rx_statechg_rep(mb);
323 break;
Harald Welte34a99682009-02-13 02:41:40 +0000324 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000325 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200326 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000327 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000328 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000329 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200330 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000331 break;
Harald Weltec7310382009-08-08 00:02:36 +0200332 case NM_MT_TEST_REP:
333 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200334 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200335 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000336 default:
Harald Welte23897662009-05-01 14:52:51 +0000337 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000338 break;
339
Harald Welte97ed1e72009-02-06 13:38:02 +0000340 };
341
Harald Welte97ed1e72009-02-06 13:38:02 +0000342 return 0;
343}
344
Harald Welte34a99682009-02-13 02:41:40 +0000345/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200346static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
347 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000348{
349 struct abis_om_hdr *oh;
350 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200351 uint8_t len = swdesc_len;
352 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000353
354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
355 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
356
357 trailer = msgb_put(msg, swdesc_len);
358 memcpy(trailer, sw_desc, swdesc_len);
359
360 return abis_nm_sendmsg(bts, msg);
361}
362
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100363int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
364 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100365{
366 static const struct tlv_definition sw_descr_def = {
367 .def = {
368 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
369 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
370 },
371 };
372
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100373 size_t pos = 0;
374 int desc_pos = 0;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100375
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100376 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
377 uint8_t tag;
378 uint16_t tag_len;
379 const uint8_t *val;
380 int len;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100381
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100382 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
383 desc[desc_pos].start = &sw_descr[pos];
384
385 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
386 * nested nature and the fact you have to assume it contains only two sub
387 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
388 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
389 LOGP(DNM, LOGL_ERROR,
390 "SW_DESCR attribute identifier not found!\n");
391 return -1;
392 }
393
394 pos += 1;
395 len = tlv_parse_one(&tag, &tag_len, &val,
396 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
397 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
398 LOGP(DNM, LOGL_ERROR,
399 "FILE_ID attribute identifier not found!\n");
400 return -2;
401 }
402 desc[desc_pos].file_id = val;
403 desc[desc_pos].file_id_len = tag_len;
404 pos += len;
405
406
407 len = tlv_parse_one(&tag, &tag_len, &val,
408 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
409 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
410 LOGP(DNM, LOGL_ERROR,
411 "FILE_VERSION attribute identifier not found!\n");
412 return -3;
413 }
414 desc[desc_pos].file_ver = val;
415 desc[desc_pos].file_ver_len = tag_len;
416 pos += len;
417
418 /* final size */
419 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100420 }
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100421
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100422 return desc_pos;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100423}
424
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100425int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
426 const size_t size)
427{
428 int res = 0;
429 int i;
430
431 for (i = 1; i < size; ++i) {
432 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
433 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
434 res = i;
435 }
436 }
437
438 return res;
439}
440
Harald Welte34a99682009-02-13 02:41:40 +0000441static int abis_nm_rx_sw_act_req(struct msgb *mb)
442{
443 struct abis_om_hdr *oh = msgb_l2(mb);
444 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200445 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200446 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200447 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100448 int ret, sw_config_len, len;
449 struct abis_nm_sw_descr sw_descr[5];
Harald Welte34a99682009-02-13 02:41:40 +0000450
Harald Welte15c61722011-05-22 22:45:37 +0200451 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200452
453 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000454
Harald Welte97a282b2010-03-14 15:37:43 +0800455 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000456
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200457 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000458 foh->obj_inst.bts_nr,
459 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800460 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000461 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100462 if (ret != 0) {
463 LOGP(DNM, LOGL_ERROR,
464 "Sending SW ActReq ACK failed: %d\n", ret);
465 return ret;
466 }
Harald Welte34a99682009-02-13 02:41:40 +0000467
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200468 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200469 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
470 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
471 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100472 LOGP(DNM, LOGL_ERROR,
473 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200474 return -EINVAL;
475 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200476 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200477 }
478
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100479 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100480 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100481 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100482 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100483 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100484 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100485 }
Mike Habena03f9772009-10-01 14:56:13 +0200486
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100487 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
488 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
489
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200490 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000491 foh->obj_inst.bts_nr,
492 foh->obj_inst.trx_nr,
493 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100494 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte34a99682009-02-13 02:41:40 +0000495}
496
Harald Weltee0590df2009-02-15 03:34:15 +0000497/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
498static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
499{
500 struct abis_om_hdr *oh = msgb_l2(mb);
501 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200502 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000503 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200504 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000505
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200506 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000507 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
508 return -EINVAL;
509
510 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
511
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200512 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000513}
514
Harald Welteee670472009-02-22 21:58:49 +0000515static int abis_nm_rx_lmt_event(struct msgb *mb)
516{
517 struct abis_om_hdr *oh = msgb_l2(mb);
518 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200519 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000520 struct tlv_parsed tp;
521
522 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200523 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000524 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
525 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200526 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000527 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
528 }
529 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
530 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200531 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000532 DEBUGPC(DNM, "Level=%u ", level);
533 }
534 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
535 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
536 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
537 DEBUGPC(DNM, "Username=%s ", name);
538 }
539 DEBUGPC(DNM, "\n");
540 /* FIXME: parse LMT LOGON TIME */
541 return 0;
542}
543
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200544void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100545{
546 int wait = 0;
547 struct msgb *msg;
548 /* the queue is empty */
549 while (!llist_empty(&bts->abis_queue)) {
550 msg = msgb_dequeue(&bts->abis_queue);
551 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200552 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100553
554 if (wait)
555 break;
556 }
557
558 bts->abis_nm_pend = wait;
559}
560
Harald Welte52b1f982008-12-23 20:25:15 +0000561/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000562static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000563{
Harald Welte6c96ba52009-05-01 13:03:40 +0000564 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000565 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200566 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200567 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100568 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
569 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100570 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000571
572 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000573 if (is_report(mt))
574 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000575
Harald Welte15c61722011-05-22 22:45:37 +0200576 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000577 return abis_nm_rcvmsg_sw(mb);
578
Harald Welte15c61722011-05-22 22:45:37 +0200579 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800580 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000581 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200582
Harald Welte15c61722011-05-22 22:45:37 +0200583 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200584
Harald Welte15c61722011-05-22 22:45:37 +0200585 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000586
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100587 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000588 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200589 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200590 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000591 else
592 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200593
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800594 nack_data.msg = mb;
595 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100596 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200597 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100598 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200599 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000600 }
Harald Weltead384642008-12-26 10:20:07 +0000601#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000602 /* check if last message is to be acked */
603 if (is_ack_nack(nmh->last_msgtype)) {
604 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100605 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000606 /* we got our ACK, continue sending the next msg */
607 } else if (mt == MT_NACK(nmh->last_msgtype)) {
608 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100609 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000610 /* FIXME: somehow signal this to the caller */
611 } else {
612 /* really strange things happen */
613 return -EINVAL;
614 }
615 }
Harald Weltead384642008-12-26 10:20:07 +0000616#endif
617
Harald Welte97ed1e72009-02-06 13:38:02 +0000618 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000619 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100620 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000621 break;
Harald Welte34a99682009-02-13 02:41:40 +0000622 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100623 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000624 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000625 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100626 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000627 break;
Harald Welte1989c082009-08-06 17:58:31 +0200628 case NM_MT_CONN_MDROP_LINK_ACK:
629 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
630 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100631 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200632 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100633 break;
634 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200635 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100636 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100637 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100638 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000639 }
640
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100641 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100642 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000643}
644
Harald Welte677c21f2009-02-17 13:22:23 +0000645static int abis_nm_rx_ipacc(struct msgb *mb);
646
647static int abis_nm_rcvmsg_manuf(struct msgb *mb)
648{
649 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200650 struct e1inp_sign_link *sign_link = mb->dst;
651 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000652
653 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100654 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200655 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000656 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200657 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000658 break;
659 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100660 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
661 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000662 rc = 0;
663 break;
664 }
665
666 return rc;
667}
668
Harald Welte52b1f982008-12-23 20:25:15 +0000669/* High-Level API */
670/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000671int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000672{
Harald Welte52b1f982008-12-23 20:25:15 +0000673 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000674 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000675
676 /* Various consistency checks */
677 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100678 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000679 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200680 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
681 rc = -EINVAL;
682 goto err;
683 }
Harald Welte52b1f982008-12-23 20:25:15 +0000684 }
685 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100686 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000687 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200688 rc = -EINVAL;
689 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000690 }
Harald Welte702d8702008-12-26 20:25:35 +0000691#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200692 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000693 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000694 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100695 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000696 oh->length + sizeof(*oh), l2_len);
697 return -EINVAL;
698 }
Harald Welte702d8702008-12-26 20:25:35 +0000699 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100700 LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
Harald Welte702d8702008-12-26 20:25:35 +0000701#endif
Harald Weltead384642008-12-26 10:20:07 +0000702 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000703
704 switch (oh->mdisc) {
705 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000706 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000707 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000708 case ABIS_OM_MDISC_MANUF:
709 rc = abis_nm_rcvmsg_manuf(msg);
710 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000711 case ABIS_OM_MDISC_MMI:
712 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100713 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000714 oh->mdisc);
715 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000716 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100717 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000718 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200719 rc = -EINVAL;
720 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000721 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200722err:
Harald Weltead384642008-12-26 10:20:07 +0000723 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000724 return rc;
725}
726
727#if 0
728/* initialized all resources */
729struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
730{
731 struct abis_nm_h *nmh;
732
733 nmh = malloc(sizeof(*nmh));
734 if (!nmh)
735 return NULL;
736
737 nmh->cfg = cfg;
738
739 return nmh;
740}
741
742/* free all resources */
743void abis_nm_fini(struct abis_nm_h *nmh)
744{
745 free(nmh);
746}
747#endif
748
749/* Here we are trying to define a high-level API that can be used by
750 * the actual BSC implementation. However, the architecture is currently
751 * still under design. Ideally the calls to this API would be synchronous,
752 * while the underlying stack behind the APi runs in a traditional select
753 * based state machine.
754 */
755
Harald Welte4724f992009-01-18 18:01:49 +0000756/* 6.2 Software Load: */
757enum sw_state {
758 SW_STATE_NONE,
759 SW_STATE_WAIT_INITACK,
760 SW_STATE_WAIT_SEGACK,
761 SW_STATE_WAIT_ENDACK,
762 SW_STATE_WAIT_ACTACK,
763 SW_STATE_ERROR,
764};
Harald Welte52b1f982008-12-23 20:25:15 +0000765
Harald Welte52b1f982008-12-23 20:25:15 +0000766struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000767 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800768 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000769 gsm_cbfn *cbfn;
770 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000771 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000772
Harald Welte52b1f982008-12-23 20:25:15 +0000773 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200774 uint8_t obj_class;
775 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000776
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200777 uint8_t file_id[255];
778 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000779
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200780 uint8_t file_version[255];
781 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000782
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200783 uint8_t window_size;
784 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000785
786 int fd;
787 FILE *stream;
788 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000789 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000790};
791
Harald Welte4724f992009-01-18 18:01:49 +0000792static struct abis_nm_sw g_sw;
793
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100794static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
795{
796 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
797 msgb_v_put(msg, NM_ATT_SW_DESCR);
798 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
799 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
800 sw->file_version);
801 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
802 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
803 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
804 sw->file_version);
805 } else {
806 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
807 }
808}
809
Harald Welte4724f992009-01-18 18:01:49 +0000810/* 6.2.1 / 8.3.1: Load Data Initiate */
811static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000812{
Harald Welte4724f992009-01-18 18:01:49 +0000813 struct abis_om_hdr *oh;
814 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200815 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000816
817 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
818 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
819 sw->obj_instance[0], sw->obj_instance[1],
820 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100821
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100822 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000823 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
824
825 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000826}
827
Harald Welte1602ade2009-01-29 21:12:39 +0000828static int is_last_line(FILE *stream)
829{
830 char next_seg_buf[256];
831 long pos;
832
833 /* check if we're sending the last line */
834 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200835
836 /* Did ftell fail? Then we are at the end for sure */
837 if (pos < 0)
838 return 1;
839
Harald Welte1602ade2009-01-29 21:12:39 +0000840 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +0100841 int rc = fseek(stream, pos, SEEK_SET);
842 if (rc < 0)
843 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000844 return 1;
845 }
846
847 fseek(stream, pos, SEEK_SET);
848 return 0;
849}
850
Harald Welte4724f992009-01-18 18:01:49 +0000851/* 6.2.2 / 8.3.2 Load Data Segment */
852static int sw_load_segment(struct abis_nm_sw *sw)
853{
854 struct abis_om_hdr *oh;
855 struct msgb *msg = nm_msgb_alloc();
856 char seg_buf[256];
857 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000858 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200859 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000860
861 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000862
863 switch (sw->bts->type) {
864 case GSM_BTS_TYPE_BS11:
865 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
866 perror("fgets reading segment");
867 return -EINVAL;
868 }
869 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000870
871 /* check if we're sending the last line */
872 sw->last_seg = is_last_line(sw->stream);
873 if (sw->last_seg)
874 seg_buf[1] = 0;
875 else
876 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000877
878 len = strlen(line_buf) + 2;
879 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200880 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000881 /* BS11 wants CR + LF in excess of the TLV length !?! */
882 tlv[1] -= 2;
883
884 /* we only now know the exact length for the OM hdr */
885 len = strlen(line_buf)+2;
886 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100887 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200888 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100889 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
890 if (len < 0) {
891 perror("read failed");
892 return -EINVAL;
893 }
894
895 if (len != IPACC_SEGMENT_SIZE)
896 sw->last_seg = 1;
897
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100898 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200899 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100900 len += 3;
901 break;
902 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000903 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100904 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000905 /* FIXME: Other BTS types */
906 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000907 }
Harald Welte4724f992009-01-18 18:01:49 +0000908
Harald Welte4724f992009-01-18 18:01:49 +0000909 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
910 sw->obj_instance[0], sw->obj_instance[1],
911 sw->obj_instance[2]);
912
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100913 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000914}
915
916/* 6.2.4 / 8.3.4 Load Data End */
917static int sw_load_end(struct abis_nm_sw *sw)
918{
919 struct abis_om_hdr *oh;
920 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200921 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000922
923 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
924 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
925 sw->obj_instance[0], sw->obj_instance[1],
926 sw->obj_instance[2]);
927
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100928 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000929 return abis_nm_sendmsg(sw->bts, msg);
930}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000931
Harald Welte52b1f982008-12-23 20:25:15 +0000932/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000933static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000934{
Harald Welte4724f992009-01-18 18:01:49 +0000935 struct abis_om_hdr *oh;
936 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200937 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000938
Harald Welte4724f992009-01-18 18:01:49 +0000939 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
940 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
941 sw->obj_instance[0], sw->obj_instance[1],
942 sw->obj_instance[2]);
943
944 /* FIXME: this is BS11 specific format */
945 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
946 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
947 sw->file_version);
948
949 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000950}
Harald Welte4724f992009-01-18 18:01:49 +0000951
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100952struct sdp_firmware {
953 char magic[4];
954 char more_magic[4];
955 unsigned int header_length;
956 unsigned int file_length;
957} __attribute__ ((packed));
958
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100959static int parse_sdp_header(struct abis_nm_sw *sw)
960{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100961 struct sdp_firmware firmware_header;
962 int rc;
963 struct stat stat;
964
965 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
966 if (rc != sizeof(firmware_header)) {
967 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
968 return -1;
969 }
970
971 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
972 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
973 return -1;
974 }
975
976 if (firmware_header.more_magic[0] != 0x10 ||
977 firmware_header.more_magic[1] != 0x02 ||
978 firmware_header.more_magic[2] != 0x00 ||
979 firmware_header.more_magic[3] != 0x00) {
980 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
981 return -1;
982 }
983
984
985 if (fstat(sw->fd, &stat) == -1) {
986 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
987 return -1;
988 }
989
990 if (ntohl(firmware_header.file_length) != stat.st_size) {
991 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
992 return -1;
993 }
994
995 /* go back to the start as we checked the whole filesize.. */
996 lseek(sw->fd, 0l, SEEK_SET);
997 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
998 "There might be checksums in the file that are not\n"
999 "verified and incomplete firmware might be flashed.\n"
1000 "There is absolutely no WARRANTY that flashing will\n"
1001 "work.\n");
1002 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001003}
1004
Harald Welte4724f992009-01-18 18:01:49 +00001005static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1006{
1007 char file_id[12+1];
1008 char file_version[80+1];
1009 int rc;
1010
1011 sw->fd = open(fname, O_RDONLY);
1012 if (sw->fd < 0)
1013 return sw->fd;
1014
1015 switch (sw->bts->type) {
1016 case GSM_BTS_TYPE_BS11:
1017 sw->stream = fdopen(sw->fd, "r");
1018 if (!sw->stream) {
1019 perror("fdopen");
1020 return -1;
1021 }
1022 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001023 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001024 file_id, file_version);
1025 if (rc != 2) {
1026 perror("parsing header line of software file");
1027 return -1;
1028 }
1029 strcpy((char *)sw->file_id, file_id);
1030 sw->file_id_len = strlen(file_id);
1031 strcpy((char *)sw->file_version, file_version);
1032 sw->file_version_len = strlen(file_version);
1033 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001034 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001035 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001036 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001037 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001038 rc = parse_sdp_header(sw);
1039 if (rc < 0) {
1040 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1041 return -1;
1042 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001043
1044 strcpy((char *)sw->file_id, "id");
1045 sw->file_id_len = 3;
1046 strcpy((char *)sw->file_version, "version");
1047 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001048 break;
Harald Welte4724f992009-01-18 18:01:49 +00001049 default:
1050 /* We don't know how to treat them yet */
1051 close(sw->fd);
1052 return -EINVAL;
1053 }
1054
1055 return 0;
1056}
1057
1058static void sw_close_file(struct abis_nm_sw *sw)
1059{
1060 switch (sw->bts->type) {
1061 case GSM_BTS_TYPE_BS11:
1062 fclose(sw->stream);
1063 break;
1064 default:
1065 close(sw->fd);
1066 break;
1067 }
1068}
1069
1070/* Fill the window */
1071static int sw_fill_window(struct abis_nm_sw *sw)
1072{
1073 int rc;
1074
1075 while (sw->seg_in_window < sw->window_size) {
1076 rc = sw_load_segment(sw);
1077 if (rc < 0)
1078 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001079 if (sw->last_seg)
1080 break;
Harald Welte4724f992009-01-18 18:01:49 +00001081 }
1082 return 0;
1083}
1084
1085/* callback function from abis_nm_rcvmsg() handler */
1086static int abis_nm_rcvmsg_sw(struct msgb *mb)
1087{
1088 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001089 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001090 int rc = -1;
1091 struct abis_nm_sw *sw = &g_sw;
1092 enum sw_state old_state = sw->state;
1093
Harald Welte3ffd1372009-02-01 22:15:49 +00001094 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001095
1096 switch (sw->state) {
1097 case SW_STATE_WAIT_INITACK:
1098 switch (foh->msg_type) {
1099 case NM_MT_LOAD_INIT_ACK:
1100 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001101 if (sw->cbfn)
1102 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1103 NM_MT_LOAD_INIT_ACK, mb,
1104 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001105 rc = sw_fill_window(sw);
1106 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001107 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001108 break;
1109 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001110 if (sw->forced) {
1111 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1112 "Init NACK\n");
1113 if (sw->cbfn)
1114 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1115 NM_MT_LOAD_INIT_ACK, mb,
1116 sw->cb_data, NULL);
1117 rc = sw_fill_window(sw);
1118 sw->state = SW_STATE_WAIT_SEGACK;
1119 } else {
1120 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001121 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001122 if (sw->cbfn)
1123 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1124 NM_MT_LOAD_INIT_NACK, mb,
1125 sw->cb_data, NULL);
1126 sw->state = SW_STATE_ERROR;
1127 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001128 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001129 break;
1130 }
1131 break;
1132 case SW_STATE_WAIT_SEGACK:
1133 switch (foh->msg_type) {
1134 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001135 if (sw->cbfn)
1136 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1137 NM_MT_LOAD_SEG_ACK, mb,
1138 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001139 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001140 if (!sw->last_seg) {
1141 /* fill window with more segments */
1142 rc = sw_fill_window(sw);
1143 sw->state = SW_STATE_WAIT_SEGACK;
1144 } else {
1145 /* end the transfer */
1146 sw->state = SW_STATE_WAIT_ENDACK;
1147 rc = sw_load_end(sw);
1148 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001149 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001150 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001151 case NM_MT_LOAD_ABORT:
1152 if (sw->cbfn)
1153 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1154 NM_MT_LOAD_ABORT, mb,
1155 sw->cb_data, NULL);
1156 break;
Harald Welte4724f992009-01-18 18:01:49 +00001157 }
1158 break;
1159 case SW_STATE_WAIT_ENDACK:
1160 switch (foh->msg_type) {
1161 case NM_MT_LOAD_END_ACK:
1162 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001163 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1164 sw->bts->nr);
1165 sw->state = SW_STATE_NONE;
1166 if (sw->cbfn)
1167 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1168 NM_MT_LOAD_END_ACK, mb,
1169 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001170 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001171 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001172 break;
1173 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001174 if (sw->forced) {
1175 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1176 "End NACK\n");
1177 sw->state = SW_STATE_NONE;
1178 if (sw->cbfn)
1179 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1180 NM_MT_LOAD_END_ACK, mb,
1181 sw->cb_data, NULL);
1182 } else {
1183 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001184 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001185 sw->state = SW_STATE_ERROR;
1186 if (sw->cbfn)
1187 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1188 NM_MT_LOAD_END_NACK, mb,
1189 sw->cb_data, NULL);
1190 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001191 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001192 break;
1193 }
1194 case SW_STATE_WAIT_ACTACK:
1195 switch (foh->msg_type) {
1196 case NM_MT_ACTIVATE_SW_ACK:
1197 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001198 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001199 sw->state = SW_STATE_NONE;
1200 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001201 if (sw->cbfn)
1202 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1203 NM_MT_ACTIVATE_SW_ACK, mb,
1204 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001205 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001206 break;
1207 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001208 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001209 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001210 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001211 if (sw->cbfn)
1212 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1213 NM_MT_ACTIVATE_SW_NACK, mb,
1214 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001215 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001216 break;
1217 }
1218 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001219 switch (foh->msg_type) {
1220 case NM_MT_ACTIVATE_SW_ACK:
1221 rc = 0;
1222 break;
1223 }
1224 break;
Harald Welte4724f992009-01-18 18:01:49 +00001225 case SW_STATE_ERROR:
1226 break;
1227 }
1228
1229 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001230 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001231 foh->msg_type, old_state, sw->state);
1232
1233 return rc;
1234}
1235
1236/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001237int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001238 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001239 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001240{
1241 struct abis_nm_sw *sw = &g_sw;
1242 int rc;
1243
Harald Welte5e4d1b32009-02-01 13:36:56 +00001244 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1245 bts->nr, fname);
1246
Harald Welte4724f992009-01-18 18:01:49 +00001247 if (sw->state != SW_STATE_NONE)
1248 return -EBUSY;
1249
1250 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001251 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001252
1253 switch (bts->type) {
1254 case GSM_BTS_TYPE_BS11:
1255 sw->obj_class = NM_OC_SITE_MANAGER;
1256 sw->obj_instance[0] = 0xff;
1257 sw->obj_instance[1] = 0xff;
1258 sw->obj_instance[2] = 0xff;
1259 break;
1260 case GSM_BTS_TYPE_NANOBTS:
1261 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001262 sw->obj_instance[0] = sw->bts->nr;
1263 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001264 sw->obj_instance[2] = 0xff;
1265 break;
1266 case GSM_BTS_TYPE_UNKNOWN:
1267 default:
1268 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1269 return -1;
1270 break;
1271 }
Harald Welte4724f992009-01-18 18:01:49 +00001272 sw->window_size = win_size;
1273 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001274 sw->cbfn = cbfn;
1275 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001276 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001277
1278 rc = sw_open_file(sw, fname);
1279 if (rc < 0) {
1280 sw->state = SW_STATE_NONE;
1281 return rc;
1282 }
1283
1284 return sw_load_init(sw);
1285}
Harald Welte52b1f982008-12-23 20:25:15 +00001286
Harald Welte1602ade2009-01-29 21:12:39 +00001287int abis_nm_software_load_status(struct gsm_bts *bts)
1288{
1289 struct abis_nm_sw *sw = &g_sw;
1290 struct stat st;
1291 int rc, percent;
1292
1293 rc = fstat(sw->fd, &st);
1294 if (rc < 0) {
1295 perror("ERROR during stat");
1296 return rc;
1297 }
1298
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001299 if (sw->stream)
1300 percent = (ftell(sw->stream) * 100) / st.st_size;
1301 else
1302 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001303 return percent;
1304}
1305
Harald Welte5e4d1b32009-02-01 13:36:56 +00001306/* Activate the specified software into the BTS */
1307int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1308 gsm_cbfn *cbfn, void *cb_data)
1309{
1310 struct abis_nm_sw *sw = &g_sw;
1311 int rc;
1312
1313 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1314 bts->nr, fname);
1315
1316 if (sw->state != SW_STATE_NONE)
1317 return -EBUSY;
1318
1319 sw->bts = bts;
1320 sw->obj_class = NM_OC_SITE_MANAGER;
1321 sw->obj_instance[0] = 0xff;
1322 sw->obj_instance[1] = 0xff;
1323 sw->obj_instance[2] = 0xff;
1324 sw->state = SW_STATE_WAIT_ACTACK;
1325 sw->cbfn = cbfn;
1326 sw->cb_data = cb_data;
1327
1328 /* Open the file in order to fill some sw struct members */
1329 rc = sw_open_file(sw, fname);
1330 if (rc < 0) {
1331 sw->state = SW_STATE_NONE;
1332 return rc;
1333 }
1334 sw_close_file(sw);
1335
1336 return sw_activate(sw);
1337}
1338
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001339static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1340 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001341{
Harald Welteadaf08b2009-01-18 11:08:10 +00001342 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001343 ch->bts_port = bts_port;
1344 ch->timeslot = ts_nr;
1345 ch->subslot = subslot_nr;
1346}
1347
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001348int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1349 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1350 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001351{
1352 struct abis_om_hdr *oh;
1353 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001354 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001355 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001356
1357 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1358 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1359 bts->bts_nr, trx_nr, 0xff);
1360
Harald Welte8470bf22008-12-25 23:28:35 +00001361 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001362
1363 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1364 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1365
1366 return abis_nm_sendmsg(bts, msg);
1367}
1368
1369/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1370int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001371 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001372{
Harald Welte8470bf22008-12-25 23:28:35 +00001373 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001374 struct abis_om_hdr *oh;
1375 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001376 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001377
1378 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001379 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001380 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1381
1382 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1383 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1384
1385 return abis_nm_sendmsg(bts, msg);
1386}
1387
1388#if 0
1389int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1390 struct abis_nm_abis_channel *chan)
1391{
1392}
1393#endif
1394
1395int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001396 uint8_t e1_port, uint8_t e1_timeslot,
1397 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001398{
1399 struct gsm_bts *bts = ts->trx->bts;
1400 struct abis_om_hdr *oh;
1401 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001402 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001403
1404 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1405 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001406 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001407
1408 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1409 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1410
Harald Weltef325eb42009-02-19 17:07:39 +00001411 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1412 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001413 e1_port, e1_timeslot, e1_subslot);
1414
Harald Welte52b1f982008-12-23 20:25:15 +00001415 return abis_nm_sendmsg(bts, msg);
1416}
1417
1418#if 0
1419int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1420 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001421 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001422{
1423}
1424#endif
1425
Harald Weltefe568f22012-08-14 19:15:57 +02001426/* Chapter 8.11.1 */
1427int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1428 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1429 uint8_t *attr, uint8_t attr_len)
1430{
1431 struct abis_om_hdr *oh;
1432 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001433
1434 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1435
1436 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1437 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1438 bts_nr, trx_nr, ts_nr);
1439 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1440
1441 return abis_nm_sendmsg(bts, msg);
1442}
1443
Harald Welte22af0db2009-02-14 15:41:08 +00001444/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001445int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001446{
1447 struct abis_om_hdr *oh;
1448 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001449 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001450
1451 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1452
1453 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001454 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001455 cur = msgb_put(msg, attr_len);
1456 memcpy(cur, attr, attr_len);
1457
1458 return abis_nm_sendmsg(bts, msg);
1459}
1460
1461/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001462int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001463{
1464 struct abis_om_hdr *oh;
1465 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001466 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001467
1468 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1469
1470 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1471 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001472 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001473 cur = msgb_put(msg, attr_len);
1474 memcpy(cur, attr, attr_len);
1475
1476 return abis_nm_sendmsg(trx->bts, msg);
1477}
1478
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001479int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1480{
1481 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1482 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1483}
1484
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001485static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1486 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001487{
1488 int i;
1489
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001490 *reason = "Reason unknown";
1491
Harald Welte39c7deb2009-08-09 21:49:48 +02001492 /* As it turns out, the BS-11 has some very peculiar restrictions
1493 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301494 switch (ts->trx->bts->type) {
1495 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001496 switch (chan_comb) {
1497 case NM_CHANC_TCHHalf:
1498 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001499 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001500 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001501 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001502 return -EINVAL;
1503 case NM_CHANC_SDCCH:
1504 /* only one SDCCH/8 per TRX */
1505 for (i = 0; i < TRX_NR_TS; i++) {
1506 if (i == ts->nr)
1507 continue;
1508 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001509 NM_CHANC_SDCCH) {
1510 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001511 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001512 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001513 }
1514 /* not allowed for TS0 of BCCH-TRX */
1515 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001516 ts->nr == 0) {
1517 *reason = "SDCCH/8 must be on TS0.";
1518 return -EINVAL;
1519 }
1520
Harald Welte39c7deb2009-08-09 21:49:48 +02001521 /* not on the same TRX that has a BCCH+SDCCH4
1522 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001523 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001524 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001525 ts->trx->ts[0].nm_chan_comb == 8)) {
1526 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1527 return -EINVAL;
1528 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001529 break;
1530 case NM_CHANC_mainBCCH:
1531 case NM_CHANC_BCCHComb:
1532 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001533 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1534 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001535 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001536 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001537 break;
1538 case NM_CHANC_BCCH:
1539 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001540 if (ts->trx != ts->trx->bts->c0) {
1541 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001542 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001543 }
1544 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1545 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001546 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001547 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001548 break;
1549 case 8: /* this is not like 08.58, but in fact
1550 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1551 /* FIXME: only one CBCH allowed per cell */
1552 break;
1553 }
Harald Welted6575f92009-12-02 02:45:23 +05301554 break;
1555 case GSM_BTS_TYPE_NANOBTS:
1556 switch (ts->nr) {
1557 case 0:
1558 if (ts->trx->nr == 0) {
1559 /* only on TRX0 */
1560 switch (chan_comb) {
1561 case NM_CHANC_BCCH:
1562 case NM_CHANC_mainBCCH:
1563 case NM_CHANC_BCCHComb:
1564 return 0;
1565 break;
1566 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001567 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301568 return -EINVAL;
1569 }
1570 } else {
1571 switch (chan_comb) {
1572 case NM_CHANC_TCHFull:
1573 case NM_CHANC_TCHHalf:
1574 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1575 return 0;
1576 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001577 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301578 return -EINVAL;
1579 }
1580 }
1581 break;
1582 case 1:
1583 if (ts->trx->nr == 0) {
1584 switch (chan_comb) {
1585 case NM_CHANC_SDCCH_CBCH:
1586 if (ts->trx->ts[0].nm_chan_comb ==
1587 NM_CHANC_mainBCCH)
1588 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001589 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301590 return -EINVAL;
1591 case NM_CHANC_SDCCH:
1592 case NM_CHANC_TCHFull:
1593 case NM_CHANC_TCHHalf:
1594 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1595 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001596 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301597 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001598 default:
1599 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1600 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301601 }
1602 } else {
1603 switch (chan_comb) {
1604 case NM_CHANC_SDCCH:
1605 case NM_CHANC_TCHFull:
1606 case NM_CHANC_TCHHalf:
1607 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1608 return 0;
1609 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001610 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301611 return -EINVAL;
1612 }
1613 }
1614 break;
1615 case 2:
1616 case 3:
1617 case 4:
1618 case 5:
1619 case 6:
1620 case 7:
1621 switch (chan_comb) {
1622 case NM_CHANC_TCHFull:
1623 case NM_CHANC_TCHHalf:
1624 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1625 return 0;
1626 case NM_CHANC_IPAC_PDCH:
1627 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001628 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301629 if (ts->trx->nr == 0)
1630 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001631 else {
1632 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301633 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001634 }
Harald Welted6575f92009-12-02 02:45:23 +05301635 }
1636 break;
1637 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001638 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301639 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001640 case GSM_BTS_TYPE_OSMO_SYSMO:
1641 /* no known restrictions */
1642 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301643 default:
1644 /* unknown BTS type */
1645 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001646 }
1647 return 0;
1648}
1649
Harald Welte22af0db2009-02-14 15:41:08 +00001650/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001651int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001652{
1653 struct gsm_bts *bts = ts->trx->bts;
1654 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001655 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001656 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001657 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001658 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001659
1660 if (bts->type == GSM_BTS_TYPE_BS11)
1661 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001662
Harald Weltef325eb42009-02-19 17:07:39 +00001663 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001664 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001665 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001666 LOGP(DNM, LOGL_ERROR,
1667 "Invalid Channel Combination %d on %s. Reason: %s\n",
1668 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001669 return -EINVAL;
1670 }
1671 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001672
Harald Welte52b1f982008-12-23 20:25:15 +00001673 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001674 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001675 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001676 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001677 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001678 if (ts->hopping.enabled) {
1679 unsigned int i;
1680 uint8_t *len;
1681
Harald Welte6e0cd042009-09-12 13:05:33 +02001682 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1683 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001684
1685 /* build the ARFCN list */
1686 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1687 len = msgb_put(msg, 1);
1688 *len = 0;
1689 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1690 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1691 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001692 /* At least BS-11 wants a TLV16 here */
1693 if (bts->type == GSM_BTS_TYPE_BS11)
1694 *len += 1;
1695 else
1696 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001697 }
1698 }
Harald Weltee0590df2009-02-15 03:34:15 +00001699 }
Harald Welte1fe24122014-01-19 17:18:21 +01001700 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001701 if (bts->type == GSM_BTS_TYPE_BS11)
1702 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001703
1704 return abis_nm_sendmsg(bts, msg);
1705}
1706
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001707int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1708 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001709{
1710 struct abis_om_hdr *oh;
1711 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001712 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1713 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001714
1715 if (nack) {
1716 len += 2;
1717 msgtype = NM_MT_SW_ACT_REQ_NACK;
1718 }
Harald Welte34a99682009-02-13 02:41:40 +00001719
1720 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001721 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1722
Harald Welte34a99682009-02-13 02:41:40 +00001723 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001724 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001725 memcpy(ptr, attr, att_len);
1726 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001727 if (nack)
1728 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001729
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001730 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001731}
1732
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001733int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001734{
Harald Welte8470bf22008-12-25 23:28:35 +00001735 struct msgb *msg = nm_msgb_alloc();
1736 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001737 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001738
1739 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1740 fill_om_hdr(oh, len);
1741 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001742 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001743
1744 return abis_nm_sendmsg(bts, msg);
1745}
1746
1747/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001748static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001749{
1750 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001751 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001752
1753 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001754 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001755 0xff, 0xff, 0xff);
1756
1757 return abis_nm_sendmsg(bts, msg);
1758}
1759
Harald Welte34a99682009-02-13 02:41:40 +00001760/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001761int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
Harald Welte34a99682009-02-13 02:41:40 +00001762{
1763 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001764 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001765 struct msgb *msg = nm_msgb_alloc();
1766
1767 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001768 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001769
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001770 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001771 DEBUGPC(DNM, "Sending OPSTART\n");
1772
Harald Welte34a99682009-02-13 02:41:40 +00001773 return abis_nm_sendmsg(bts, msg);
1774}
1775
1776/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001777int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1778 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001779{
1780 struct abis_om_hdr *oh;
1781 struct msgb *msg = nm_msgb_alloc();
1782
1783 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1784 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1785 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1786
1787 return abis_nm_sendmsg(bts, msg);
1788}
1789
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001790int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1791 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001792{
1793 struct abis_om_hdr *oh;
1794 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001795 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001796
1797 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1798 e1_port0, ts0, e1_port1, ts1);
1799
1800 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1801 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1802 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1803
1804 attr = msgb_put(msg, 3);
1805 attr[0] = NM_ATT_MDROP_LINK;
1806 attr[1] = e1_port0;
1807 attr[2] = ts0;
1808
1809 attr = msgb_put(msg, 3);
1810 attr[0] = NM_ATT_MDROP_NEXT;
1811 attr[1] = e1_port1;
1812 attr[2] = ts1;
1813
1814 return abis_nm_sendmsg(bts, msg);
1815}
Harald Welte34a99682009-02-13 02:41:40 +00001816
Harald Weltec7310382009-08-08 00:02:36 +02001817/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001818int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1819 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1820 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001821{
1822 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001823
Harald Welte15c61722011-05-22 22:45:37 +02001824 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001825
1826 if (!msg)
1827 msg = nm_msgb_alloc();
1828
1829 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1830 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1831 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1832 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001833 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001834
1835 return abis_nm_sendmsg(bts, msg);
1836}
1837
Harald Welte52b1f982008-12-23 20:25:15 +00001838int abis_nm_event_reports(struct gsm_bts *bts, int on)
1839{
1840 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001841 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001842 else
Harald Welte227d4072009-01-03 08:16:25 +00001843 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001844}
1845
Harald Welte47d88ae2009-01-04 12:02:08 +00001846/* Siemens (or BS-11) specific commands */
1847
Harald Welte3ffd1372009-02-01 22:15:49 +00001848int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1849{
1850 if (reconnect == 0)
1851 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1852 else
1853 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1854}
1855
Harald Welteb8427972009-02-05 19:27:17 +00001856int abis_nm_bs11_restart(struct gsm_bts *bts)
1857{
1858 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1859}
1860
1861
Harald Welte268bb402009-02-01 19:11:56 +00001862struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001863 uint16_t year;
1864 uint8_t month;
1865 uint8_t day;
1866 uint8_t hour;
1867 uint8_t min;
1868 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001869} __attribute__((packed));
1870
1871
1872void get_bs11_date_time(struct bs11_date_time *aet)
1873{
1874 time_t t;
1875 struct tm *tm;
1876
1877 t = time(NULL);
1878 tm = localtime(&t);
1879 aet->sec = tm->tm_sec;
1880 aet->min = tm->tm_min;
1881 aet->hour = tm->tm_hour;
1882 aet->day = tm->tm_mday;
1883 aet->month = tm->tm_mon;
1884 aet->year = htons(1900 + tm->tm_year);
1885}
1886
Harald Welte05188ee2009-01-18 11:39:08 +00001887int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001888{
Harald Welte4668fda2009-01-03 08:19:29 +00001889 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001890}
1891
Harald Welte05188ee2009-01-18 11:39:08 +00001892int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001893{
1894 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001895 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001896 else
Harald Welte4668fda2009-01-03 08:19:29 +00001897 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001898}
Harald Welte47d88ae2009-01-04 12:02:08 +00001899
Harald Welte05188ee2009-01-18 11:39:08 +00001900int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001901 enum abis_bs11_objtype type, uint8_t idx,
1902 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001903{
1904 struct abis_om_hdr *oh;
1905 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001906 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001907
1908 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001909 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001910 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001911 cur = msgb_put(msg, attr_len);
1912 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001913
1914 return abis_nm_sendmsg(bts, msg);
1915}
1916
Harald Welte78fc0d42009-02-19 02:50:57 +00001917int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001918 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001919{
1920 struct abis_om_hdr *oh;
1921 struct msgb *msg = nm_msgb_alloc();
1922
1923 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1924 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1925 NM_OC_BS11, type, 0, idx);
1926
1927 return abis_nm_sendmsg(bts, msg);
1928}
1929
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001930int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001931{
1932 struct abis_om_hdr *oh;
1933 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001934 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001935
1936 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001937 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001938 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1939 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001940
1941 return abis_nm_sendmsg(bts, msg);
1942}
1943
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001944int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001945{
1946 struct abis_om_hdr *oh;
1947 struct msgb *msg = nm_msgb_alloc();
1948
1949 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1950 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001951 idx, 0xff, 0xff);
1952
1953 return abis_nm_sendmsg(bts, msg);
1954}
1955
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001956int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001957{
1958 struct abis_om_hdr *oh;
1959 struct msgb *msg = nm_msgb_alloc();
1960
1961 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1962 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1963 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001964
1965 return abis_nm_sendmsg(bts, msg);
1966}
Harald Welte05188ee2009-01-18 11:39:08 +00001967
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001968static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001969int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1970{
1971 struct abis_om_hdr *oh;
1972 struct msgb *msg = nm_msgb_alloc();
1973
1974 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1975 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1976 0xff, 0xff, 0xff);
1977 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1978
1979 return abis_nm_sendmsg(bts, msg);
1980}
1981
Harald Welteb6c92ae2009-02-21 20:15:32 +00001982/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001983int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1984 uint8_t e1_timeslot, uint8_t e1_subslot,
1985 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001986{
1987 struct abis_om_hdr *oh;
1988 struct abis_nm_channel *ch;
1989 struct msgb *msg = nm_msgb_alloc();
1990
1991 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001992 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001993 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1994
1995 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1996 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001997 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001998
1999 return abis_nm_sendmsg(bts, msg);
2000}
2001
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002002int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002003{
2004 struct abis_om_hdr *oh;
2005 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002006
2007 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002008 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002009 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2010 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2011
2012 return abis_nm_sendmsg(trx->bts, msg);
2013}
2014
Harald Welte78fc0d42009-02-19 02:50:57 +00002015int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2016{
2017 struct abis_om_hdr *oh;
2018 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002019 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002020
2021 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2022 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2023 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2024 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2025
2026 return abis_nm_sendmsg(trx->bts, msg);
2027}
2028
Harald Welteaaf02d92009-04-29 13:25:57 +00002029int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2030{
2031 struct abis_om_hdr *oh;
2032 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002033 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002034
2035 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2036 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2037 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002038 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002039
2040 return abis_nm_sendmsg(bts, msg);
2041}
2042
Harald Welteef061952009-05-17 12:43:42 +00002043int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2044{
2045 struct abis_om_hdr *oh;
2046 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002047 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002048 NM_ATT_BS11_CCLK_TYPE };
2049
2050 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2051 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2052 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2053 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2054
2055 return abis_nm_sendmsg(bts, msg);
2056
2057}
Harald Welteaaf02d92009-04-29 13:25:57 +00002058
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002059//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002060
Harald Welte1bc09062009-01-18 14:17:52 +00002061int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002062{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002063 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2064}
2065
Daniel Willmann4b054c82010-01-07 00:46:26 +01002066int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2067{
2068 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2069}
2070
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002071int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002072{
Harald Welte05188ee2009-01-18 11:39:08 +00002073 struct abis_om_hdr *oh;
2074 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002075 struct bs11_date_time bdt;
2076
2077 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002078
2079 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002080 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002081 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002082 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002083 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002084 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002085 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002086 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002087 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002088 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002089 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002090 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002091 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002092 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002093 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002094 }
Harald Welte05188ee2009-01-18 11:39:08 +00002095
2096 return abis_nm_sendmsg(bts, msg);
2097}
Harald Welte1bc09062009-01-18 14:17:52 +00002098
2099int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2100{
2101 struct abis_om_hdr *oh;
2102 struct msgb *msg;
2103
2104 if (strlen(password) != 10)
2105 return -EINVAL;
2106
2107 msg = nm_msgb_alloc();
2108 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002109 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002110 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002111 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002112
2113 return abis_nm_sendmsg(bts, msg);
2114}
2115
Harald Weltee69f5fb2009-04-28 16:31:38 +00002116/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2117int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2118{
2119 struct abis_om_hdr *oh;
2120 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002121 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002122
2123 msg = nm_msgb_alloc();
2124 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2125 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2126 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002127
2128 if (locked)
2129 tlv_value = BS11_LI_PLL_LOCKED;
2130 else
2131 tlv_value = BS11_LI_PLL_STANDALONE;
2132
2133 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002134
2135 return abis_nm_sendmsg(bts, msg);
2136}
2137
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002138/* Set the calibration value of the PLL (work value/set value)
2139 * It depends on the login which one is changed */
2140int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2141{
2142 struct abis_om_hdr *oh;
2143 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002144 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002145
2146 msg = nm_msgb_alloc();
2147 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2148 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2149 BS11_OBJ_TRX1, 0x00, 0x00);
2150
2151 tlv_value[0] = value>>8;
2152 tlv_value[1] = value&0xff;
2153
2154 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2155
2156 return abis_nm_sendmsg(bts, msg);
2157}
2158
Harald Welte1bc09062009-01-18 14:17:52 +00002159int abis_nm_bs11_get_state(struct gsm_bts *bts)
2160{
2161 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2162}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002163
2164/* BS11 SWL */
2165
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002166void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002167
Harald Welte5e4d1b32009-02-01 13:36:56 +00002168struct abis_nm_bs11_sw {
2169 struct gsm_bts *bts;
2170 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002171 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002172 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002173 struct llist_head file_list;
2174 gsm_cbfn *user_cb; /* specified by the user */
2175};
2176static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2177
2178struct file_list_entry {
2179 struct llist_head list;
2180 char fname[PATH_MAX];
2181};
2182
2183struct file_list_entry *fl_dequeue(struct llist_head *queue)
2184{
2185 struct llist_head *lh;
2186
2187 if (llist_empty(queue))
2188 return NULL;
2189
2190 lh = queue->next;
2191 llist_del(lh);
2192
2193 return llist_entry(lh, struct file_list_entry, list);
2194}
2195
2196static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2197{
2198 char linebuf[255];
2199 struct llist_head *lh, *lh2;
2200 FILE *swl;
2201 int rc = 0;
2202
2203 swl = fopen(bs11_sw->swl_fname, "r");
2204 if (!swl)
2205 return -ENODEV;
2206
2207 /* zero the stale file list, if any */
2208 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2209 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002210 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002211 }
2212
2213 while (fgets(linebuf, sizeof(linebuf), swl)) {
2214 char file_id[12+1];
2215 char file_version[80+1];
2216 struct file_list_entry *fle;
2217 static char dir[PATH_MAX];
2218
2219 if (strlen(linebuf) < 4)
2220 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002221
Harald Welte5e4d1b32009-02-01 13:36:56 +00002222 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2223 if (rc < 0) {
2224 perror("ERR parsing SWL file");
2225 rc = -EINVAL;
2226 goto out;
2227 }
2228 if (rc < 2)
2229 continue;
2230
Harald Welte470ec292009-06-26 20:25:23 +02002231 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002232 if (!fle) {
2233 rc = -ENOMEM;
2234 goto out;
2235 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002236
2237 /* construct new filename */
2238 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welteb0993e62016-11-25 23:54:18 +01002239 dir[sizeof(dir)-1] = '\0';
Harald Welte5e4d1b32009-02-01 13:36:56 +00002240 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2241 strcat(fle->fname, "/");
2242 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002243
2244 llist_add_tail(&fle->list, &bs11_sw->file_list);
2245 }
2246
2247out:
2248 fclose(swl);
2249 return rc;
2250}
2251
2252/* bs11 swload specific callback, passed to abis_nm core swload */
2253static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2254 struct msgb *msg, void *data, void *param)
2255{
2256 struct abis_nm_bs11_sw *bs11_sw = data;
2257 struct file_list_entry *fle;
2258 int rc = 0;
2259
Harald Welte5e4d1b32009-02-01 13:36:56 +00002260 switch (event) {
2261 case NM_MT_LOAD_END_ACK:
2262 fle = fl_dequeue(&bs11_sw->file_list);
2263 if (fle) {
2264 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002265 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002266 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002267 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002268 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002269 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002270 } else {
2271 /* activate the SWL */
2272 rc = abis_nm_software_activate(bs11_sw->bts,
2273 bs11_sw->swl_fname,
2274 bs11_swload_cbfn,
2275 bs11_sw);
2276 }
2277 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002278 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002279 case NM_MT_LOAD_END_NACK:
2280 case NM_MT_LOAD_INIT_ACK:
2281 case NM_MT_LOAD_INIT_NACK:
2282 case NM_MT_ACTIVATE_SW_NACK:
2283 case NM_MT_ACTIVATE_SW_ACK:
2284 default:
2285 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002286 if (bs11_sw->user_cb)
2287 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002288 break;
2289 }
2290
2291 return rc;
2292}
2293
2294/* Siemens provides a SWL file that is a mere listing of all the other
2295 * files that are part of a software release. We need to upload first
2296 * the list file, and then each file that is listed in the list file */
2297int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002298 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002299{
2300 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2301 struct file_list_entry *fle;
2302 int rc = 0;
2303
2304 INIT_LLIST_HEAD(&bs11_sw->file_list);
2305 bs11_sw->bts = bts;
2306 bs11_sw->win_size = win_size;
2307 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002308 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002309
2310 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte7b6bae62016-11-25 23:52:46 +01002311 bs11_sw->swl_fname[sizeof(bs11_sw->swl_fname)-1] = '\0';
Harald Welte5e4d1b32009-02-01 13:36:56 +00002312 rc = bs11_read_swl_file(bs11_sw);
2313 if (rc < 0)
2314 return rc;
2315
2316 /* dequeue next item in file list */
2317 fle = fl_dequeue(&bs11_sw->file_list);
2318 if (!fle)
2319 return -EINVAL;
2320
2321 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002322 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002323 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002324 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002325 return rc;
2326}
2327
Harald Welte5083b0b2009-02-02 19:20:52 +00002328#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002329static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002330 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2331 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2332 NM_ATT_BS11_LMT_USER_NAME,
2333
2334 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2335
2336 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2337
2338 NM_ATT_BS11_SW_LOAD_STORED };
2339
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002340static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002341 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2342 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2343 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2344 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002345#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002346
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002347static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002348 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2349 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002350 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002351
2352int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2353{
2354 struct abis_om_hdr *oh;
2355 struct msgb *msg = nm_msgb_alloc();
2356
2357 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2358 /* SiemensHW CCTRL object */
2359 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2360 0x03, 0x00, 0x00);
2361 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2362
2363 return abis_nm_sendmsg(bts, msg);
2364}
Harald Welte268bb402009-02-01 19:11:56 +00002365
2366int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2367{
2368 struct abis_om_hdr *oh;
2369 struct msgb *msg = nm_msgb_alloc();
2370 struct bs11_date_time aet;
2371
2372 get_bs11_date_time(&aet);
2373 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2374 /* SiemensHW CCTRL object */
2375 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2376 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002377 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002378
2379 return abis_nm_sendmsg(bts, msg);
2380}
Harald Welte5c1e4582009-02-15 11:57:29 +00002381
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002382int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002383{
2384 struct abis_om_hdr *oh;
2385 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002386 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002387
2388 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2389 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2390 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2391 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2392
2393 return abis_nm_sendmsg(bts, msg);
2394}
2395
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002396int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002397{
2398 struct abis_om_hdr *oh;
2399 struct msgb *msg = nm_msgb_alloc();
2400 struct bs11_date_time aet;
2401
2402 get_bs11_date_time(&aet);
2403 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2404 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2405 bport, 0xff, 0x02);
2406 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2407
2408 return abis_nm_sendmsg(bts, msg);
2409}
2410
Harald Welte5c1e4582009-02-15 11:57:29 +00002411/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002412static const char ipaccess_magic[] = "com.ipaccess";
2413
Harald Welte677c21f2009-02-17 13:22:23 +00002414
2415static int abis_nm_rx_ipacc(struct msgb *msg)
2416{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002417 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002418 struct abis_om_hdr *oh = msgb_l2(msg);
2419 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002420 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002421 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002422 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002423 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002424
2425 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002426 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002427 return -EINVAL;
2428 }
2429
Harald Welte193fefc2009-04-30 15:16:27 +00002430 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002431 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002432
Harald Welte15c61722011-05-22 22:45:37 +02002433 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002434
Harald Welte746d6092009-10-19 22:11:11 +02002435 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002436
Harald Welte677c21f2009-02-17 13:22:23 +00002437 switch (foh->msg_type) {
2438 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002439 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002440 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2441 memcpy(&addr,
2442 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2443
2444 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2445 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002446 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002447 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002448 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002449 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002450 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2451 DEBUGPC(DNM, "STREAM=0x%02x ",
2452 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002453 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002454 break;
2455 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002456 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002457 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002458 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002459 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002460 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002461 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002462 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002463 case NM_MT_IPACC_SET_NVATTR_ACK:
2464 DEBUGPC(DNM, "SET NVATTR ACK\n");
2465 /* FIXME: decode and show the actual attributes */
2466 break;
2467 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002468 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002469 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002470 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002471 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002472 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002473 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002474 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002475 case NM_MT_IPACC_GET_NVATTR_ACK:
2476 DEBUGPC(DNM, "GET NVATTR ACK\n");
2477 /* FIXME: decode and show the actual attributes */
2478 break;
2479 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002480 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002481 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002482 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002483 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002484 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002485 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002486 break;
Harald Welte15c44172009-10-08 20:15:24 +02002487 case NM_MT_IPACC_SET_ATTR_ACK:
2488 DEBUGPC(DNM, "SET ATTR ACK\n");
2489 break;
2490 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002491 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002492 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002493 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002494 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002495 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002496 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002497 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002498 default:
2499 DEBUGPC(DNM, "unknown\n");
2500 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002501 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002502
2503 /* signal handling */
2504 switch (foh->msg_type) {
2505 case NM_MT_IPACC_RSL_CONNECT_NACK:
2506 case NM_MT_IPACC_SET_NVATTR_NACK:
2507 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002508 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002509 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002510 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002511 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002512 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002513 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002514 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002515 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002516 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002517 default:
2518 break;
2519 }
2520
Harald Welte677c21f2009-02-17 13:22:23 +00002521 return 0;
2522}
2523
Harald Welte193fefc2009-04-30 15:16:27 +00002524/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002525int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2526 uint8_t obj_class, uint8_t bts_nr,
2527 uint8_t trx_nr, uint8_t ts_nr,
2528 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002529{
2530 struct msgb *msg = nm_msgb_alloc();
2531 struct abis_om_hdr *oh;
2532 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002533 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002534
2535 /* construct the 12.21 OM header, observe the erroneous length */
2536 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2537 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2538 oh->mdisc = ABIS_OM_MDISC_MANUF;
2539
2540 /* add the ip.access magic */
2541 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2542 *data++ = sizeof(ipaccess_magic);
2543 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2544
2545 /* fill the 12.21 FOM header */
2546 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2547 foh->msg_type = msg_type;
2548 foh->obj_class = obj_class;
2549 foh->obj_inst.bts_nr = bts_nr;
2550 foh->obj_inst.trx_nr = trx_nr;
2551 foh->obj_inst.ts_nr = ts_nr;
2552
2553 if (attr && attr_len) {
2554 data = msgb_put(msg, attr_len);
2555 memcpy(data, attr, attr_len);
2556 }
2557
2558 return abis_nm_sendmsg(bts, msg);
2559}
Harald Welte677c21f2009-02-17 13:22:23 +00002560
Harald Welte193fefc2009-04-30 15:16:27 +00002561/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002562int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002563 int attr_len)
2564{
Harald Welte2ef156d2010-01-07 20:39:42 +01002565 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2566 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002567 attr_len);
2568}
2569
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002570int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002571 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002572{
2573 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002574 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002575 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2576 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2577
2578 int attr_len = sizeof(attr);
2579
2580 ia.s_addr = htonl(ip);
2581 attr[1] = stream;
2582 attr[3] = port >> 8;
2583 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002584 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002585
2586 /* if ip == 0, we use the default IP */
2587 if (ip == 0)
2588 attr_len -= 5;
2589
2590 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002591 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002592
2593 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2594 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2595 trx->nr, 0xff, attr, attr_len);
2596}
2597
Harald Welte193fefc2009-04-30 15:16:27 +00002598/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002599int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002600{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002601 struct abis_om_hdr *oh;
2602 struct msgb *msg = nm_msgb_alloc();
2603
2604 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2605 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2606 trx->bts->nr, trx->nr, 0xff);
2607
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002608 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002609}
Harald Weltedaef5212009-10-24 10:20:41 +02002610
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002611int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2612 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2613 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002614{
2615 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2616 obj_class, bts_nr, trx_nr, ts_nr,
2617 attr, attr_len);
2618}
Harald Welte0f255852009-11-12 14:48:42 +01002619
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002620void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002621{
2622 /* we simply reuse the GSM48 function and overwrite the RAC
2623 * with the Cell ID */
2624 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002625 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002626}
2627
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002628void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2629{
2630 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2631
Harald Welted64c0bc2011-05-30 12:07:53 +02002632 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002633 if (!trx->bts || !trx->bts->oml_link)
2634 return;
2635
2636 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2637 trx->bts->bts_nr, trx->nr, 0xff,
2638 new_state);
2639}
2640
Harald Welte92b1fe42010-03-25 11:45:30 +08002641static const struct value_string ipacc_testres_names[] = {
2642 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2643 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2644 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2645 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2646 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2647 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002648};
2649
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002650const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002651{
Harald Welte92b1fe42010-03-25 11:45:30 +08002652 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002653}
2654
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002655void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002656{
2657 cid->mcc = (buf[0] & 0xf) * 100;
2658 cid->mcc += (buf[0] >> 4) * 10;
2659 cid->mcc += (buf[1] & 0xf) * 1;
2660
2661 if (buf[1] >> 4 == 0xf) {
2662 cid->mnc = (buf[2] & 0xf) * 10;
2663 cid->mnc += (buf[2] >> 4) * 1;
2664 } else {
2665 cid->mnc = (buf[2] & 0xf) * 100;
2666 cid->mnc += (buf[2] >> 4) * 10;
2667 cid->mnc += (buf[1] >> 4) * 1;
2668 }
2669
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002670 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2671 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002672}
2673
Harald Welte0f255852009-11-12 14:48:42 +01002674/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002675int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002676{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002677 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002678 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002679
Harald Welteaf109b92010-07-22 18:14:36 +02002680 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002681
2682 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2683 return -EINVAL;
2684 cur++;
2685
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002686 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002687 cur += 2;
2688
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002689 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002690 cur += 2;
2691
2692 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2693 binf->freq_qual = *cur >> 2;
2694
Harald Welteaf109b92010-07-22 18:14:36 +02002695 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002696 binf->arfcn |= *cur++;
2697
2698 if (binf->info_type & IPAC_BINF_RXLEV)
2699 binf->rx_lev = *cur & 0x3f;
2700 cur++;
2701
2702 if (binf->info_type & IPAC_BINF_RXQUAL)
2703 binf->rx_qual = *cur & 0x7;
2704 cur++;
2705
2706 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002707 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002708 cur += 2;
2709
2710 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002711 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002712 cur += 2;
2713
2714 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002715 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002716 cur += 4;
2717
Harald Weltea780a3d2010-07-30 22:34:42 +02002718#if 0
2719 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002720 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002721#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002722 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002723 cur++;
2724
Harald Welteb40a38f2009-11-13 11:56:05 +01002725 ipac_parse_cgi(&binf->cgi, cur);
2726 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002727
2728 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2729 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2730 cur += sizeof(binf->ba_list_si2);
2731 }
2732
2733 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2734 memcpy(binf->ba_list_si2bis, cur,
2735 sizeof(binf->ba_list_si2bis));
2736 cur += sizeof(binf->ba_list_si2bis);
2737 }
2738
2739 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2740 memcpy(binf->ba_list_si2ter, cur,
2741 sizeof(binf->ba_list_si2ter));
2742 cur += sizeof(binf->ba_list_si2ter);
2743 }
2744
2745 return 0;
2746}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002747
2748void abis_nm_clear_queue(struct gsm_bts *bts)
2749{
2750 struct msgb *msg;
2751
2752 while (!llist_empty(&bts->abis_queue)) {
2753 msg = msgb_dequeue(&bts->abis_queue);
2754 msgb_free(msg);
2755 }
2756
2757 bts->abis_nm_pend = 0;
2758}