blob: 5a968492d8dbb19d0da1093208b49bcb3d1f972c [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 Freytherc42ad8b2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 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;
109}
110
Harald Welte8470bf22008-12-25 23:28:35 +0000111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte966636f2009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000115}
116
Harald Welte15eae8d2011-09-26 23:43:23 +0200117int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200118{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200119 msg->l2h = msg->data;
120
121 if (!msg->dst) {
122 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
123 return -EINVAL;
124 }
125
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200126 return abis_sendmsg(msg);
127}
128
Harald Welte52b1f982008-12-23 20:25:15 +0000129/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100130static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000131{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200132 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000133
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100134 /* queue OML messages */
135 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
136 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200137 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100138 } else {
139 msgb_enqueue(&bts->abis_queue, msg);
140 return 0;
141 }
142
143}
144
145int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
146{
147 OBSC_NM_W_ACK_CB(msg) = 1;
148 return abis_nm_queue_msg(bts, msg);
149}
150
151static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
152{
153 OBSC_NM_W_ACK_CB(msg) = 0;
154 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000155}
156
Harald Welte4724f992009-01-18 18:01:49 +0000157static int abis_nm_rcvmsg_sw(struct msgb *mb);
158
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100159int nm_is_running(struct gsm_nm_state *s) {
160 return (s->operational == NM_OPSTATE_ENABLED) && (
161 (s->availability == NM_AVSTATE_OK) ||
162 (s->availability == 0xff)
163 );
164}
165
Harald Weltee0590df2009-02-15 03:34:15 +0000166/* Update the administrative state of a given object in our in-memory data
167 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200168static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
169 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000170{
Harald Welteaeedeb42009-05-01 13:08:14 +0000171 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100172 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000173
Harald Welteaf9b8102011-03-06 21:20:38 +0100174 memset(&nsd, 0, sizeof(nsd));
175
Harald Welte978714d2011-06-06 18:31:20 +0200176 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100177 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100178 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200179 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000180 if (!nm_state)
181 return -1;
182
183 new_state = *nm_state;
184 new_state.administrative = adm_state;
185
Harald Weltef38ca9a2011-03-06 22:11:32 +0100186 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100187 nsd.obj_class = obj_class;
188 nsd.old_state = nm_state;
189 nsd.new_state = &new_state;
190 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200191 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000192
193 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000194
Harald Weltef338a032011-01-14 15:55:42 +0100195 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000196}
197
Harald Welte97ed1e72009-02-06 13:38:02 +0000198static int abis_nm_rx_statechg_rep(struct msgb *mb)
199{
Harald Weltee0590df2009-02-15 03:34:15 +0000200 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000201 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200202 struct e1inp_sign_link *sign_link = mb->dst;
203 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000204 struct tlv_parsed tp;
205 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000206
Harald Welte23897662009-05-01 14:52:51 +0000207 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000208
Harald Welte8b697c72009-06-05 19:18:45 +0000209 memset(&new_state, 0, sizeof(new_state));
210
Harald Welte978714d2011-06-06 18:31:20 +0200211 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000212 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100213 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000214 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000215 }
Harald Weltee0590df2009-02-15 03:34:15 +0000216
217 new_state = *nm_state;
218
Harald Welte39315c42010-01-10 18:01:52 +0100219 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000220 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
221 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200222 DEBUGPC(DNM, "OP_STATE=%s ",
223 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000224 }
225 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000226 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
227 new_state.availability = 0xff;
228 else
229 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
231 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000232 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100233 } else
234 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000235 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
236 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200237 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200238 get_value_string(abis_nm_adm_state_names,
239 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000240 }
241 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000242
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100243 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
244 new_state.operational != nm_state->operational ||
245 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000246 /* Update the operational state of a given object in our in-memory data
247 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100248 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200249 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100250 nsd.obj_class = foh->obj_class;
251 nsd.old_state = nm_state;
252 nsd.new_state = &new_state;
253 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100254 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200255 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100256 nm_state->operational = new_state.operational;
257 nm_state->availability = new_state.availability;
258 if (nm_state->administrative == 0)
259 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000260 }
261#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000262 if (op_state == 1) {
263 /* try to enable objects that are disabled */
264 abis_nm_opstart(bts, foh->obj_class,
265 foh->obj_inst.bts_nr,
266 foh->obj_inst.trx_nr,
267 foh->obj_inst.ts_nr);
268 }
Harald Weltee0590df2009-02-15 03:34:15 +0000269#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000270 return 0;
271}
272
Harald Welte0db97b22009-05-01 17:22:47 +0000273static int rx_fail_evt_rep(struct msgb *mb)
274{
275 struct abis_om_hdr *oh = msgb_l2(mb);
276 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200277 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000278 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100279 const uint8_t *p_val;
280 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000281
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200282 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000283
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200284 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000285
286 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200287 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
288 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000289 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200290 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
291 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100292 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
293 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200294 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 +0100295 }
296 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
297 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
298 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
299 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200300 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100301 talloc_free(p_text);
302 }
303 }
Harald Welte0db97b22009-05-01 17:22:47 +0000304
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200305 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000306
307 return 0;
308}
309
Harald Welte97ed1e72009-02-06 13:38:02 +0000310static int abis_nm_rcvmsg_report(struct msgb *mb)
311{
312 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200313 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000314
Harald Welte15c61722011-05-22 22:45:37 +0200315 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000316
Harald Welte97ed1e72009-02-06 13:38:02 +0000317 //nmh->cfg->report_cb(mb, foh);
318
319 switch (mt) {
320 case NM_MT_STATECHG_EVENT_REP:
321 return abis_nm_rx_statechg_rep(mb);
322 break;
Harald Welte34a99682009-02-13 02:41:40 +0000323 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000324 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200325 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000326 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000327 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000328 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200329 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000330 break;
Harald Weltec7310382009-08-08 00:02:36 +0200331 case NM_MT_TEST_REP:
332 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200334 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000335 default:
Harald Welte23897662009-05-01 14:52:51 +0000336 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000337 break;
338
Harald Welte97ed1e72009-02-06 13:38:02 +0000339 };
340
Harald Welte97ed1e72009-02-06 13:38:02 +0000341 return 0;
342}
343
Harald Welte34a99682009-02-13 02:41:40 +0000344/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200345static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
346 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000347{
348 struct abis_om_hdr *oh;
349 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200350 uint8_t len = swdesc_len;
351 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000352
353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
354 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
355
356 trailer = msgb_put(msg, swdesc_len);
357 memcpy(trailer, sw_desc, swdesc_len);
358
359 return abis_nm_sendmsg(bts, msg);
360}
361
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100362int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
363 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100364{
365 static const struct tlv_definition sw_descr_def = {
366 .def = {
367 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
368 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
369 },
370 };
371
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100372 size_t pos = 0;
373 int desc_pos = 0;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100374
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100375 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
376 uint8_t tag;
377 uint16_t tag_len;
378 const uint8_t *val;
379 int len;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100380
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100381 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
382 desc[desc_pos].start = &sw_descr[pos];
383
384 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
385 * nested nature and the fact you have to assume it contains only two sub
386 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
387 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
388 LOGP(DNM, LOGL_ERROR,
389 "SW_DESCR attribute identifier not found!\n");
390 return -1;
391 }
392
393 pos += 1;
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
396 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
397 LOGP(DNM, LOGL_ERROR,
398 "FILE_ID attribute identifier not found!\n");
399 return -2;
400 }
401 desc[desc_pos].file_id = val;
402 desc[desc_pos].file_id_len = tag_len;
403 pos += len;
404
405
406 len = tlv_parse_one(&tag, &tag_len, &val,
407 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
408 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
409 LOGP(DNM, LOGL_ERROR,
410 "FILE_VERSION attribute identifier not found!\n");
411 return -3;
412 }
413 desc[desc_pos].file_ver = val;
414 desc[desc_pos].file_ver_len = tag_len;
415 pos += len;
416
417 /* final size */
418 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100419 }
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100420
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100421 return desc_pos;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100422}
423
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100424int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
425 const size_t size)
426{
427 int res = 0;
428 int i;
429
430 for (i = 1; i < size; ++i) {
431 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
432 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
433 res = i;
434 }
435 }
436
437 return res;
438}
439
Harald Welte34a99682009-02-13 02:41:40 +0000440static int abis_nm_rx_sw_act_req(struct msgb *mb)
441{
442 struct abis_om_hdr *oh = msgb_l2(mb);
443 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200444 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200445 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200446 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100447 int ret, sw_config_len, len;
448 struct abis_nm_sw_descr sw_descr[5];
Harald Welte34a99682009-02-13 02:41:40 +0000449
Harald Welte15c61722011-05-22 22:45:37 +0200450 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200451
452 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000453
Harald Welte97a282b2010-03-14 15:37:43 +0800454 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000455
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200456 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000457 foh->obj_inst.bts_nr,
458 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800459 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000460 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100461 if (ret != 0) {
462 LOGP(DNM, LOGL_ERROR,
463 "Sending SW ActReq ACK failed: %d\n", ret);
464 return ret;
465 }
Harald Welte34a99682009-02-13 02:41:40 +0000466
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200467 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200468 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
469 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
470 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100471 LOGP(DNM, LOGL_ERROR,
472 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200473 return -EINVAL;
474 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200475 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200476 }
477
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100478 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100479 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100480 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100481 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100482 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100483 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100484 }
Mike Habena03f9772009-10-01 14:56:13 +0200485
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100486 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
487 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
488
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200489 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000490 foh->obj_inst.bts_nr,
491 foh->obj_inst.trx_nr,
492 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100493 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte34a99682009-02-13 02:41:40 +0000494}
495
Harald Weltee0590df2009-02-15 03:34:15 +0000496/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
497static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
498{
499 struct abis_om_hdr *oh = msgb_l2(mb);
500 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200501 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000502 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200503 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000504
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200505 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000506 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
507 return -EINVAL;
508
509 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
510
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200511 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000512}
513
Harald Welteee670472009-02-22 21:58:49 +0000514static int abis_nm_rx_lmt_event(struct msgb *mb)
515{
516 struct abis_om_hdr *oh = msgb_l2(mb);
517 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200518 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000519 struct tlv_parsed tp;
520
521 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200522 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000523 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
524 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200525 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000526 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
527 }
528 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
529 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200530 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000531 DEBUGPC(DNM, "Level=%u ", level);
532 }
533 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
534 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
535 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
536 DEBUGPC(DNM, "Username=%s ", name);
537 }
538 DEBUGPC(DNM, "\n");
539 /* FIXME: parse LMT LOGON TIME */
540 return 0;
541}
542
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200543void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100544{
545 int wait = 0;
546 struct msgb *msg;
547 /* the queue is empty */
548 while (!llist_empty(&bts->abis_queue)) {
549 msg = msgb_dequeue(&bts->abis_queue);
550 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200551 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100552
553 if (wait)
554 break;
555 }
556
557 bts->abis_nm_pend = wait;
558}
559
Harald Welte52b1f982008-12-23 20:25:15 +0000560/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000561static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000562{
Harald Welte6c96ba52009-05-01 13:03:40 +0000563 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000564 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200565 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200566 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100567 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000568
569 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000570 if (is_report(mt))
571 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000572
Harald Welte15c61722011-05-22 22:45:37 +0200573 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000574 return abis_nm_rcvmsg_sw(mb);
575
Harald Welte15c61722011-05-22 22:45:37 +0200576 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800577 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000578 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200579
Harald Welte15c61722011-05-22 22:45:37 +0200580 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200581
Harald Welte15c61722011-05-22 22:45:37 +0200582 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000583
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200584 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000585 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200586 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200587 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000588 else
589 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200590
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800591 nack_data.msg = mb;
592 nack_data.mt = mt;
Holger Hans Peter Freytherde1674a2012-11-11 18:26:23 +0100593 nack_data.bts = sign_link->trx->bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200594 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200595 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200596 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000597 }
Harald Weltead384642008-12-26 10:20:07 +0000598#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000599 /* check if last message is to be acked */
600 if (is_ack_nack(nmh->last_msgtype)) {
601 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100602 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000603 /* we got our ACK, continue sending the next msg */
604 } else if (mt == MT_NACK(nmh->last_msgtype)) {
605 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100606 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000607 /* FIXME: somehow signal this to the caller */
608 } else {
609 /* really strange things happen */
610 return -EINVAL;
611 }
612 }
Harald Weltead384642008-12-26 10:20:07 +0000613#endif
614
Harald Welte97ed1e72009-02-06 13:38:02 +0000615 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000616 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100617 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000618 break;
Harald Welte34a99682009-02-13 02:41:40 +0000619 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100620 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000621 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000622 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100623 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000624 break;
Harald Welte1989c082009-08-06 17:58:31 +0200625 case NM_MT_CONN_MDROP_LINK_ACK:
626 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
627 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100628 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200629 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100630 break;
631 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200632 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100633 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100634 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100635 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000636 }
637
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200638 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100639 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000640}
641
Harald Welte677c21f2009-02-17 13:22:23 +0000642static int abis_nm_rx_ipacc(struct msgb *mb);
643
644static int abis_nm_rcvmsg_manuf(struct msgb *mb)
645{
646 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200647 struct e1inp_sign_link *sign_link = mb->dst;
648 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000649
650 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100651 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200652 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000653 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200654 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000655 break;
656 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100657 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
658 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000659 rc = 0;
660 break;
661 }
662
663 return rc;
664}
665
Harald Welte52b1f982008-12-23 20:25:15 +0000666/* High-Level API */
667/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000668int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000669{
Harald Welte52b1f982008-12-23 20:25:15 +0000670 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000671 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000672
673 /* Various consistency checks */
674 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100675 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000676 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200677 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
678 rc = -EINVAL;
679 goto err;
680 }
Harald Welte52b1f982008-12-23 20:25:15 +0000681 }
682 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100683 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000684 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200685 rc = -EINVAL;
686 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000687 }
Harald Welte702d8702008-12-26 20:25:35 +0000688#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200689 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000690 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000691 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100692 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000693 oh->length + sizeof(*oh), l2_len);
694 return -EINVAL;
695 }
Harald Welte702d8702008-12-26 20:25:35 +0000696 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100697 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 +0000698#endif
Harald Weltead384642008-12-26 10:20:07 +0000699 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000700
701 switch (oh->mdisc) {
702 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000703 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000704 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000705 case ABIS_OM_MDISC_MANUF:
706 rc = abis_nm_rcvmsg_manuf(msg);
707 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000708 case ABIS_OM_MDISC_MMI:
709 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100710 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000711 oh->mdisc);
712 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000713 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100714 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000715 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200716 rc = -EINVAL;
717 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000718 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200719err:
Harald Weltead384642008-12-26 10:20:07 +0000720 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000721 return rc;
722}
723
724#if 0
725/* initialized all resources */
726struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
727{
728 struct abis_nm_h *nmh;
729
730 nmh = malloc(sizeof(*nmh));
731 if (!nmh)
732 return NULL;
733
734 nmh->cfg = cfg;
735
736 return nmh;
737}
738
739/* free all resources */
740void abis_nm_fini(struct abis_nm_h *nmh)
741{
742 free(nmh);
743}
744#endif
745
746/* Here we are trying to define a high-level API that can be used by
747 * the actual BSC implementation. However, the architecture is currently
748 * still under design. Ideally the calls to this API would be synchronous,
749 * while the underlying stack behind the APi runs in a traditional select
750 * based state machine.
751 */
752
Harald Welte4724f992009-01-18 18:01:49 +0000753/* 6.2 Software Load: */
754enum sw_state {
755 SW_STATE_NONE,
756 SW_STATE_WAIT_INITACK,
757 SW_STATE_WAIT_SEGACK,
758 SW_STATE_WAIT_ENDACK,
759 SW_STATE_WAIT_ACTACK,
760 SW_STATE_ERROR,
761};
Harald Welte52b1f982008-12-23 20:25:15 +0000762
Harald Welte52b1f982008-12-23 20:25:15 +0000763struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000764 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800765 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000766 gsm_cbfn *cbfn;
767 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000768 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000769
Harald Welte52b1f982008-12-23 20:25:15 +0000770 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200771 uint8_t obj_class;
772 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000773
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200774 uint8_t file_id[255];
775 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000776
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200777 uint8_t file_version[255];
778 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000779
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200780 uint8_t window_size;
781 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000782
783 int fd;
784 FILE *stream;
785 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000786 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000787};
788
Harald Welte4724f992009-01-18 18:01:49 +0000789static struct abis_nm_sw g_sw;
790
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100791static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
792{
793 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
794 msgb_v_put(msg, NM_ATT_SW_DESCR);
795 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
796 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
797 sw->file_version);
798 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
799 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
800 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
801 sw->file_version);
802 } else {
803 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
804 }
805}
806
Harald Welte4724f992009-01-18 18:01:49 +0000807/* 6.2.1 / 8.3.1: Load Data Initiate */
808static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000809{
Harald Welte4724f992009-01-18 18:01:49 +0000810 struct abis_om_hdr *oh;
811 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200812 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000813
814 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
815 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
816 sw->obj_instance[0], sw->obj_instance[1],
817 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100818
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100819 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000820 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
821
822 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000823}
824
Harald Welte1602ade2009-01-29 21:12:39 +0000825static int is_last_line(FILE *stream)
826{
827 char next_seg_buf[256];
828 long pos;
829
830 /* check if we're sending the last line */
831 pos = ftell(stream);
832 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
833 fseek(stream, pos, SEEK_SET);
834 return 1;
835 }
836
837 fseek(stream, pos, SEEK_SET);
838 return 0;
839}
840
Harald Welte4724f992009-01-18 18:01:49 +0000841/* 6.2.2 / 8.3.2 Load Data Segment */
842static int sw_load_segment(struct abis_nm_sw *sw)
843{
844 struct abis_om_hdr *oh;
845 struct msgb *msg = nm_msgb_alloc();
846 char seg_buf[256];
847 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000848 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200849 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000850
851 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000852
853 switch (sw->bts->type) {
854 case GSM_BTS_TYPE_BS11:
855 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
856 perror("fgets reading segment");
857 return -EINVAL;
858 }
859 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000860
861 /* check if we're sending the last line */
862 sw->last_seg = is_last_line(sw->stream);
863 if (sw->last_seg)
864 seg_buf[1] = 0;
865 else
866 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000867
868 len = strlen(line_buf) + 2;
869 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200870 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000871 /* BS11 wants CR + LF in excess of the TLV length !?! */
872 tlv[1] -= 2;
873
874 /* we only now know the exact length for the OM hdr */
875 len = strlen(line_buf)+2;
876 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100877 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200878 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100879 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
880 if (len < 0) {
881 perror("read failed");
882 return -EINVAL;
883 }
884
885 if (len != IPACC_SEGMENT_SIZE)
886 sw->last_seg = 1;
887
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100888 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200889 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100890 len += 3;
891 break;
892 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000893 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100894 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000895 /* FIXME: Other BTS types */
896 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000897 }
Harald Welte4724f992009-01-18 18:01:49 +0000898
Harald Welte4724f992009-01-18 18:01:49 +0000899 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
900 sw->obj_instance[0], sw->obj_instance[1],
901 sw->obj_instance[2]);
902
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100903 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000904}
905
906/* 6.2.4 / 8.3.4 Load Data End */
907static int sw_load_end(struct abis_nm_sw *sw)
908{
909 struct abis_om_hdr *oh;
910 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200911 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000912
913 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
914 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
915 sw->obj_instance[0], sw->obj_instance[1],
916 sw->obj_instance[2]);
917
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100918 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000919 return abis_nm_sendmsg(sw->bts, msg);
920}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000921
Harald Welte52b1f982008-12-23 20:25:15 +0000922/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000923static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000924{
Harald Welte4724f992009-01-18 18:01:49 +0000925 struct abis_om_hdr *oh;
926 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200927 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000928
Harald Welte4724f992009-01-18 18:01:49 +0000929 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
930 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
931 sw->obj_instance[0], sw->obj_instance[1],
932 sw->obj_instance[2]);
933
934 /* FIXME: this is BS11 specific format */
935 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
936 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
937 sw->file_version);
938
939 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000940}
Harald Welte4724f992009-01-18 18:01:49 +0000941
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100942struct sdp_firmware {
943 char magic[4];
944 char more_magic[4];
945 unsigned int header_length;
946 unsigned int file_length;
947} __attribute__ ((packed));
948
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100949static int parse_sdp_header(struct abis_nm_sw *sw)
950{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100951 struct sdp_firmware firmware_header;
952 int rc;
953 struct stat stat;
954
955 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
956 if (rc != sizeof(firmware_header)) {
957 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
958 return -1;
959 }
960
961 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
962 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
963 return -1;
964 }
965
966 if (firmware_header.more_magic[0] != 0x10 ||
967 firmware_header.more_magic[1] != 0x02 ||
968 firmware_header.more_magic[2] != 0x00 ||
969 firmware_header.more_magic[3] != 0x00) {
970 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
971 return -1;
972 }
973
974
975 if (fstat(sw->fd, &stat) == -1) {
976 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
977 return -1;
978 }
979
980 if (ntohl(firmware_header.file_length) != stat.st_size) {
981 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
982 return -1;
983 }
984
985 /* go back to the start as we checked the whole filesize.. */
986 lseek(sw->fd, 0l, SEEK_SET);
987 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
988 "There might be checksums in the file that are not\n"
989 "verified and incomplete firmware might be flashed.\n"
990 "There is absolutely no WARRANTY that flashing will\n"
991 "work.\n");
992 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100993}
994
Harald Welte4724f992009-01-18 18:01:49 +0000995static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
996{
997 char file_id[12+1];
998 char file_version[80+1];
999 int rc;
1000
1001 sw->fd = open(fname, O_RDONLY);
1002 if (sw->fd < 0)
1003 return sw->fd;
1004
1005 switch (sw->bts->type) {
1006 case GSM_BTS_TYPE_BS11:
1007 sw->stream = fdopen(sw->fd, "r");
1008 if (!sw->stream) {
1009 perror("fdopen");
1010 return -1;
1011 }
1012 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001013 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001014 file_id, file_version);
1015 if (rc != 2) {
1016 perror("parsing header line of software file");
1017 return -1;
1018 }
1019 strcpy((char *)sw->file_id, file_id);
1020 sw->file_id_len = strlen(file_id);
1021 strcpy((char *)sw->file_version, file_version);
1022 sw->file_version_len = strlen(file_version);
1023 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001024 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001025 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001026 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001027 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001028 rc = parse_sdp_header(sw);
1029 if (rc < 0) {
1030 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1031 return -1;
1032 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001033
1034 strcpy((char *)sw->file_id, "id");
1035 sw->file_id_len = 3;
1036 strcpy((char *)sw->file_version, "version");
1037 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001038 break;
Harald Welte4724f992009-01-18 18:01:49 +00001039 default:
1040 /* We don't know how to treat them yet */
1041 close(sw->fd);
1042 return -EINVAL;
1043 }
1044
1045 return 0;
1046}
1047
1048static void sw_close_file(struct abis_nm_sw *sw)
1049{
1050 switch (sw->bts->type) {
1051 case GSM_BTS_TYPE_BS11:
1052 fclose(sw->stream);
1053 break;
1054 default:
1055 close(sw->fd);
1056 break;
1057 }
1058}
1059
1060/* Fill the window */
1061static int sw_fill_window(struct abis_nm_sw *sw)
1062{
1063 int rc;
1064
1065 while (sw->seg_in_window < sw->window_size) {
1066 rc = sw_load_segment(sw);
1067 if (rc < 0)
1068 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001069 if (sw->last_seg)
1070 break;
Harald Welte4724f992009-01-18 18:01:49 +00001071 }
1072 return 0;
1073}
1074
1075/* callback function from abis_nm_rcvmsg() handler */
1076static int abis_nm_rcvmsg_sw(struct msgb *mb)
1077{
1078 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001079 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001080 int rc = -1;
1081 struct abis_nm_sw *sw = &g_sw;
1082 enum sw_state old_state = sw->state;
1083
Harald Welte3ffd1372009-02-01 22:15:49 +00001084 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001085
1086 switch (sw->state) {
1087 case SW_STATE_WAIT_INITACK:
1088 switch (foh->msg_type) {
1089 case NM_MT_LOAD_INIT_ACK:
1090 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001091 if (sw->cbfn)
1092 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1093 NM_MT_LOAD_INIT_ACK, mb,
1094 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001095 rc = sw_fill_window(sw);
1096 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001097 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001098 break;
1099 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001100 if (sw->forced) {
1101 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1102 "Init NACK\n");
1103 if (sw->cbfn)
1104 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1105 NM_MT_LOAD_INIT_ACK, mb,
1106 sw->cb_data, NULL);
1107 rc = sw_fill_window(sw);
1108 sw->state = SW_STATE_WAIT_SEGACK;
1109 } else {
1110 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001111 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001112 if (sw->cbfn)
1113 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1114 NM_MT_LOAD_INIT_NACK, mb,
1115 sw->cb_data, NULL);
1116 sw->state = SW_STATE_ERROR;
1117 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001118 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001119 break;
1120 }
1121 break;
1122 case SW_STATE_WAIT_SEGACK:
1123 switch (foh->msg_type) {
1124 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001125 if (sw->cbfn)
1126 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1127 NM_MT_LOAD_SEG_ACK, mb,
1128 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001129 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001130 if (!sw->last_seg) {
1131 /* fill window with more segments */
1132 rc = sw_fill_window(sw);
1133 sw->state = SW_STATE_WAIT_SEGACK;
1134 } else {
1135 /* end the transfer */
1136 sw->state = SW_STATE_WAIT_ENDACK;
1137 rc = sw_load_end(sw);
1138 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001139 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001140 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001141 case NM_MT_LOAD_ABORT:
1142 if (sw->cbfn)
1143 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1144 NM_MT_LOAD_ABORT, mb,
1145 sw->cb_data, NULL);
1146 break;
Harald Welte4724f992009-01-18 18:01:49 +00001147 }
1148 break;
1149 case SW_STATE_WAIT_ENDACK:
1150 switch (foh->msg_type) {
1151 case NM_MT_LOAD_END_ACK:
1152 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001153 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1154 sw->bts->nr);
1155 sw->state = SW_STATE_NONE;
1156 if (sw->cbfn)
1157 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1158 NM_MT_LOAD_END_ACK, mb,
1159 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001160 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001161 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001162 break;
1163 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001164 if (sw->forced) {
1165 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1166 "End NACK\n");
1167 sw->state = SW_STATE_NONE;
1168 if (sw->cbfn)
1169 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1170 NM_MT_LOAD_END_ACK, mb,
1171 sw->cb_data, NULL);
1172 } else {
1173 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001174 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001175 sw->state = SW_STATE_ERROR;
1176 if (sw->cbfn)
1177 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1178 NM_MT_LOAD_END_NACK, mb,
1179 sw->cb_data, NULL);
1180 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001181 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001182 break;
1183 }
1184 case SW_STATE_WAIT_ACTACK:
1185 switch (foh->msg_type) {
1186 case NM_MT_ACTIVATE_SW_ACK:
1187 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001188 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001189 sw->state = SW_STATE_NONE;
1190 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001191 if (sw->cbfn)
1192 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1193 NM_MT_ACTIVATE_SW_ACK, mb,
1194 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001195 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001196 break;
1197 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001198 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001199 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001200 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001201 if (sw->cbfn)
1202 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1203 NM_MT_ACTIVATE_SW_NACK, mb,
1204 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001205 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001206 break;
1207 }
1208 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001209 switch (foh->msg_type) {
1210 case NM_MT_ACTIVATE_SW_ACK:
1211 rc = 0;
1212 break;
1213 }
1214 break;
Harald Welte4724f992009-01-18 18:01:49 +00001215 case SW_STATE_ERROR:
1216 break;
1217 }
1218
1219 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001220 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001221 foh->msg_type, old_state, sw->state);
1222
1223 return rc;
1224}
1225
1226/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001227int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001228 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001229 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001230{
1231 struct abis_nm_sw *sw = &g_sw;
1232 int rc;
1233
Harald Welte5e4d1b32009-02-01 13:36:56 +00001234 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1235 bts->nr, fname);
1236
Harald Welte4724f992009-01-18 18:01:49 +00001237 if (sw->state != SW_STATE_NONE)
1238 return -EBUSY;
1239
1240 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001241 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001242
1243 switch (bts->type) {
1244 case GSM_BTS_TYPE_BS11:
1245 sw->obj_class = NM_OC_SITE_MANAGER;
1246 sw->obj_instance[0] = 0xff;
1247 sw->obj_instance[1] = 0xff;
1248 sw->obj_instance[2] = 0xff;
1249 break;
1250 case GSM_BTS_TYPE_NANOBTS:
1251 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001252 sw->obj_instance[0] = sw->bts->nr;
1253 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001254 sw->obj_instance[2] = 0xff;
1255 break;
1256 case GSM_BTS_TYPE_UNKNOWN:
1257 default:
1258 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1259 return -1;
1260 break;
1261 }
Harald Welte4724f992009-01-18 18:01:49 +00001262 sw->window_size = win_size;
1263 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001264 sw->cbfn = cbfn;
1265 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001266 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001267
1268 rc = sw_open_file(sw, fname);
1269 if (rc < 0) {
1270 sw->state = SW_STATE_NONE;
1271 return rc;
1272 }
1273
1274 return sw_load_init(sw);
1275}
Harald Welte52b1f982008-12-23 20:25:15 +00001276
Harald Welte1602ade2009-01-29 21:12:39 +00001277int abis_nm_software_load_status(struct gsm_bts *bts)
1278{
1279 struct abis_nm_sw *sw = &g_sw;
1280 struct stat st;
1281 int rc, percent;
1282
1283 rc = fstat(sw->fd, &st);
1284 if (rc < 0) {
1285 perror("ERROR during stat");
1286 return rc;
1287 }
1288
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001289 if (sw->stream)
1290 percent = (ftell(sw->stream) * 100) / st.st_size;
1291 else
1292 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001293 return percent;
1294}
1295
Harald Welte5e4d1b32009-02-01 13:36:56 +00001296/* Activate the specified software into the BTS */
1297int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1298 gsm_cbfn *cbfn, void *cb_data)
1299{
1300 struct abis_nm_sw *sw = &g_sw;
1301 int rc;
1302
1303 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1304 bts->nr, fname);
1305
1306 if (sw->state != SW_STATE_NONE)
1307 return -EBUSY;
1308
1309 sw->bts = bts;
1310 sw->obj_class = NM_OC_SITE_MANAGER;
1311 sw->obj_instance[0] = 0xff;
1312 sw->obj_instance[1] = 0xff;
1313 sw->obj_instance[2] = 0xff;
1314 sw->state = SW_STATE_WAIT_ACTACK;
1315 sw->cbfn = cbfn;
1316 sw->cb_data = cb_data;
1317
1318 /* Open the file in order to fill some sw struct members */
1319 rc = sw_open_file(sw, fname);
1320 if (rc < 0) {
1321 sw->state = SW_STATE_NONE;
1322 return rc;
1323 }
1324 sw_close_file(sw);
1325
1326 return sw_activate(sw);
1327}
1328
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001329static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1330 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001331{
Harald Welteadaf08b2009-01-18 11:08:10 +00001332 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001333 ch->bts_port = bts_port;
1334 ch->timeslot = ts_nr;
1335 ch->subslot = subslot_nr;
1336}
1337
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001338int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1339 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1340 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001341{
1342 struct abis_om_hdr *oh;
1343 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001344 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001345 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001346
1347 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1348 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1349 bts->bts_nr, trx_nr, 0xff);
1350
Harald Welte8470bf22008-12-25 23:28:35 +00001351 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001352
1353 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1354 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1355
1356 return abis_nm_sendmsg(bts, msg);
1357}
1358
1359/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1360int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001361 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001362{
Harald Welte8470bf22008-12-25 23:28:35 +00001363 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001364 struct abis_om_hdr *oh;
1365 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001366 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001367
1368 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001369 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001370 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1371
1372 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1373 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1374
1375 return abis_nm_sendmsg(bts, msg);
1376}
1377
1378#if 0
1379int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1380 struct abis_nm_abis_channel *chan)
1381{
1382}
1383#endif
1384
1385int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001386 uint8_t e1_port, uint8_t e1_timeslot,
1387 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001388{
1389 struct gsm_bts *bts = ts->trx->bts;
1390 struct abis_om_hdr *oh;
1391 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001392 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001393
1394 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1395 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001396 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001397
1398 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1399 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1400
Harald Weltef325eb42009-02-19 17:07:39 +00001401 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1402 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001403 e1_port, e1_timeslot, e1_subslot);
1404
Harald Welte52b1f982008-12-23 20:25:15 +00001405 return abis_nm_sendmsg(bts, msg);
1406}
1407
1408#if 0
1409int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1410 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001411 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001412{
1413}
1414#endif
1415
Harald Weltefe568f22012-08-14 19:15:57 +02001416/* Chapter 8.11.1 */
1417int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1418 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1419 uint8_t *attr, uint8_t attr_len)
1420{
1421 struct abis_om_hdr *oh;
1422 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001423
1424 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1425
1426 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1427 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1428 bts_nr, trx_nr, ts_nr);
1429 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1430
1431 return abis_nm_sendmsg(bts, msg);
1432}
1433
Harald Welte22af0db2009-02-14 15:41:08 +00001434/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001435int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001436{
1437 struct abis_om_hdr *oh;
1438 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001439 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001440
1441 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1442
1443 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001444 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 +00001445 cur = msgb_put(msg, attr_len);
1446 memcpy(cur, attr, attr_len);
1447
1448 return abis_nm_sendmsg(bts, msg);
1449}
1450
1451/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001452int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001453{
1454 struct abis_om_hdr *oh;
1455 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001456 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001457
1458 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1459
1460 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1461 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001462 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001463 cur = msgb_put(msg, attr_len);
1464 memcpy(cur, attr, attr_len);
1465
1466 return abis_nm_sendmsg(trx->bts, msg);
1467}
1468
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001469int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1470{
1471 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1472 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1473}
1474
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001475static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1476 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001477{
1478 int i;
1479
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001480 *reason = "Reason unknown";
1481
Harald Welte39c7deb2009-08-09 21:49:48 +02001482 /* As it turns out, the BS-11 has some very peculiar restrictions
1483 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301484 switch (ts->trx->bts->type) {
1485 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001486 switch (chan_comb) {
1487 case NM_CHANC_TCHHalf:
1488 case NM_CHANC_TCHHalf2:
1489 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001490 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001491 return -EINVAL;
1492 case NM_CHANC_SDCCH:
1493 /* only one SDCCH/8 per TRX */
1494 for (i = 0; i < TRX_NR_TS; i++) {
1495 if (i == ts->nr)
1496 continue;
1497 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001498 NM_CHANC_SDCCH) {
1499 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001500 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001501 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001502 }
1503 /* not allowed for TS0 of BCCH-TRX */
1504 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001505 ts->nr == 0) {
1506 *reason = "SDCCH/8 must be on TS0.";
1507 return -EINVAL;
1508 }
1509
Harald Welte39c7deb2009-08-09 21:49:48 +02001510 /* not on the same TRX that has a BCCH+SDCCH4
1511 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001512 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001513 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001514 ts->trx->ts[0].nm_chan_comb == 8)) {
1515 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1516 return -EINVAL;
1517 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001518 break;
1519 case NM_CHANC_mainBCCH:
1520 case NM_CHANC_BCCHComb:
1521 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001522 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1523 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001524 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001525 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001526 break;
1527 case NM_CHANC_BCCH:
1528 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001529 if (ts->trx != ts->trx->bts->c0) {
1530 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001531 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001532 }
1533 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1534 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001535 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001536 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001537 break;
1538 case 8: /* this is not like 08.58, but in fact
1539 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1540 /* FIXME: only one CBCH allowed per cell */
1541 break;
1542 }
Harald Welted6575f92009-12-02 02:45:23 +05301543 break;
1544 case GSM_BTS_TYPE_NANOBTS:
1545 switch (ts->nr) {
1546 case 0:
1547 if (ts->trx->nr == 0) {
1548 /* only on TRX0 */
1549 switch (chan_comb) {
1550 case NM_CHANC_BCCH:
1551 case NM_CHANC_mainBCCH:
1552 case NM_CHANC_BCCHComb:
1553 return 0;
1554 break;
1555 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001556 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301557 return -EINVAL;
1558 }
1559 } else {
1560 switch (chan_comb) {
1561 case NM_CHANC_TCHFull:
1562 case NM_CHANC_TCHHalf:
1563 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1564 return 0;
1565 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001566 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301567 return -EINVAL;
1568 }
1569 }
1570 break;
1571 case 1:
1572 if (ts->trx->nr == 0) {
1573 switch (chan_comb) {
1574 case NM_CHANC_SDCCH_CBCH:
1575 if (ts->trx->ts[0].nm_chan_comb ==
1576 NM_CHANC_mainBCCH)
1577 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001578 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301579 return -EINVAL;
1580 case NM_CHANC_SDCCH:
1581 case NM_CHANC_TCHFull:
1582 case NM_CHANC_TCHHalf:
1583 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1584 case NM_CHANC_IPAC_TCHFull_PDCH:
1585 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001586 default:
1587 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1588 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301589 }
1590 } else {
1591 switch (chan_comb) {
1592 case NM_CHANC_SDCCH:
1593 case NM_CHANC_TCHFull:
1594 case NM_CHANC_TCHHalf:
1595 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1596 return 0;
1597 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001598 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301599 return -EINVAL;
1600 }
1601 }
1602 break;
1603 case 2:
1604 case 3:
1605 case 4:
1606 case 5:
1607 case 6:
1608 case 7:
1609 switch (chan_comb) {
1610 case NM_CHANC_TCHFull:
1611 case NM_CHANC_TCHHalf:
1612 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1613 return 0;
1614 case NM_CHANC_IPAC_PDCH:
1615 case NM_CHANC_IPAC_TCHFull_PDCH:
1616 if (ts->trx->nr == 0)
1617 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001618 else {
1619 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301620 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001621 }
Harald Welted6575f92009-12-02 02:45:23 +05301622 }
1623 break;
1624 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001625 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301626 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001627 case GSM_BTS_TYPE_OSMO_SYSMO:
1628 /* no known restrictions */
1629 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301630 default:
1631 /* unknown BTS type */
1632 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001633 }
1634 return 0;
1635}
1636
Harald Welte22af0db2009-02-14 15:41:08 +00001637/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001638int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001639{
1640 struct gsm_bts *bts = ts->trx->bts;
1641 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001642 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001643 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001644 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001645 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001646
1647 if (bts->type == GSM_BTS_TYPE_BS11)
1648 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001649
Harald Weltef325eb42009-02-19 17:07:39 +00001650 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001651 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001652 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001653 LOGP(DNM, LOGL_ERROR,
1654 "Invalid Channel Combination %d on %s. Reason: %s\n",
1655 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001656 return -EINVAL;
1657 }
1658 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001659
Harald Welte52b1f982008-12-23 20:25:15 +00001660 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001661 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001662 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001663 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001664 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001665 if (ts->hopping.enabled) {
1666 unsigned int i;
1667 uint8_t *len;
1668
Harald Welte6e0cd042009-09-12 13:05:33 +02001669 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1670 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001671
1672 /* build the ARFCN list */
1673 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1674 len = msgb_put(msg, 1);
1675 *len = 0;
1676 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1677 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1678 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001679 /* At least BS-11 wants a TLV16 here */
1680 if (bts->type == GSM_BTS_TYPE_BS11)
1681 *len += 1;
1682 else
1683 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001684 }
1685 }
Harald Weltee0590df2009-02-15 03:34:15 +00001686 }
Harald Welte1fe24122014-01-19 17:18:21 +01001687 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001688 if (bts->type == GSM_BTS_TYPE_BS11)
1689 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001690
1691 return abis_nm_sendmsg(bts, msg);
1692}
1693
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001694int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1695 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001696{
1697 struct abis_om_hdr *oh;
1698 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001699 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1700 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001701
1702 if (nack) {
1703 len += 2;
1704 msgtype = NM_MT_SW_ACT_REQ_NACK;
1705 }
Harald Welte34a99682009-02-13 02:41:40 +00001706
1707 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001708 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1709
Harald Welte34a99682009-02-13 02:41:40 +00001710 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001711 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001712 memcpy(ptr, attr, att_len);
1713 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001714 if (nack)
1715 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001716
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001717 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001718}
1719
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001720int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001721{
Harald Welte8470bf22008-12-25 23:28:35 +00001722 struct msgb *msg = nm_msgb_alloc();
1723 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001724 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001725
1726 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1727 fill_om_hdr(oh, len);
1728 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001729 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001730
1731 return abis_nm_sendmsg(bts, msg);
1732}
1733
1734/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001735static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001736{
1737 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001738 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001739
1740 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001741 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001742 0xff, 0xff, 0xff);
1743
1744 return abis_nm_sendmsg(bts, msg);
1745}
1746
Harald Welte34a99682009-02-13 02:41:40 +00001747/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001748int 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 +00001749{
1750 struct abis_om_hdr *oh;
1751 struct msgb *msg = nm_msgb_alloc();
1752
1753 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1754 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1755
Harald Welte15c61722011-05-22 22:45:37 +02001756 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001757 DEBUGPC(DNM, "Sending OPSTART\n");
1758
Harald Welte34a99682009-02-13 02:41:40 +00001759 return abis_nm_sendmsg(bts, msg);
1760}
1761
1762/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001763int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1764 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001765{
1766 struct abis_om_hdr *oh;
1767 struct msgb *msg = nm_msgb_alloc();
1768
1769 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1770 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1771 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1772
1773 return abis_nm_sendmsg(bts, msg);
1774}
1775
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001776int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1777 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001778{
1779 struct abis_om_hdr *oh;
1780 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001781 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001782
1783 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1784 e1_port0, ts0, e1_port1, ts1);
1785
1786 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1787 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1788 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1789
1790 attr = msgb_put(msg, 3);
1791 attr[0] = NM_ATT_MDROP_LINK;
1792 attr[1] = e1_port0;
1793 attr[2] = ts0;
1794
1795 attr = msgb_put(msg, 3);
1796 attr[0] = NM_ATT_MDROP_NEXT;
1797 attr[1] = e1_port1;
1798 attr[2] = ts1;
1799
1800 return abis_nm_sendmsg(bts, msg);
1801}
Harald Welte34a99682009-02-13 02:41:40 +00001802
Harald Weltec7310382009-08-08 00:02:36 +02001803/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001804int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1805 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1806 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001807{
1808 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001809
Harald Welte15c61722011-05-22 22:45:37 +02001810 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001811
1812 if (!msg)
1813 msg = nm_msgb_alloc();
1814
1815 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1816 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1817 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1818 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001819 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001820
1821 return abis_nm_sendmsg(bts, msg);
1822}
1823
Harald Welte52b1f982008-12-23 20:25:15 +00001824int abis_nm_event_reports(struct gsm_bts *bts, int on)
1825{
1826 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001827 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001828 else
Harald Welte227d4072009-01-03 08:16:25 +00001829 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001830}
1831
Harald Welte47d88ae2009-01-04 12:02:08 +00001832/* Siemens (or BS-11) specific commands */
1833
Harald Welte3ffd1372009-02-01 22:15:49 +00001834int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1835{
1836 if (reconnect == 0)
1837 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1838 else
1839 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1840}
1841
Harald Welteb8427972009-02-05 19:27:17 +00001842int abis_nm_bs11_restart(struct gsm_bts *bts)
1843{
1844 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1845}
1846
1847
Harald Welte268bb402009-02-01 19:11:56 +00001848struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001849 uint16_t year;
1850 uint8_t month;
1851 uint8_t day;
1852 uint8_t hour;
1853 uint8_t min;
1854 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001855} __attribute__((packed));
1856
1857
1858void get_bs11_date_time(struct bs11_date_time *aet)
1859{
1860 time_t t;
1861 struct tm *tm;
1862
1863 t = time(NULL);
1864 tm = localtime(&t);
1865 aet->sec = tm->tm_sec;
1866 aet->min = tm->tm_min;
1867 aet->hour = tm->tm_hour;
1868 aet->day = tm->tm_mday;
1869 aet->month = tm->tm_mon;
1870 aet->year = htons(1900 + tm->tm_year);
1871}
1872
Harald Welte05188ee2009-01-18 11:39:08 +00001873int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001874{
Harald Welte4668fda2009-01-03 08:19:29 +00001875 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001876}
1877
Harald Welte05188ee2009-01-18 11:39:08 +00001878int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001879{
1880 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001881 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001882 else
Harald Welte4668fda2009-01-03 08:19:29 +00001883 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001884}
Harald Welte47d88ae2009-01-04 12:02:08 +00001885
Harald Welte05188ee2009-01-18 11:39:08 +00001886int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001887 enum abis_bs11_objtype type, uint8_t idx,
1888 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001889{
1890 struct abis_om_hdr *oh;
1891 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001892 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001893
1894 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001895 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001896 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001897 cur = msgb_put(msg, attr_len);
1898 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001899
1900 return abis_nm_sendmsg(bts, msg);
1901}
1902
Harald Welte78fc0d42009-02-19 02:50:57 +00001903int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001904 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001905{
1906 struct abis_om_hdr *oh;
1907 struct msgb *msg = nm_msgb_alloc();
1908
1909 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1910 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1911 NM_OC_BS11, type, 0, idx);
1912
1913 return abis_nm_sendmsg(bts, msg);
1914}
1915
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001916int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001917{
1918 struct abis_om_hdr *oh;
1919 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001920 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001921
1922 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001923 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001924 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1925 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001926
1927 return abis_nm_sendmsg(bts, msg);
1928}
1929
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001930int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001931{
1932 struct abis_om_hdr *oh;
1933 struct msgb *msg = nm_msgb_alloc();
1934
1935 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1936 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001937 idx, 0xff, 0xff);
1938
1939 return abis_nm_sendmsg(bts, msg);
1940}
1941
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001942int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001943{
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_DELETE_OBJ, NM_OC_BS11_BPORT,
1949 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001950
1951 return abis_nm_sendmsg(bts, msg);
1952}
Harald Welte05188ee2009-01-18 11:39:08 +00001953
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001954static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001955int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1956{
1957 struct abis_om_hdr *oh;
1958 struct msgb *msg = nm_msgb_alloc();
1959
1960 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1961 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1962 0xff, 0xff, 0xff);
1963 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1964
1965 return abis_nm_sendmsg(bts, msg);
1966}
1967
Harald Welteb6c92ae2009-02-21 20:15:32 +00001968/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001969int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1970 uint8_t e1_timeslot, uint8_t e1_subslot,
1971 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001972{
1973 struct abis_om_hdr *oh;
1974 struct abis_nm_channel *ch;
1975 struct msgb *msg = nm_msgb_alloc();
1976
1977 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001978 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001979 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1980
1981 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1982 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001983 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001984
1985 return abis_nm_sendmsg(bts, msg);
1986}
1987
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001988int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001989{
1990 struct abis_om_hdr *oh;
1991 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001992
1993 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001994 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001995 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1996 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1997
1998 return abis_nm_sendmsg(trx->bts, msg);
1999}
2000
Harald Welte78fc0d42009-02-19 02:50:57 +00002001int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2002{
2003 struct abis_om_hdr *oh;
2004 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002005 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002006
2007 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2008 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2009 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2010 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2011
2012 return abis_nm_sendmsg(trx->bts, msg);
2013}
2014
Harald Welteaaf02d92009-04-29 13:25:57 +00002015int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2016{
2017 struct abis_om_hdr *oh;
2018 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002019 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002020
2021 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2022 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2023 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002024 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002025
2026 return abis_nm_sendmsg(bts, msg);
2027}
2028
Harald Welteef061952009-05-17 12:43:42 +00002029int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2030{
2031 struct abis_om_hdr *oh;
2032 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002033 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002034 NM_ATT_BS11_CCLK_TYPE };
2035
2036 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2037 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2038 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2039 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2040
2041 return abis_nm_sendmsg(bts, msg);
2042
2043}
Harald Welteaaf02d92009-04-29 13:25:57 +00002044
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002045//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002046
Harald Welte1bc09062009-01-18 14:17:52 +00002047int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002048{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002049 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2050}
2051
Daniel Willmann4b054c82010-01-07 00:46:26 +01002052int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2053{
2054 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2055}
2056
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002057int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002058{
Harald Welte05188ee2009-01-18 11:39:08 +00002059 struct abis_om_hdr *oh;
2060 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002061 struct bs11_date_time bdt;
2062
2063 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002064
2065 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002066 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002067 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002068 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002069 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002070 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002071 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002072 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002073 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002074 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002075 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002076 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002077 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002078 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002079 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002080 }
Harald Welte05188ee2009-01-18 11:39:08 +00002081
2082 return abis_nm_sendmsg(bts, msg);
2083}
Harald Welte1bc09062009-01-18 14:17:52 +00002084
2085int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2086{
2087 struct abis_om_hdr *oh;
2088 struct msgb *msg;
2089
2090 if (strlen(password) != 10)
2091 return -EINVAL;
2092
2093 msg = nm_msgb_alloc();
2094 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002095 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002096 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002097 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002098
2099 return abis_nm_sendmsg(bts, msg);
2100}
2101
Harald Weltee69f5fb2009-04-28 16:31:38 +00002102/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2103int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2104{
2105 struct abis_om_hdr *oh;
2106 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002107 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002108
2109 msg = nm_msgb_alloc();
2110 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2111 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2112 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002113
2114 if (locked)
2115 tlv_value = BS11_LI_PLL_LOCKED;
2116 else
2117 tlv_value = BS11_LI_PLL_STANDALONE;
2118
2119 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002120
2121 return abis_nm_sendmsg(bts, msg);
2122}
2123
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002124/* Set the calibration value of the PLL (work value/set value)
2125 * It depends on the login which one is changed */
2126int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2127{
2128 struct abis_om_hdr *oh;
2129 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002130 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002131
2132 msg = nm_msgb_alloc();
2133 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2134 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2135 BS11_OBJ_TRX1, 0x00, 0x00);
2136
2137 tlv_value[0] = value>>8;
2138 tlv_value[1] = value&0xff;
2139
2140 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2141
2142 return abis_nm_sendmsg(bts, msg);
2143}
2144
Harald Welte1bc09062009-01-18 14:17:52 +00002145int abis_nm_bs11_get_state(struct gsm_bts *bts)
2146{
2147 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2148}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002149
2150/* BS11 SWL */
2151
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002152void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002153
Harald Welte5e4d1b32009-02-01 13:36:56 +00002154struct abis_nm_bs11_sw {
2155 struct gsm_bts *bts;
2156 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002157 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002158 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002159 struct llist_head file_list;
2160 gsm_cbfn *user_cb; /* specified by the user */
2161};
2162static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2163
2164struct file_list_entry {
2165 struct llist_head list;
2166 char fname[PATH_MAX];
2167};
2168
2169struct file_list_entry *fl_dequeue(struct llist_head *queue)
2170{
2171 struct llist_head *lh;
2172
2173 if (llist_empty(queue))
2174 return NULL;
2175
2176 lh = queue->next;
2177 llist_del(lh);
2178
2179 return llist_entry(lh, struct file_list_entry, list);
2180}
2181
2182static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2183{
2184 char linebuf[255];
2185 struct llist_head *lh, *lh2;
2186 FILE *swl;
2187 int rc = 0;
2188
2189 swl = fopen(bs11_sw->swl_fname, "r");
2190 if (!swl)
2191 return -ENODEV;
2192
2193 /* zero the stale file list, if any */
2194 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2195 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002196 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002197 }
2198
2199 while (fgets(linebuf, sizeof(linebuf), swl)) {
2200 char file_id[12+1];
2201 char file_version[80+1];
2202 struct file_list_entry *fle;
2203 static char dir[PATH_MAX];
2204
2205 if (strlen(linebuf) < 4)
2206 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002207
Harald Welte5e4d1b32009-02-01 13:36:56 +00002208 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2209 if (rc < 0) {
2210 perror("ERR parsing SWL file");
2211 rc = -EINVAL;
2212 goto out;
2213 }
2214 if (rc < 2)
2215 continue;
2216
Harald Welte470ec292009-06-26 20:25:23 +02002217 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002218 if (!fle) {
2219 rc = -ENOMEM;
2220 goto out;
2221 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002222
2223 /* construct new filename */
2224 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2225 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2226 strcat(fle->fname, "/");
2227 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002228
2229 llist_add_tail(&fle->list, &bs11_sw->file_list);
2230 }
2231
2232out:
2233 fclose(swl);
2234 return rc;
2235}
2236
2237/* bs11 swload specific callback, passed to abis_nm core swload */
2238static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2239 struct msgb *msg, void *data, void *param)
2240{
2241 struct abis_nm_bs11_sw *bs11_sw = data;
2242 struct file_list_entry *fle;
2243 int rc = 0;
2244
Harald Welte5e4d1b32009-02-01 13:36:56 +00002245 switch (event) {
2246 case NM_MT_LOAD_END_ACK:
2247 fle = fl_dequeue(&bs11_sw->file_list);
2248 if (fle) {
2249 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002250 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002251 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002252 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002253 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002254 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002255 } else {
2256 /* activate the SWL */
2257 rc = abis_nm_software_activate(bs11_sw->bts,
2258 bs11_sw->swl_fname,
2259 bs11_swload_cbfn,
2260 bs11_sw);
2261 }
2262 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002263 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002264 case NM_MT_LOAD_END_NACK:
2265 case NM_MT_LOAD_INIT_ACK:
2266 case NM_MT_LOAD_INIT_NACK:
2267 case NM_MT_ACTIVATE_SW_NACK:
2268 case NM_MT_ACTIVATE_SW_ACK:
2269 default:
2270 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002271 if (bs11_sw->user_cb)
2272 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002273 break;
2274 }
2275
2276 return rc;
2277}
2278
2279/* Siemens provides a SWL file that is a mere listing of all the other
2280 * files that are part of a software release. We need to upload first
2281 * the list file, and then each file that is listed in the list file */
2282int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002283 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002284{
2285 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2286 struct file_list_entry *fle;
2287 int rc = 0;
2288
2289 INIT_LLIST_HEAD(&bs11_sw->file_list);
2290 bs11_sw->bts = bts;
2291 bs11_sw->win_size = win_size;
2292 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002293 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002294
2295 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2296 rc = bs11_read_swl_file(bs11_sw);
2297 if (rc < 0)
2298 return rc;
2299
2300 /* dequeue next item in file list */
2301 fle = fl_dequeue(&bs11_sw->file_list);
2302 if (!fle)
2303 return -EINVAL;
2304
2305 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002306 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002307 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002308 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002309 return rc;
2310}
2311
Harald Welte5083b0b2009-02-02 19:20:52 +00002312#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002313static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002314 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2315 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2316 NM_ATT_BS11_LMT_USER_NAME,
2317
2318 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2319
2320 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2321
2322 NM_ATT_BS11_SW_LOAD_STORED };
2323
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002324static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002325 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2326 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2327 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2328 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002329#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002330
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002331static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002332 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2333 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002334 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002335
2336int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2337{
2338 struct abis_om_hdr *oh;
2339 struct msgb *msg = nm_msgb_alloc();
2340
2341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2342 /* SiemensHW CCTRL object */
2343 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2344 0x03, 0x00, 0x00);
2345 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2346
2347 return abis_nm_sendmsg(bts, msg);
2348}
Harald Welte268bb402009-02-01 19:11:56 +00002349
2350int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2351{
2352 struct abis_om_hdr *oh;
2353 struct msgb *msg = nm_msgb_alloc();
2354 struct bs11_date_time aet;
2355
2356 get_bs11_date_time(&aet);
2357 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2358 /* SiemensHW CCTRL object */
2359 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2360 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002361 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002362
2363 return abis_nm_sendmsg(bts, msg);
2364}
Harald Welte5c1e4582009-02-15 11:57:29 +00002365
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002366int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002367{
2368 struct abis_om_hdr *oh;
2369 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002370 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002371
2372 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2373 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2374 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2375 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2376
2377 return abis_nm_sendmsg(bts, msg);
2378}
2379
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002380int 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 +02002381{
2382 struct abis_om_hdr *oh;
2383 struct msgb *msg = nm_msgb_alloc();
2384 struct bs11_date_time aet;
2385
2386 get_bs11_date_time(&aet);
2387 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2388 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2389 bport, 0xff, 0x02);
2390 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2391
2392 return abis_nm_sendmsg(bts, msg);
2393}
2394
Harald Welte5c1e4582009-02-15 11:57:29 +00002395/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002396static const char ipaccess_magic[] = "com.ipaccess";
2397
Harald Welte677c21f2009-02-17 13:22:23 +00002398
2399static int abis_nm_rx_ipacc(struct msgb *msg)
2400{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002401 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002402 struct abis_om_hdr *oh = msgb_l2(msg);
2403 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002404 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002405 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002406 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002407 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002408
2409 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002410 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002411 return -EINVAL;
2412 }
2413
Harald Welte193fefc2009-04-30 15:16:27 +00002414 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002415 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002416
Harald Welte15c61722011-05-22 22:45:37 +02002417 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002418
Harald Welte746d6092009-10-19 22:11:11 +02002419 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002420
Harald Welte677c21f2009-02-17 13:22:23 +00002421 switch (foh->msg_type) {
2422 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002423 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002424 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2425 memcpy(&addr,
2426 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2427
2428 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2429 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002430 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002431 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002432 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002433 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002434 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2435 DEBUGPC(DNM, "STREAM=0x%02x ",
2436 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002437 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002438 break;
2439 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002440 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002441 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002442 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002443 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002444 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002445 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002446 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002447 case NM_MT_IPACC_SET_NVATTR_ACK:
2448 DEBUGPC(DNM, "SET NVATTR ACK\n");
2449 /* FIXME: decode and show the actual attributes */
2450 break;
2451 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002452 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002453 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002454 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002455 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002456 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002457 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002458 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002459 case NM_MT_IPACC_GET_NVATTR_ACK:
2460 DEBUGPC(DNM, "GET NVATTR ACK\n");
2461 /* FIXME: decode and show the actual attributes */
2462 break;
2463 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002464 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002465 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002466 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002467 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002468 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002469 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002470 break;
Harald Welte15c44172009-10-08 20:15:24 +02002471 case NM_MT_IPACC_SET_ATTR_ACK:
2472 DEBUGPC(DNM, "SET ATTR ACK\n");
2473 break;
2474 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002475 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002476 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002477 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002478 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002479 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002480 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002481 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002482 default:
2483 DEBUGPC(DNM, "unknown\n");
2484 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002485 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002486
2487 /* signal handling */
2488 switch (foh->msg_type) {
2489 case NM_MT_IPACC_RSL_CONNECT_NACK:
2490 case NM_MT_IPACC_SET_NVATTR_NACK:
2491 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002492 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 +01002493 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002494 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002495 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002496 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002497 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 +01002498 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002499 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002500 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002501 default:
2502 break;
2503 }
2504
Harald Welte677c21f2009-02-17 13:22:23 +00002505 return 0;
2506}
2507
Harald Welte193fefc2009-04-30 15:16:27 +00002508/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002509int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2510 uint8_t obj_class, uint8_t bts_nr,
2511 uint8_t trx_nr, uint8_t ts_nr,
2512 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002513{
2514 struct msgb *msg = nm_msgb_alloc();
2515 struct abis_om_hdr *oh;
2516 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002517 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002518
2519 /* construct the 12.21 OM header, observe the erroneous length */
2520 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2521 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2522 oh->mdisc = ABIS_OM_MDISC_MANUF;
2523
2524 /* add the ip.access magic */
2525 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2526 *data++ = sizeof(ipaccess_magic);
2527 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2528
2529 /* fill the 12.21 FOM header */
2530 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2531 foh->msg_type = msg_type;
2532 foh->obj_class = obj_class;
2533 foh->obj_inst.bts_nr = bts_nr;
2534 foh->obj_inst.trx_nr = trx_nr;
2535 foh->obj_inst.ts_nr = ts_nr;
2536
2537 if (attr && attr_len) {
2538 data = msgb_put(msg, attr_len);
2539 memcpy(data, attr, attr_len);
2540 }
2541
2542 return abis_nm_sendmsg(bts, msg);
2543}
Harald Welte677c21f2009-02-17 13:22:23 +00002544
Harald Welte193fefc2009-04-30 15:16:27 +00002545/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002546int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002547 int attr_len)
2548{
Harald Welte2ef156d2010-01-07 20:39:42 +01002549 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2550 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002551 attr_len);
2552}
2553
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002554int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002555 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002556{
2557 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002558 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002559 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2560 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2561
2562 int attr_len = sizeof(attr);
2563
2564 ia.s_addr = htonl(ip);
2565 attr[1] = stream;
2566 attr[3] = port >> 8;
2567 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002568 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002569
2570 /* if ip == 0, we use the default IP */
2571 if (ip == 0)
2572 attr_len -= 5;
2573
2574 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002575 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002576
2577 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2578 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2579 trx->nr, 0xff, attr, attr_len);
2580}
2581
Harald Welte193fefc2009-04-30 15:16:27 +00002582/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002583int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002584{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002585 struct abis_om_hdr *oh;
2586 struct msgb *msg = nm_msgb_alloc();
2587
2588 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2589 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2590 trx->bts->nr, trx->nr, 0xff);
2591
2592 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002593}
Harald Weltedaef5212009-10-24 10:20:41 +02002594
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002595int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2596 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2597 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002598{
2599 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2600 obj_class, bts_nr, trx_nr, ts_nr,
2601 attr, attr_len);
2602}
Harald Welte0f255852009-11-12 14:48:42 +01002603
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002604void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002605{
2606 /* we simply reuse the GSM48 function and overwrite the RAC
2607 * with the Cell ID */
2608 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002609 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002610}
2611
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002612void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2613{
2614 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2615
Harald Welted64c0bc2011-05-30 12:07:53 +02002616 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002617 if (!trx->bts || !trx->bts->oml_link)
2618 return;
2619
2620 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2621 trx->bts->bts_nr, trx->nr, 0xff,
2622 new_state);
2623}
2624
Harald Welte92b1fe42010-03-25 11:45:30 +08002625static const struct value_string ipacc_testres_names[] = {
2626 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2627 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2628 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2629 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2630 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2631 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002632};
2633
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002634const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002635{
Harald Welte92b1fe42010-03-25 11:45:30 +08002636 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002637}
2638
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002639void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002640{
2641 cid->mcc = (buf[0] & 0xf) * 100;
2642 cid->mcc += (buf[0] >> 4) * 10;
2643 cid->mcc += (buf[1] & 0xf) * 1;
2644
2645 if (buf[1] >> 4 == 0xf) {
2646 cid->mnc = (buf[2] & 0xf) * 10;
2647 cid->mnc += (buf[2] >> 4) * 1;
2648 } else {
2649 cid->mnc = (buf[2] & 0xf) * 100;
2650 cid->mnc += (buf[2] >> 4) * 10;
2651 cid->mnc += (buf[1] >> 4) * 1;
2652 }
2653
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002654 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2655 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002656}
2657
Harald Welte0f255852009-11-12 14:48:42 +01002658/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002659int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002660{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002661 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002662 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002663
Harald Welteaf109b92010-07-22 18:14:36 +02002664 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002665
2666 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2667 return -EINVAL;
2668 cur++;
2669
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002670 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002671 cur += 2;
2672
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002673 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002674 cur += 2;
2675
2676 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2677 binf->freq_qual = *cur >> 2;
2678
Harald Welteaf109b92010-07-22 18:14:36 +02002679 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002680 binf->arfcn |= *cur++;
2681
2682 if (binf->info_type & IPAC_BINF_RXLEV)
2683 binf->rx_lev = *cur & 0x3f;
2684 cur++;
2685
2686 if (binf->info_type & IPAC_BINF_RXQUAL)
2687 binf->rx_qual = *cur & 0x7;
2688 cur++;
2689
2690 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002691 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002692 cur += 2;
2693
2694 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002695 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002696 cur += 2;
2697
2698 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002699 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002700 cur += 4;
2701
Harald Weltea780a3d2010-07-30 22:34:42 +02002702#if 0
2703 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002704 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002705#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002706 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002707 cur++;
2708
Harald Welteb40a38f2009-11-13 11:56:05 +01002709 ipac_parse_cgi(&binf->cgi, cur);
2710 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002711
2712 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2713 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2714 cur += sizeof(binf->ba_list_si2);
2715 }
2716
2717 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2718 memcpy(binf->ba_list_si2bis, cur,
2719 sizeof(binf->ba_list_si2bis));
2720 cur += sizeof(binf->ba_list_si2bis);
2721 }
2722
2723 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2724 memcpy(binf->ba_list_si2ter, cur,
2725 sizeof(binf->ba_list_si2ter));
2726 cur += sizeof(binf->ba_list_si2ter);
2727 }
2728
2729 return 0;
2730}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002731
2732void abis_nm_clear_queue(struct gsm_bts *bts)
2733{
2734 struct msgb *msg;
2735
2736 while (!llist_empty(&bts->abis_queue)) {
2737 msg = msgb_dequeue(&bts->abis_queue);
2738 msgb_free(msg);
2739 }
2740
2741 bts->abis_nm_pend = 0;
2742}