blob: c9b2aaca4ce661ea7536b7832d57a89861a3e0ce [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)) {
841 fseek(stream, pos, SEEK_SET);
842 return 1;
843 }
844
845 fseek(stream, pos, SEEK_SET);
846 return 0;
847}
848
Harald Welte4724f992009-01-18 18:01:49 +0000849/* 6.2.2 / 8.3.2 Load Data Segment */
850static int sw_load_segment(struct abis_nm_sw *sw)
851{
852 struct abis_om_hdr *oh;
853 struct msgb *msg = nm_msgb_alloc();
854 char seg_buf[256];
855 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000856 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200857 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000858
859 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000860
861 switch (sw->bts->type) {
862 case GSM_BTS_TYPE_BS11:
863 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
864 perror("fgets reading segment");
865 return -EINVAL;
866 }
867 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000868
869 /* check if we're sending the last line */
870 sw->last_seg = is_last_line(sw->stream);
871 if (sw->last_seg)
872 seg_buf[1] = 0;
873 else
874 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000875
876 len = strlen(line_buf) + 2;
877 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200878 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000879 /* BS11 wants CR + LF in excess of the TLV length !?! */
880 tlv[1] -= 2;
881
882 /* we only now know the exact length for the OM hdr */
883 len = strlen(line_buf)+2;
884 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100885 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200886 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100887 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
888 if (len < 0) {
889 perror("read failed");
890 return -EINVAL;
891 }
892
893 if (len != IPACC_SEGMENT_SIZE)
894 sw->last_seg = 1;
895
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100896 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200897 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100898 len += 3;
899 break;
900 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000901 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100902 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000903 /* FIXME: Other BTS types */
904 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000905 }
Harald Welte4724f992009-01-18 18:01:49 +0000906
Harald Welte4724f992009-01-18 18:01:49 +0000907 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
908 sw->obj_instance[0], sw->obj_instance[1],
909 sw->obj_instance[2]);
910
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100911 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000912}
913
914/* 6.2.4 / 8.3.4 Load Data End */
915static int sw_load_end(struct abis_nm_sw *sw)
916{
917 struct abis_om_hdr *oh;
918 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200919 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000920
921 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
922 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
923 sw->obj_instance[0], sw->obj_instance[1],
924 sw->obj_instance[2]);
925
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100926 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000927 return abis_nm_sendmsg(sw->bts, msg);
928}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000929
Harald Welte52b1f982008-12-23 20:25:15 +0000930/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000931static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000932{
Harald Welte4724f992009-01-18 18:01:49 +0000933 struct abis_om_hdr *oh;
934 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200935 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000936
Harald Welte4724f992009-01-18 18:01:49 +0000937 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
938 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
939 sw->obj_instance[0], sw->obj_instance[1],
940 sw->obj_instance[2]);
941
942 /* FIXME: this is BS11 specific format */
943 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
944 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
945 sw->file_version);
946
947 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000948}
Harald Welte4724f992009-01-18 18:01:49 +0000949
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100950struct sdp_firmware {
951 char magic[4];
952 char more_magic[4];
953 unsigned int header_length;
954 unsigned int file_length;
955} __attribute__ ((packed));
956
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100957static int parse_sdp_header(struct abis_nm_sw *sw)
958{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100959 struct sdp_firmware firmware_header;
960 int rc;
961 struct stat stat;
962
963 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
964 if (rc != sizeof(firmware_header)) {
965 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
966 return -1;
967 }
968
969 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
970 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
971 return -1;
972 }
973
974 if (firmware_header.more_magic[0] != 0x10 ||
975 firmware_header.more_magic[1] != 0x02 ||
976 firmware_header.more_magic[2] != 0x00 ||
977 firmware_header.more_magic[3] != 0x00) {
978 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
979 return -1;
980 }
981
982
983 if (fstat(sw->fd, &stat) == -1) {
984 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
985 return -1;
986 }
987
988 if (ntohl(firmware_header.file_length) != stat.st_size) {
989 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
990 return -1;
991 }
992
993 /* go back to the start as we checked the whole filesize.. */
994 lseek(sw->fd, 0l, SEEK_SET);
995 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
996 "There might be checksums in the file that are not\n"
997 "verified and incomplete firmware might be flashed.\n"
998 "There is absolutely no WARRANTY that flashing will\n"
999 "work.\n");
1000 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001001}
1002
Harald Welte4724f992009-01-18 18:01:49 +00001003static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1004{
1005 char file_id[12+1];
1006 char file_version[80+1];
1007 int rc;
1008
1009 sw->fd = open(fname, O_RDONLY);
1010 if (sw->fd < 0)
1011 return sw->fd;
1012
1013 switch (sw->bts->type) {
1014 case GSM_BTS_TYPE_BS11:
1015 sw->stream = fdopen(sw->fd, "r");
1016 if (!sw->stream) {
1017 perror("fdopen");
1018 return -1;
1019 }
1020 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001021 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001022 file_id, file_version);
1023 if (rc != 2) {
1024 perror("parsing header line of software file");
1025 return -1;
1026 }
1027 strcpy((char *)sw->file_id, file_id);
1028 sw->file_id_len = strlen(file_id);
1029 strcpy((char *)sw->file_version, file_version);
1030 sw->file_version_len = strlen(file_version);
1031 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001032 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001033 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001034 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001035 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001036 rc = parse_sdp_header(sw);
1037 if (rc < 0) {
1038 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1039 return -1;
1040 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001041
1042 strcpy((char *)sw->file_id, "id");
1043 sw->file_id_len = 3;
1044 strcpy((char *)sw->file_version, "version");
1045 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001046 break;
Harald Welte4724f992009-01-18 18:01:49 +00001047 default:
1048 /* We don't know how to treat them yet */
1049 close(sw->fd);
1050 return -EINVAL;
1051 }
1052
1053 return 0;
1054}
1055
1056static void sw_close_file(struct abis_nm_sw *sw)
1057{
1058 switch (sw->bts->type) {
1059 case GSM_BTS_TYPE_BS11:
1060 fclose(sw->stream);
1061 break;
1062 default:
1063 close(sw->fd);
1064 break;
1065 }
1066}
1067
1068/* Fill the window */
1069static int sw_fill_window(struct abis_nm_sw *sw)
1070{
1071 int rc;
1072
1073 while (sw->seg_in_window < sw->window_size) {
1074 rc = sw_load_segment(sw);
1075 if (rc < 0)
1076 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001077 if (sw->last_seg)
1078 break;
Harald Welte4724f992009-01-18 18:01:49 +00001079 }
1080 return 0;
1081}
1082
1083/* callback function from abis_nm_rcvmsg() handler */
1084static int abis_nm_rcvmsg_sw(struct msgb *mb)
1085{
1086 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001087 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001088 int rc = -1;
1089 struct abis_nm_sw *sw = &g_sw;
1090 enum sw_state old_state = sw->state;
1091
Harald Welte3ffd1372009-02-01 22:15:49 +00001092 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001093
1094 switch (sw->state) {
1095 case SW_STATE_WAIT_INITACK:
1096 switch (foh->msg_type) {
1097 case NM_MT_LOAD_INIT_ACK:
1098 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001099 if (sw->cbfn)
1100 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1101 NM_MT_LOAD_INIT_ACK, mb,
1102 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001103 rc = sw_fill_window(sw);
1104 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001105 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001106 break;
1107 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001108 if (sw->forced) {
1109 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1110 "Init NACK\n");
1111 if (sw->cbfn)
1112 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1113 NM_MT_LOAD_INIT_ACK, mb,
1114 sw->cb_data, NULL);
1115 rc = sw_fill_window(sw);
1116 sw->state = SW_STATE_WAIT_SEGACK;
1117 } else {
1118 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001119 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001120 if (sw->cbfn)
1121 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1122 NM_MT_LOAD_INIT_NACK, mb,
1123 sw->cb_data, NULL);
1124 sw->state = SW_STATE_ERROR;
1125 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001126 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001127 break;
1128 }
1129 break;
1130 case SW_STATE_WAIT_SEGACK:
1131 switch (foh->msg_type) {
1132 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001133 if (sw->cbfn)
1134 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1135 NM_MT_LOAD_SEG_ACK, mb,
1136 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001137 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001138 if (!sw->last_seg) {
1139 /* fill window with more segments */
1140 rc = sw_fill_window(sw);
1141 sw->state = SW_STATE_WAIT_SEGACK;
1142 } else {
1143 /* end the transfer */
1144 sw->state = SW_STATE_WAIT_ENDACK;
1145 rc = sw_load_end(sw);
1146 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001147 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001148 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001149 case NM_MT_LOAD_ABORT:
1150 if (sw->cbfn)
1151 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1152 NM_MT_LOAD_ABORT, mb,
1153 sw->cb_data, NULL);
1154 break;
Harald Welte4724f992009-01-18 18:01:49 +00001155 }
1156 break;
1157 case SW_STATE_WAIT_ENDACK:
1158 switch (foh->msg_type) {
1159 case NM_MT_LOAD_END_ACK:
1160 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001161 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1162 sw->bts->nr);
1163 sw->state = SW_STATE_NONE;
1164 if (sw->cbfn)
1165 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1166 NM_MT_LOAD_END_ACK, mb,
1167 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001168 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001169 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001170 break;
1171 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001172 if (sw->forced) {
1173 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1174 "End NACK\n");
1175 sw->state = SW_STATE_NONE;
1176 if (sw->cbfn)
1177 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1178 NM_MT_LOAD_END_ACK, mb,
1179 sw->cb_data, NULL);
1180 } else {
1181 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001182 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001183 sw->state = SW_STATE_ERROR;
1184 if (sw->cbfn)
1185 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1186 NM_MT_LOAD_END_NACK, mb,
1187 sw->cb_data, NULL);
1188 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001189 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001190 break;
1191 }
1192 case SW_STATE_WAIT_ACTACK:
1193 switch (foh->msg_type) {
1194 case NM_MT_ACTIVATE_SW_ACK:
1195 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001196 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001197 sw->state = SW_STATE_NONE;
1198 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001199 if (sw->cbfn)
1200 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1201 NM_MT_ACTIVATE_SW_ACK, mb,
1202 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001203 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001204 break;
1205 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001206 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001207 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001208 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001209 if (sw->cbfn)
1210 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1211 NM_MT_ACTIVATE_SW_NACK, mb,
1212 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001213 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001214 break;
1215 }
1216 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001217 switch (foh->msg_type) {
1218 case NM_MT_ACTIVATE_SW_ACK:
1219 rc = 0;
1220 break;
1221 }
1222 break;
Harald Welte4724f992009-01-18 18:01:49 +00001223 case SW_STATE_ERROR:
1224 break;
1225 }
1226
1227 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001228 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001229 foh->msg_type, old_state, sw->state);
1230
1231 return rc;
1232}
1233
1234/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001235int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001236 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001237 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001238{
1239 struct abis_nm_sw *sw = &g_sw;
1240 int rc;
1241
Harald Welte5e4d1b32009-02-01 13:36:56 +00001242 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1243 bts->nr, fname);
1244
Harald Welte4724f992009-01-18 18:01:49 +00001245 if (sw->state != SW_STATE_NONE)
1246 return -EBUSY;
1247
1248 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001249 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001250
1251 switch (bts->type) {
1252 case GSM_BTS_TYPE_BS11:
1253 sw->obj_class = NM_OC_SITE_MANAGER;
1254 sw->obj_instance[0] = 0xff;
1255 sw->obj_instance[1] = 0xff;
1256 sw->obj_instance[2] = 0xff;
1257 break;
1258 case GSM_BTS_TYPE_NANOBTS:
1259 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001260 sw->obj_instance[0] = sw->bts->nr;
1261 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001262 sw->obj_instance[2] = 0xff;
1263 break;
1264 case GSM_BTS_TYPE_UNKNOWN:
1265 default:
1266 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1267 return -1;
1268 break;
1269 }
Harald Welte4724f992009-01-18 18:01:49 +00001270 sw->window_size = win_size;
1271 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001272 sw->cbfn = cbfn;
1273 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001274 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001275
1276 rc = sw_open_file(sw, fname);
1277 if (rc < 0) {
1278 sw->state = SW_STATE_NONE;
1279 return rc;
1280 }
1281
1282 return sw_load_init(sw);
1283}
Harald Welte52b1f982008-12-23 20:25:15 +00001284
Harald Welte1602ade2009-01-29 21:12:39 +00001285int abis_nm_software_load_status(struct gsm_bts *bts)
1286{
1287 struct abis_nm_sw *sw = &g_sw;
1288 struct stat st;
1289 int rc, percent;
1290
1291 rc = fstat(sw->fd, &st);
1292 if (rc < 0) {
1293 perror("ERROR during stat");
1294 return rc;
1295 }
1296
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001297 if (sw->stream)
1298 percent = (ftell(sw->stream) * 100) / st.st_size;
1299 else
1300 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001301 return percent;
1302}
1303
Harald Welte5e4d1b32009-02-01 13:36:56 +00001304/* Activate the specified software into the BTS */
1305int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1306 gsm_cbfn *cbfn, void *cb_data)
1307{
1308 struct abis_nm_sw *sw = &g_sw;
1309 int rc;
1310
1311 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1312 bts->nr, fname);
1313
1314 if (sw->state != SW_STATE_NONE)
1315 return -EBUSY;
1316
1317 sw->bts = bts;
1318 sw->obj_class = NM_OC_SITE_MANAGER;
1319 sw->obj_instance[0] = 0xff;
1320 sw->obj_instance[1] = 0xff;
1321 sw->obj_instance[2] = 0xff;
1322 sw->state = SW_STATE_WAIT_ACTACK;
1323 sw->cbfn = cbfn;
1324 sw->cb_data = cb_data;
1325
1326 /* Open the file in order to fill some sw struct members */
1327 rc = sw_open_file(sw, fname);
1328 if (rc < 0) {
1329 sw->state = SW_STATE_NONE;
1330 return rc;
1331 }
1332 sw_close_file(sw);
1333
1334 return sw_activate(sw);
1335}
1336
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001337static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1338 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001339{
Harald Welteadaf08b2009-01-18 11:08:10 +00001340 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001341 ch->bts_port = bts_port;
1342 ch->timeslot = ts_nr;
1343 ch->subslot = subslot_nr;
1344}
1345
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001346int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1347 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1348 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001349{
1350 struct abis_om_hdr *oh;
1351 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001352 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001353 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001354
1355 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1356 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1357 bts->bts_nr, trx_nr, 0xff);
1358
Harald Welte8470bf22008-12-25 23:28:35 +00001359 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001360
1361 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1362 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1363
1364 return abis_nm_sendmsg(bts, msg);
1365}
1366
1367/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1368int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001369 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001370{
Harald Welte8470bf22008-12-25 23:28:35 +00001371 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001372 struct abis_om_hdr *oh;
1373 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001374 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001375
1376 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001377 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001378 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1379
1380 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1381 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1382
1383 return abis_nm_sendmsg(bts, msg);
1384}
1385
1386#if 0
1387int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1388 struct abis_nm_abis_channel *chan)
1389{
1390}
1391#endif
1392
1393int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001394 uint8_t e1_port, uint8_t e1_timeslot,
1395 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001396{
1397 struct gsm_bts *bts = ts->trx->bts;
1398 struct abis_om_hdr *oh;
1399 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001400 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001401
1402 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1403 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001404 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001405
1406 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1407 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1408
Harald Weltef325eb42009-02-19 17:07:39 +00001409 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1410 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001411 e1_port, e1_timeslot, e1_subslot);
1412
Harald Welte52b1f982008-12-23 20:25:15 +00001413 return abis_nm_sendmsg(bts, msg);
1414}
1415
1416#if 0
1417int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1418 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001419 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001420{
1421}
1422#endif
1423
Harald Weltefe568f22012-08-14 19:15:57 +02001424/* Chapter 8.11.1 */
1425int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1426 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1427 uint8_t *attr, uint8_t attr_len)
1428{
1429 struct abis_om_hdr *oh;
1430 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001431
1432 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1433
1434 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1435 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1436 bts_nr, trx_nr, ts_nr);
1437 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1438
1439 return abis_nm_sendmsg(bts, msg);
1440}
1441
Harald Welte22af0db2009-02-14 15:41:08 +00001442/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001443int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001444{
1445 struct abis_om_hdr *oh;
1446 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001447 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001448
1449 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1450
1451 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001452 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 +00001453 cur = msgb_put(msg, attr_len);
1454 memcpy(cur, attr, attr_len);
1455
1456 return abis_nm_sendmsg(bts, msg);
1457}
1458
1459/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001460int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001461{
1462 struct abis_om_hdr *oh;
1463 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001464 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001465
1466 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1467
1468 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1469 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001470 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001471 cur = msgb_put(msg, attr_len);
1472 memcpy(cur, attr, attr_len);
1473
1474 return abis_nm_sendmsg(trx->bts, msg);
1475}
1476
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001477int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1478{
1479 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1480 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1481}
1482
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001483static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1484 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001485{
1486 int i;
1487
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001488 *reason = "Reason unknown";
1489
Harald Welte39c7deb2009-08-09 21:49:48 +02001490 /* As it turns out, the BS-11 has some very peculiar restrictions
1491 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301492 switch (ts->trx->bts->type) {
1493 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001494 switch (chan_comb) {
1495 case NM_CHANC_TCHHalf:
1496 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001497 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001498 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001499 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001500 return -EINVAL;
1501 case NM_CHANC_SDCCH:
1502 /* only one SDCCH/8 per TRX */
1503 for (i = 0; i < TRX_NR_TS; i++) {
1504 if (i == ts->nr)
1505 continue;
1506 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001507 NM_CHANC_SDCCH) {
1508 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001509 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001510 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001511 }
1512 /* not allowed for TS0 of BCCH-TRX */
1513 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001514 ts->nr == 0) {
1515 *reason = "SDCCH/8 must be on TS0.";
1516 return -EINVAL;
1517 }
1518
Harald Welte39c7deb2009-08-09 21:49:48 +02001519 /* not on the same TRX that has a BCCH+SDCCH4
1520 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001521 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001522 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001523 ts->trx->ts[0].nm_chan_comb == 8)) {
1524 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1525 return -EINVAL;
1526 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001527 break;
1528 case NM_CHANC_mainBCCH:
1529 case NM_CHANC_BCCHComb:
1530 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001531 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1532 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001533 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001534 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001535 break;
1536 case NM_CHANC_BCCH:
1537 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001538 if (ts->trx != ts->trx->bts->c0) {
1539 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001540 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001541 }
1542 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1543 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001544 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001545 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001546 break;
1547 case 8: /* this is not like 08.58, but in fact
1548 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1549 /* FIXME: only one CBCH allowed per cell */
1550 break;
1551 }
Harald Welted6575f92009-12-02 02:45:23 +05301552 break;
1553 case GSM_BTS_TYPE_NANOBTS:
1554 switch (ts->nr) {
1555 case 0:
1556 if (ts->trx->nr == 0) {
1557 /* only on TRX0 */
1558 switch (chan_comb) {
1559 case NM_CHANC_BCCH:
1560 case NM_CHANC_mainBCCH:
1561 case NM_CHANC_BCCHComb:
1562 return 0;
1563 break;
1564 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001565 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301566 return -EINVAL;
1567 }
1568 } else {
1569 switch (chan_comb) {
1570 case NM_CHANC_TCHFull:
1571 case NM_CHANC_TCHHalf:
1572 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1573 return 0;
1574 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001575 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301576 return -EINVAL;
1577 }
1578 }
1579 break;
1580 case 1:
1581 if (ts->trx->nr == 0) {
1582 switch (chan_comb) {
1583 case NM_CHANC_SDCCH_CBCH:
1584 if (ts->trx->ts[0].nm_chan_comb ==
1585 NM_CHANC_mainBCCH)
1586 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001587 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301588 return -EINVAL;
1589 case NM_CHANC_SDCCH:
1590 case NM_CHANC_TCHFull:
1591 case NM_CHANC_TCHHalf:
1592 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1593 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001594 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301595 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001596 default:
1597 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1598 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301599 }
1600 } else {
1601 switch (chan_comb) {
1602 case NM_CHANC_SDCCH:
1603 case NM_CHANC_TCHFull:
1604 case NM_CHANC_TCHHalf:
1605 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1606 return 0;
1607 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001608 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301609 return -EINVAL;
1610 }
1611 }
1612 break;
1613 case 2:
1614 case 3:
1615 case 4:
1616 case 5:
1617 case 6:
1618 case 7:
1619 switch (chan_comb) {
1620 case NM_CHANC_TCHFull:
1621 case NM_CHANC_TCHHalf:
1622 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1623 return 0;
1624 case NM_CHANC_IPAC_PDCH:
1625 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001626 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301627 if (ts->trx->nr == 0)
1628 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001629 else {
1630 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301631 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001632 }
Harald Welted6575f92009-12-02 02:45:23 +05301633 }
1634 break;
1635 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001636 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301637 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001638 case GSM_BTS_TYPE_OSMO_SYSMO:
1639 /* no known restrictions */
1640 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301641 default:
1642 /* unknown BTS type */
1643 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001644 }
1645 return 0;
1646}
1647
Harald Welte22af0db2009-02-14 15:41:08 +00001648/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001649int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001650{
1651 struct gsm_bts *bts = ts->trx->bts;
1652 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001653 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001654 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001655 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001656 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001657
1658 if (bts->type == GSM_BTS_TYPE_BS11)
1659 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001660
Harald Weltef325eb42009-02-19 17:07:39 +00001661 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001662 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001663 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001664 LOGP(DNM, LOGL_ERROR,
1665 "Invalid Channel Combination %d on %s. Reason: %s\n",
1666 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001667 return -EINVAL;
1668 }
1669 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001670
Harald Welte52b1f982008-12-23 20:25:15 +00001671 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001672 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001673 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001674 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001675 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001676 if (ts->hopping.enabled) {
1677 unsigned int i;
1678 uint8_t *len;
1679
Harald Welte6e0cd042009-09-12 13:05:33 +02001680 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1681 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001682
1683 /* build the ARFCN list */
1684 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1685 len = msgb_put(msg, 1);
1686 *len = 0;
1687 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1688 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1689 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001690 /* At least BS-11 wants a TLV16 here */
1691 if (bts->type == GSM_BTS_TYPE_BS11)
1692 *len += 1;
1693 else
1694 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001695 }
1696 }
Harald Weltee0590df2009-02-15 03:34:15 +00001697 }
Harald Welte1fe24122014-01-19 17:18:21 +01001698 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001699 if (bts->type == GSM_BTS_TYPE_BS11)
1700 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001701
1702 return abis_nm_sendmsg(bts, msg);
1703}
1704
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001705int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1706 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001707{
1708 struct abis_om_hdr *oh;
1709 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001710 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1711 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001712
1713 if (nack) {
1714 len += 2;
1715 msgtype = NM_MT_SW_ACT_REQ_NACK;
1716 }
Harald Welte34a99682009-02-13 02:41:40 +00001717
1718 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001719 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1720
Harald Welte34a99682009-02-13 02:41:40 +00001721 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001722 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001723 memcpy(ptr, attr, att_len);
1724 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001725 if (nack)
1726 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001727
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001728 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001729}
1730
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001731int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001732{
Harald Welte8470bf22008-12-25 23:28:35 +00001733 struct msgb *msg = nm_msgb_alloc();
1734 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001735 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001736
1737 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1738 fill_om_hdr(oh, len);
1739 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001740 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001741
1742 return abis_nm_sendmsg(bts, msg);
1743}
1744
1745/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001746static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001747{
1748 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001749 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001750
1751 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001752 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001753 0xff, 0xff, 0xff);
1754
1755 return abis_nm_sendmsg(bts, msg);
1756}
1757
Harald Welte34a99682009-02-13 02:41:40 +00001758/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001759int 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 +00001760{
1761 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001762 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001763 struct msgb *msg = nm_msgb_alloc();
1764
1765 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001766 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001767
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001768 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001769 DEBUGPC(DNM, "Sending OPSTART\n");
1770
Harald Welte34a99682009-02-13 02:41:40 +00001771 return abis_nm_sendmsg(bts, msg);
1772}
1773
1774/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001775int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1776 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001777{
1778 struct abis_om_hdr *oh;
1779 struct msgb *msg = nm_msgb_alloc();
1780
1781 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1782 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1783 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1784
1785 return abis_nm_sendmsg(bts, msg);
1786}
1787
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001788int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1789 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001790{
1791 struct abis_om_hdr *oh;
1792 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001793 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001794
1795 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1796 e1_port0, ts0, e1_port1, ts1);
1797
1798 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1799 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1800 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1801
1802 attr = msgb_put(msg, 3);
1803 attr[0] = NM_ATT_MDROP_LINK;
1804 attr[1] = e1_port0;
1805 attr[2] = ts0;
1806
1807 attr = msgb_put(msg, 3);
1808 attr[0] = NM_ATT_MDROP_NEXT;
1809 attr[1] = e1_port1;
1810 attr[2] = ts1;
1811
1812 return abis_nm_sendmsg(bts, msg);
1813}
Harald Welte34a99682009-02-13 02:41:40 +00001814
Harald Weltec7310382009-08-08 00:02:36 +02001815/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001816int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1817 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1818 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001819{
1820 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001821
Harald Welte15c61722011-05-22 22:45:37 +02001822 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001823
1824 if (!msg)
1825 msg = nm_msgb_alloc();
1826
1827 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1828 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1829 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1830 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001831 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001832
1833 return abis_nm_sendmsg(bts, msg);
1834}
1835
Harald Welte52b1f982008-12-23 20:25:15 +00001836int abis_nm_event_reports(struct gsm_bts *bts, int on)
1837{
1838 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001839 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001840 else
Harald Welte227d4072009-01-03 08:16:25 +00001841 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001842}
1843
Harald Welte47d88ae2009-01-04 12:02:08 +00001844/* Siemens (or BS-11) specific commands */
1845
Harald Welte3ffd1372009-02-01 22:15:49 +00001846int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1847{
1848 if (reconnect == 0)
1849 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1850 else
1851 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1852}
1853
Harald Welteb8427972009-02-05 19:27:17 +00001854int abis_nm_bs11_restart(struct gsm_bts *bts)
1855{
1856 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1857}
1858
1859
Harald Welte268bb402009-02-01 19:11:56 +00001860struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001861 uint16_t year;
1862 uint8_t month;
1863 uint8_t day;
1864 uint8_t hour;
1865 uint8_t min;
1866 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001867} __attribute__((packed));
1868
1869
1870void get_bs11_date_time(struct bs11_date_time *aet)
1871{
1872 time_t t;
1873 struct tm *tm;
1874
1875 t = time(NULL);
1876 tm = localtime(&t);
1877 aet->sec = tm->tm_sec;
1878 aet->min = tm->tm_min;
1879 aet->hour = tm->tm_hour;
1880 aet->day = tm->tm_mday;
1881 aet->month = tm->tm_mon;
1882 aet->year = htons(1900 + tm->tm_year);
1883}
1884
Harald Welte05188ee2009-01-18 11:39:08 +00001885int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001886{
Harald Welte4668fda2009-01-03 08:19:29 +00001887 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001888}
1889
Harald Welte05188ee2009-01-18 11:39:08 +00001890int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001891{
1892 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001893 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001894 else
Harald Welte4668fda2009-01-03 08:19:29 +00001895 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001896}
Harald Welte47d88ae2009-01-04 12:02:08 +00001897
Harald Welte05188ee2009-01-18 11:39:08 +00001898int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001899 enum abis_bs11_objtype type, uint8_t idx,
1900 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001901{
1902 struct abis_om_hdr *oh;
1903 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001904 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001905
1906 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001907 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001908 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001909 cur = msgb_put(msg, attr_len);
1910 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001911
1912 return abis_nm_sendmsg(bts, msg);
1913}
1914
Harald Welte78fc0d42009-02-19 02:50:57 +00001915int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001916 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001917{
1918 struct abis_om_hdr *oh;
1919 struct msgb *msg = nm_msgb_alloc();
1920
1921 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1922 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1923 NM_OC_BS11, type, 0, idx);
1924
1925 return abis_nm_sendmsg(bts, msg);
1926}
1927
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001928int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001929{
1930 struct abis_om_hdr *oh;
1931 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001932 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001933
1934 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001935 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001936 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1937 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001938
1939 return abis_nm_sendmsg(bts, msg);
1940}
1941
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001942int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001943{
1944 struct abis_om_hdr *oh;
1945 struct msgb *msg = nm_msgb_alloc();
1946
1947 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1948 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001949 idx, 0xff, 0xff);
1950
1951 return abis_nm_sendmsg(bts, msg);
1952}
1953
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001954int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001955{
1956 struct abis_om_hdr *oh;
1957 struct msgb *msg = nm_msgb_alloc();
1958
1959 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1960 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1961 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001962
1963 return abis_nm_sendmsg(bts, msg);
1964}
Harald Welte05188ee2009-01-18 11:39:08 +00001965
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001966static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001967int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1968{
1969 struct abis_om_hdr *oh;
1970 struct msgb *msg = nm_msgb_alloc();
1971
1972 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1973 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1974 0xff, 0xff, 0xff);
1975 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1976
1977 return abis_nm_sendmsg(bts, msg);
1978}
1979
Harald Welteb6c92ae2009-02-21 20:15:32 +00001980/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001981int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1982 uint8_t e1_timeslot, uint8_t e1_subslot,
1983 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001984{
1985 struct abis_om_hdr *oh;
1986 struct abis_nm_channel *ch;
1987 struct msgb *msg = nm_msgb_alloc();
1988
1989 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001990 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001991 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1992
1993 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1994 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001995 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001996
1997 return abis_nm_sendmsg(bts, msg);
1998}
1999
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002000int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002001{
2002 struct abis_om_hdr *oh;
2003 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002004
2005 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002006 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002007 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2008 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2009
2010 return abis_nm_sendmsg(trx->bts, msg);
2011}
2012
Harald Welte78fc0d42009-02-19 02:50:57 +00002013int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2014{
2015 struct abis_om_hdr *oh;
2016 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002017 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002018
2019 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2020 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2021 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2022 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2023
2024 return abis_nm_sendmsg(trx->bts, msg);
2025}
2026
Harald Welteaaf02d92009-04-29 13:25:57 +00002027int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2028{
2029 struct abis_om_hdr *oh;
2030 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002031 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002032
2033 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2034 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2035 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002036 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002037
2038 return abis_nm_sendmsg(bts, msg);
2039}
2040
Harald Welteef061952009-05-17 12:43:42 +00002041int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2042{
2043 struct abis_om_hdr *oh;
2044 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002045 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002046 NM_ATT_BS11_CCLK_TYPE };
2047
2048 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2049 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2050 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2051 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2052
2053 return abis_nm_sendmsg(bts, msg);
2054
2055}
Harald Welteaaf02d92009-04-29 13:25:57 +00002056
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002057//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002058
Harald Welte1bc09062009-01-18 14:17:52 +00002059int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002060{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002061 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2062}
2063
Daniel Willmann4b054c82010-01-07 00:46:26 +01002064int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2065{
2066 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2067}
2068
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002069int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002070{
Harald Welte05188ee2009-01-18 11:39:08 +00002071 struct abis_om_hdr *oh;
2072 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002073 struct bs11_date_time bdt;
2074
2075 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002076
2077 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002078 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002079 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002080 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002081 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002082 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002083 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002084 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002085 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002086 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002087 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002088 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002089 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002090 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002091 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002092 }
Harald Welte05188ee2009-01-18 11:39:08 +00002093
2094 return abis_nm_sendmsg(bts, msg);
2095}
Harald Welte1bc09062009-01-18 14:17:52 +00002096
2097int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2098{
2099 struct abis_om_hdr *oh;
2100 struct msgb *msg;
2101
2102 if (strlen(password) != 10)
2103 return -EINVAL;
2104
2105 msg = nm_msgb_alloc();
2106 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002107 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002108 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002109 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002110
2111 return abis_nm_sendmsg(bts, msg);
2112}
2113
Harald Weltee69f5fb2009-04-28 16:31:38 +00002114/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2115int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2116{
2117 struct abis_om_hdr *oh;
2118 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002119 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002120
2121 msg = nm_msgb_alloc();
2122 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2123 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2124 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002125
2126 if (locked)
2127 tlv_value = BS11_LI_PLL_LOCKED;
2128 else
2129 tlv_value = BS11_LI_PLL_STANDALONE;
2130
2131 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002132
2133 return abis_nm_sendmsg(bts, msg);
2134}
2135
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002136/* Set the calibration value of the PLL (work value/set value)
2137 * It depends on the login which one is changed */
2138int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2139{
2140 struct abis_om_hdr *oh;
2141 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002142 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002143
2144 msg = nm_msgb_alloc();
2145 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2146 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2147 BS11_OBJ_TRX1, 0x00, 0x00);
2148
2149 tlv_value[0] = value>>8;
2150 tlv_value[1] = value&0xff;
2151
2152 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2153
2154 return abis_nm_sendmsg(bts, msg);
2155}
2156
Harald Welte1bc09062009-01-18 14:17:52 +00002157int abis_nm_bs11_get_state(struct gsm_bts *bts)
2158{
2159 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2160}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002161
2162/* BS11 SWL */
2163
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002164void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002165
Harald Welte5e4d1b32009-02-01 13:36:56 +00002166struct abis_nm_bs11_sw {
2167 struct gsm_bts *bts;
2168 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002169 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002170 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002171 struct llist_head file_list;
2172 gsm_cbfn *user_cb; /* specified by the user */
2173};
2174static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2175
2176struct file_list_entry {
2177 struct llist_head list;
2178 char fname[PATH_MAX];
2179};
2180
2181struct file_list_entry *fl_dequeue(struct llist_head *queue)
2182{
2183 struct llist_head *lh;
2184
2185 if (llist_empty(queue))
2186 return NULL;
2187
2188 lh = queue->next;
2189 llist_del(lh);
2190
2191 return llist_entry(lh, struct file_list_entry, list);
2192}
2193
2194static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2195{
2196 char linebuf[255];
2197 struct llist_head *lh, *lh2;
2198 FILE *swl;
2199 int rc = 0;
2200
2201 swl = fopen(bs11_sw->swl_fname, "r");
2202 if (!swl)
2203 return -ENODEV;
2204
2205 /* zero the stale file list, if any */
2206 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2207 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002208 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002209 }
2210
2211 while (fgets(linebuf, sizeof(linebuf), swl)) {
2212 char file_id[12+1];
2213 char file_version[80+1];
2214 struct file_list_entry *fle;
2215 static char dir[PATH_MAX];
2216
2217 if (strlen(linebuf) < 4)
2218 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002219
Harald Welte5e4d1b32009-02-01 13:36:56 +00002220 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2221 if (rc < 0) {
2222 perror("ERR parsing SWL file");
2223 rc = -EINVAL;
2224 goto out;
2225 }
2226 if (rc < 2)
2227 continue;
2228
Harald Welte470ec292009-06-26 20:25:23 +02002229 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002230 if (!fle) {
2231 rc = -ENOMEM;
2232 goto out;
2233 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002234
2235 /* construct new filename */
2236 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welteb0993e62016-11-25 23:54:18 +01002237 dir[sizeof(dir)-1] = '\0';
Harald Welte5e4d1b32009-02-01 13:36:56 +00002238 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2239 strcat(fle->fname, "/");
2240 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002241
2242 llist_add_tail(&fle->list, &bs11_sw->file_list);
2243 }
2244
2245out:
2246 fclose(swl);
2247 return rc;
2248}
2249
2250/* bs11 swload specific callback, passed to abis_nm core swload */
2251static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2252 struct msgb *msg, void *data, void *param)
2253{
2254 struct abis_nm_bs11_sw *bs11_sw = data;
2255 struct file_list_entry *fle;
2256 int rc = 0;
2257
Harald Welte5e4d1b32009-02-01 13:36:56 +00002258 switch (event) {
2259 case NM_MT_LOAD_END_ACK:
2260 fle = fl_dequeue(&bs11_sw->file_list);
2261 if (fle) {
2262 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002263 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002264 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002265 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002266 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002267 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002268 } else {
2269 /* activate the SWL */
2270 rc = abis_nm_software_activate(bs11_sw->bts,
2271 bs11_sw->swl_fname,
2272 bs11_swload_cbfn,
2273 bs11_sw);
2274 }
2275 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002276 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002277 case NM_MT_LOAD_END_NACK:
2278 case NM_MT_LOAD_INIT_ACK:
2279 case NM_MT_LOAD_INIT_NACK:
2280 case NM_MT_ACTIVATE_SW_NACK:
2281 case NM_MT_ACTIVATE_SW_ACK:
2282 default:
2283 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002284 if (bs11_sw->user_cb)
2285 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002286 break;
2287 }
2288
2289 return rc;
2290}
2291
2292/* Siemens provides a SWL file that is a mere listing of all the other
2293 * files that are part of a software release. We need to upload first
2294 * the list file, and then each file that is listed in the list file */
2295int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002296 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002297{
2298 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2299 struct file_list_entry *fle;
2300 int rc = 0;
2301
2302 INIT_LLIST_HEAD(&bs11_sw->file_list);
2303 bs11_sw->bts = bts;
2304 bs11_sw->win_size = win_size;
2305 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002306 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002307
2308 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte7b6bae62016-11-25 23:52:46 +01002309 bs11_sw->swl_fname[sizeof(bs11_sw->swl_fname)-1] = '\0';
Harald Welte5e4d1b32009-02-01 13:36:56 +00002310 rc = bs11_read_swl_file(bs11_sw);
2311 if (rc < 0)
2312 return rc;
2313
2314 /* dequeue next item in file list */
2315 fle = fl_dequeue(&bs11_sw->file_list);
2316 if (!fle)
2317 return -EINVAL;
2318
2319 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002320 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002321 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002322 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002323 return rc;
2324}
2325
Harald Welte5083b0b2009-02-02 19:20:52 +00002326#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002327static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002328 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2329 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2330 NM_ATT_BS11_LMT_USER_NAME,
2331
2332 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2333
2334 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2335
2336 NM_ATT_BS11_SW_LOAD_STORED };
2337
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002338static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002339 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2340 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2341 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2342 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002343#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002344
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002345static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002346 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2347 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002348 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002349
2350int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2351{
2352 struct abis_om_hdr *oh;
2353 struct msgb *msg = nm_msgb_alloc();
2354
2355 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2356 /* SiemensHW CCTRL object */
2357 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2358 0x03, 0x00, 0x00);
2359 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2360
2361 return abis_nm_sendmsg(bts, msg);
2362}
Harald Welte268bb402009-02-01 19:11:56 +00002363
2364int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2365{
2366 struct abis_om_hdr *oh;
2367 struct msgb *msg = nm_msgb_alloc();
2368 struct bs11_date_time aet;
2369
2370 get_bs11_date_time(&aet);
2371 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2372 /* SiemensHW CCTRL object */
2373 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2374 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002375 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002376
2377 return abis_nm_sendmsg(bts, msg);
2378}
Harald Welte5c1e4582009-02-15 11:57:29 +00002379
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002380int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002381{
2382 struct abis_om_hdr *oh;
2383 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002384 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002385
2386 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2387 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2388 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2389 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2390
2391 return abis_nm_sendmsg(bts, msg);
2392}
2393
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002394int 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 +02002395{
2396 struct abis_om_hdr *oh;
2397 struct msgb *msg = nm_msgb_alloc();
2398 struct bs11_date_time aet;
2399
2400 get_bs11_date_time(&aet);
2401 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2402 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2403 bport, 0xff, 0x02);
2404 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2405
2406 return abis_nm_sendmsg(bts, msg);
2407}
2408
Harald Welte5c1e4582009-02-15 11:57:29 +00002409/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002410static const char ipaccess_magic[] = "com.ipaccess";
2411
Harald Welte677c21f2009-02-17 13:22:23 +00002412
2413static int abis_nm_rx_ipacc(struct msgb *msg)
2414{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002415 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002416 struct abis_om_hdr *oh = msgb_l2(msg);
2417 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002418 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002419 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002420 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002421 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002422
2423 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002424 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002425 return -EINVAL;
2426 }
2427
Harald Welte193fefc2009-04-30 15:16:27 +00002428 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002429 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002430
Harald Welte15c61722011-05-22 22:45:37 +02002431 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002432
Harald Welte746d6092009-10-19 22:11:11 +02002433 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002434
Harald Welte677c21f2009-02-17 13:22:23 +00002435 switch (foh->msg_type) {
2436 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002437 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002438 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2439 memcpy(&addr,
2440 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2441
2442 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2443 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002444 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002445 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002446 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002447 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002448 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2449 DEBUGPC(DNM, "STREAM=0x%02x ",
2450 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002451 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002452 break;
2453 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002454 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002455 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002456 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002457 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002458 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002459 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002460 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002461 case NM_MT_IPACC_SET_NVATTR_ACK:
2462 DEBUGPC(DNM, "SET NVATTR ACK\n");
2463 /* FIXME: decode and show the actual attributes */
2464 break;
2465 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002466 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002467 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002468 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002469 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002470 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002471 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002472 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002473 case NM_MT_IPACC_GET_NVATTR_ACK:
2474 DEBUGPC(DNM, "GET NVATTR ACK\n");
2475 /* FIXME: decode and show the actual attributes */
2476 break;
2477 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002478 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002479 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002480 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002481 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002482 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002483 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002484 break;
Harald Welte15c44172009-10-08 20:15:24 +02002485 case NM_MT_IPACC_SET_ATTR_ACK:
2486 DEBUGPC(DNM, "SET ATTR ACK\n");
2487 break;
2488 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002489 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002490 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002491 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002492 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002493 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002494 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002495 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002496 default:
2497 DEBUGPC(DNM, "unknown\n");
2498 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002499 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002500
2501 /* signal handling */
2502 switch (foh->msg_type) {
2503 case NM_MT_IPACC_RSL_CONNECT_NACK:
2504 case NM_MT_IPACC_SET_NVATTR_NACK:
2505 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002506 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 +01002507 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002508 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002509 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002510 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002511 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 +01002512 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002513 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002514 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002515 default:
2516 break;
2517 }
2518
Harald Welte677c21f2009-02-17 13:22:23 +00002519 return 0;
2520}
2521
Harald Welte193fefc2009-04-30 15:16:27 +00002522/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002523int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2524 uint8_t obj_class, uint8_t bts_nr,
2525 uint8_t trx_nr, uint8_t ts_nr,
2526 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002527{
2528 struct msgb *msg = nm_msgb_alloc();
2529 struct abis_om_hdr *oh;
2530 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002531 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002532
2533 /* construct the 12.21 OM header, observe the erroneous length */
2534 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2535 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2536 oh->mdisc = ABIS_OM_MDISC_MANUF;
2537
2538 /* add the ip.access magic */
2539 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2540 *data++ = sizeof(ipaccess_magic);
2541 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2542
2543 /* fill the 12.21 FOM header */
2544 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2545 foh->msg_type = msg_type;
2546 foh->obj_class = obj_class;
2547 foh->obj_inst.bts_nr = bts_nr;
2548 foh->obj_inst.trx_nr = trx_nr;
2549 foh->obj_inst.ts_nr = ts_nr;
2550
2551 if (attr && attr_len) {
2552 data = msgb_put(msg, attr_len);
2553 memcpy(data, attr, attr_len);
2554 }
2555
2556 return abis_nm_sendmsg(bts, msg);
2557}
Harald Welte677c21f2009-02-17 13:22:23 +00002558
Harald Welte193fefc2009-04-30 15:16:27 +00002559/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002560int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002561 int attr_len)
2562{
Harald Welte2ef156d2010-01-07 20:39:42 +01002563 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2564 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002565 attr_len);
2566}
2567
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002568int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002569 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002570{
2571 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002572 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002573 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2574 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2575
2576 int attr_len = sizeof(attr);
2577
2578 ia.s_addr = htonl(ip);
2579 attr[1] = stream;
2580 attr[3] = port >> 8;
2581 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002582 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002583
2584 /* if ip == 0, we use the default IP */
2585 if (ip == 0)
2586 attr_len -= 5;
2587
2588 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002589 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002590
2591 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2592 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2593 trx->nr, 0xff, attr, attr_len);
2594}
2595
Harald Welte193fefc2009-04-30 15:16:27 +00002596/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002597int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002598{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002599 struct abis_om_hdr *oh;
2600 struct msgb *msg = nm_msgb_alloc();
2601
2602 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2603 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2604 trx->bts->nr, trx->nr, 0xff);
2605
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002606 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002607}
Harald Weltedaef5212009-10-24 10:20:41 +02002608
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002609int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2610 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2611 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002612{
2613 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2614 obj_class, bts_nr, trx_nr, ts_nr,
2615 attr, attr_len);
2616}
Harald Welte0f255852009-11-12 14:48:42 +01002617
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002618void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002619{
2620 /* we simply reuse the GSM48 function and overwrite the RAC
2621 * with the Cell ID */
2622 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002623 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002624}
2625
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002626void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2627{
2628 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2629
Harald Welted64c0bc2011-05-30 12:07:53 +02002630 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002631 if (!trx->bts || !trx->bts->oml_link)
2632 return;
2633
2634 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2635 trx->bts->bts_nr, trx->nr, 0xff,
2636 new_state);
2637}
2638
Harald Welte92b1fe42010-03-25 11:45:30 +08002639static const struct value_string ipacc_testres_names[] = {
2640 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2641 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2642 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2643 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2644 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2645 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002646};
2647
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002648const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002649{
Harald Welte92b1fe42010-03-25 11:45:30 +08002650 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002651}
2652
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002653void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002654{
2655 cid->mcc = (buf[0] & 0xf) * 100;
2656 cid->mcc += (buf[0] >> 4) * 10;
2657 cid->mcc += (buf[1] & 0xf) * 1;
2658
2659 if (buf[1] >> 4 == 0xf) {
2660 cid->mnc = (buf[2] & 0xf) * 10;
2661 cid->mnc += (buf[2] >> 4) * 1;
2662 } else {
2663 cid->mnc = (buf[2] & 0xf) * 100;
2664 cid->mnc += (buf[2] >> 4) * 10;
2665 cid->mnc += (buf[1] >> 4) * 1;
2666 }
2667
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002668 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2669 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002670}
2671
Harald Welte0f255852009-11-12 14:48:42 +01002672/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002673int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002674{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002675 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002676 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002677
Harald Welteaf109b92010-07-22 18:14:36 +02002678 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002679
2680 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2681 return -EINVAL;
2682 cur++;
2683
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002684 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002685 cur += 2;
2686
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002687 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002688 cur += 2;
2689
2690 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2691 binf->freq_qual = *cur >> 2;
2692
Harald Welteaf109b92010-07-22 18:14:36 +02002693 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002694 binf->arfcn |= *cur++;
2695
2696 if (binf->info_type & IPAC_BINF_RXLEV)
2697 binf->rx_lev = *cur & 0x3f;
2698 cur++;
2699
2700 if (binf->info_type & IPAC_BINF_RXQUAL)
2701 binf->rx_qual = *cur & 0x7;
2702 cur++;
2703
2704 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002705 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002706 cur += 2;
2707
2708 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002709 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002710 cur += 2;
2711
2712 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002713 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002714 cur += 4;
2715
Harald Weltea780a3d2010-07-30 22:34:42 +02002716#if 0
2717 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002718 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002719#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002720 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002721 cur++;
2722
Harald Welteb40a38f2009-11-13 11:56:05 +01002723 ipac_parse_cgi(&binf->cgi, cur);
2724 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002725
2726 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2727 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2728 cur += sizeof(binf->ba_list_si2);
2729 }
2730
2731 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2732 memcpy(binf->ba_list_si2bis, cur,
2733 sizeof(binf->ba_list_si2bis));
2734 cur += sizeof(binf->ba_list_si2bis);
2735 }
2736
2737 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2738 memcpy(binf->ba_list_si2ter, cur,
2739 sizeof(binf->ba_list_si2ter));
2740 cur += sizeof(binf->ba_list_si2ter);
2741 }
2742
2743 return 0;
2744}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002745
2746void abis_nm_clear_queue(struct gsm_bts *bts)
2747{
2748 struct msgb *msg;
2749
2750 while (!llist_empty(&bts->abis_queue)) {
2751 msg = msgb_dequeue(&bts->abis_queue);
2752 msgb_free(msg);
2753 }
2754
2755 bts->abis_nm_pend = 0;
2756}