blob: c29e21b3d2879e942bab8f4148a843e4c207e6b2 [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);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200832
833 /* Did ftell fail? Then we are at the end for sure */
834 if (pos < 0)
835 return 1;
836
Harald Welte1602ade2009-01-29 21:12:39 +0000837 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
838 fseek(stream, pos, SEEK_SET);
839 return 1;
840 }
841
842 fseek(stream, pos, SEEK_SET);
843 return 0;
844}
845
Harald Welte4724f992009-01-18 18:01:49 +0000846/* 6.2.2 / 8.3.2 Load Data Segment */
847static int sw_load_segment(struct abis_nm_sw *sw)
848{
849 struct abis_om_hdr *oh;
850 struct msgb *msg = nm_msgb_alloc();
851 char seg_buf[256];
852 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000853 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200854 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000855
856 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000857
858 switch (sw->bts->type) {
859 case GSM_BTS_TYPE_BS11:
860 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
861 perror("fgets reading segment");
862 return -EINVAL;
863 }
864 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000865
866 /* check if we're sending the last line */
867 sw->last_seg = is_last_line(sw->stream);
868 if (sw->last_seg)
869 seg_buf[1] = 0;
870 else
871 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000872
873 len = strlen(line_buf) + 2;
874 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200875 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000876 /* BS11 wants CR + LF in excess of the TLV length !?! */
877 tlv[1] -= 2;
878
879 /* we only now know the exact length for the OM hdr */
880 len = strlen(line_buf)+2;
881 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100882 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200883 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100884 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
885 if (len < 0) {
886 perror("read failed");
887 return -EINVAL;
888 }
889
890 if (len != IPACC_SEGMENT_SIZE)
891 sw->last_seg = 1;
892
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100893 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200894 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100895 len += 3;
896 break;
897 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000898 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100899 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000900 /* FIXME: Other BTS types */
901 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000902 }
Harald Welte4724f992009-01-18 18:01:49 +0000903
Harald Welte4724f992009-01-18 18:01:49 +0000904 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
905 sw->obj_instance[0], sw->obj_instance[1],
906 sw->obj_instance[2]);
907
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100908 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000909}
910
911/* 6.2.4 / 8.3.4 Load Data End */
912static int sw_load_end(struct abis_nm_sw *sw)
913{
914 struct abis_om_hdr *oh;
915 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200916 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000917
918 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
919 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
920 sw->obj_instance[0], sw->obj_instance[1],
921 sw->obj_instance[2]);
922
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100923 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000924 return abis_nm_sendmsg(sw->bts, msg);
925}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000926
Harald Welte52b1f982008-12-23 20:25:15 +0000927/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000928static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000929{
Harald Welte4724f992009-01-18 18:01:49 +0000930 struct abis_om_hdr *oh;
931 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200932 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000933
Harald Welte4724f992009-01-18 18:01:49 +0000934 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
935 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
936 sw->obj_instance[0], sw->obj_instance[1],
937 sw->obj_instance[2]);
938
939 /* FIXME: this is BS11 specific format */
940 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
941 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
942 sw->file_version);
943
944 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000945}
Harald Welte4724f992009-01-18 18:01:49 +0000946
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100947struct sdp_firmware {
948 char magic[4];
949 char more_magic[4];
950 unsigned int header_length;
951 unsigned int file_length;
952} __attribute__ ((packed));
953
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100954static int parse_sdp_header(struct abis_nm_sw *sw)
955{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100956 struct sdp_firmware firmware_header;
957 int rc;
958 struct stat stat;
959
960 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
961 if (rc != sizeof(firmware_header)) {
962 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
963 return -1;
964 }
965
966 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
967 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
968 return -1;
969 }
970
971 if (firmware_header.more_magic[0] != 0x10 ||
972 firmware_header.more_magic[1] != 0x02 ||
973 firmware_header.more_magic[2] != 0x00 ||
974 firmware_header.more_magic[3] != 0x00) {
975 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
976 return -1;
977 }
978
979
980 if (fstat(sw->fd, &stat) == -1) {
981 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
982 return -1;
983 }
984
985 if (ntohl(firmware_header.file_length) != stat.st_size) {
986 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
987 return -1;
988 }
989
990 /* go back to the start as we checked the whole filesize.. */
991 lseek(sw->fd, 0l, SEEK_SET);
992 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
993 "There might be checksums in the file that are not\n"
994 "verified and incomplete firmware might be flashed.\n"
995 "There is absolutely no WARRANTY that flashing will\n"
996 "work.\n");
997 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100998}
999
Harald Welte4724f992009-01-18 18:01:49 +00001000static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1001{
1002 char file_id[12+1];
1003 char file_version[80+1];
1004 int rc;
1005
1006 sw->fd = open(fname, O_RDONLY);
1007 if (sw->fd < 0)
1008 return sw->fd;
1009
1010 switch (sw->bts->type) {
1011 case GSM_BTS_TYPE_BS11:
1012 sw->stream = fdopen(sw->fd, "r");
1013 if (!sw->stream) {
1014 perror("fdopen");
1015 return -1;
1016 }
1017 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001018 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001019 file_id, file_version);
1020 if (rc != 2) {
1021 perror("parsing header line of software file");
1022 return -1;
1023 }
1024 strcpy((char *)sw->file_id, file_id);
1025 sw->file_id_len = strlen(file_id);
1026 strcpy((char *)sw->file_version, file_version);
1027 sw->file_version_len = strlen(file_version);
1028 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001029 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001030 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001031 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001032 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001033 rc = parse_sdp_header(sw);
1034 if (rc < 0) {
1035 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1036 return -1;
1037 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001038
1039 strcpy((char *)sw->file_id, "id");
1040 sw->file_id_len = 3;
1041 strcpy((char *)sw->file_version, "version");
1042 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001043 break;
Harald Welte4724f992009-01-18 18:01:49 +00001044 default:
1045 /* We don't know how to treat them yet */
1046 close(sw->fd);
1047 return -EINVAL;
1048 }
1049
1050 return 0;
1051}
1052
1053static void sw_close_file(struct abis_nm_sw *sw)
1054{
1055 switch (sw->bts->type) {
1056 case GSM_BTS_TYPE_BS11:
1057 fclose(sw->stream);
1058 break;
1059 default:
1060 close(sw->fd);
1061 break;
1062 }
1063}
1064
1065/* Fill the window */
1066static int sw_fill_window(struct abis_nm_sw *sw)
1067{
1068 int rc;
1069
1070 while (sw->seg_in_window < sw->window_size) {
1071 rc = sw_load_segment(sw);
1072 if (rc < 0)
1073 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001074 if (sw->last_seg)
1075 break;
Harald Welte4724f992009-01-18 18:01:49 +00001076 }
1077 return 0;
1078}
1079
1080/* callback function from abis_nm_rcvmsg() handler */
1081static int abis_nm_rcvmsg_sw(struct msgb *mb)
1082{
1083 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001084 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001085 int rc = -1;
1086 struct abis_nm_sw *sw = &g_sw;
1087 enum sw_state old_state = sw->state;
1088
Harald Welte3ffd1372009-02-01 22:15:49 +00001089 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001090
1091 switch (sw->state) {
1092 case SW_STATE_WAIT_INITACK:
1093 switch (foh->msg_type) {
1094 case NM_MT_LOAD_INIT_ACK:
1095 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001096 if (sw->cbfn)
1097 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1098 NM_MT_LOAD_INIT_ACK, mb,
1099 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001100 rc = sw_fill_window(sw);
1101 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001102 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001103 break;
1104 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001105 if (sw->forced) {
1106 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1107 "Init NACK\n");
1108 if (sw->cbfn)
1109 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1110 NM_MT_LOAD_INIT_ACK, mb,
1111 sw->cb_data, NULL);
1112 rc = sw_fill_window(sw);
1113 sw->state = SW_STATE_WAIT_SEGACK;
1114 } else {
1115 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001116 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001117 if (sw->cbfn)
1118 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1119 NM_MT_LOAD_INIT_NACK, mb,
1120 sw->cb_data, NULL);
1121 sw->state = SW_STATE_ERROR;
1122 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001123 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001124 break;
1125 }
1126 break;
1127 case SW_STATE_WAIT_SEGACK:
1128 switch (foh->msg_type) {
1129 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001130 if (sw->cbfn)
1131 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1132 NM_MT_LOAD_SEG_ACK, mb,
1133 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001134 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001135 if (!sw->last_seg) {
1136 /* fill window with more segments */
1137 rc = sw_fill_window(sw);
1138 sw->state = SW_STATE_WAIT_SEGACK;
1139 } else {
1140 /* end the transfer */
1141 sw->state = SW_STATE_WAIT_ENDACK;
1142 rc = sw_load_end(sw);
1143 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001144 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001145 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001146 case NM_MT_LOAD_ABORT:
1147 if (sw->cbfn)
1148 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1149 NM_MT_LOAD_ABORT, mb,
1150 sw->cb_data, NULL);
1151 break;
Harald Welte4724f992009-01-18 18:01:49 +00001152 }
1153 break;
1154 case SW_STATE_WAIT_ENDACK:
1155 switch (foh->msg_type) {
1156 case NM_MT_LOAD_END_ACK:
1157 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001158 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1159 sw->bts->nr);
1160 sw->state = SW_STATE_NONE;
1161 if (sw->cbfn)
1162 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1163 NM_MT_LOAD_END_ACK, mb,
1164 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001165 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001166 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001167 break;
1168 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001169 if (sw->forced) {
1170 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1171 "End NACK\n");
1172 sw->state = SW_STATE_NONE;
1173 if (sw->cbfn)
1174 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1175 NM_MT_LOAD_END_ACK, mb,
1176 sw->cb_data, NULL);
1177 } else {
1178 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001179 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001180 sw->state = SW_STATE_ERROR;
1181 if (sw->cbfn)
1182 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1183 NM_MT_LOAD_END_NACK, mb,
1184 sw->cb_data, NULL);
1185 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001186 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001187 break;
1188 }
1189 case SW_STATE_WAIT_ACTACK:
1190 switch (foh->msg_type) {
1191 case NM_MT_ACTIVATE_SW_ACK:
1192 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001193 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001194 sw->state = SW_STATE_NONE;
1195 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001196 if (sw->cbfn)
1197 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1198 NM_MT_ACTIVATE_SW_ACK, mb,
1199 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001200 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001201 break;
1202 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001203 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001204 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001205 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001206 if (sw->cbfn)
1207 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1208 NM_MT_ACTIVATE_SW_NACK, mb,
1209 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001210 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001211 break;
1212 }
1213 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001214 switch (foh->msg_type) {
1215 case NM_MT_ACTIVATE_SW_ACK:
1216 rc = 0;
1217 break;
1218 }
1219 break;
Harald Welte4724f992009-01-18 18:01:49 +00001220 case SW_STATE_ERROR:
1221 break;
1222 }
1223
1224 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001225 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001226 foh->msg_type, old_state, sw->state);
1227
1228 return rc;
1229}
1230
1231/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001232int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001233 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001234 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001235{
1236 struct abis_nm_sw *sw = &g_sw;
1237 int rc;
1238
Harald Welte5e4d1b32009-02-01 13:36:56 +00001239 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1240 bts->nr, fname);
1241
Harald Welte4724f992009-01-18 18:01:49 +00001242 if (sw->state != SW_STATE_NONE)
1243 return -EBUSY;
1244
1245 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001246 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001247
1248 switch (bts->type) {
1249 case GSM_BTS_TYPE_BS11:
1250 sw->obj_class = NM_OC_SITE_MANAGER;
1251 sw->obj_instance[0] = 0xff;
1252 sw->obj_instance[1] = 0xff;
1253 sw->obj_instance[2] = 0xff;
1254 break;
1255 case GSM_BTS_TYPE_NANOBTS:
1256 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001257 sw->obj_instance[0] = sw->bts->nr;
1258 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001259 sw->obj_instance[2] = 0xff;
1260 break;
1261 case GSM_BTS_TYPE_UNKNOWN:
1262 default:
1263 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1264 return -1;
1265 break;
1266 }
Harald Welte4724f992009-01-18 18:01:49 +00001267 sw->window_size = win_size;
1268 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001269 sw->cbfn = cbfn;
1270 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001271 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001272
1273 rc = sw_open_file(sw, fname);
1274 if (rc < 0) {
1275 sw->state = SW_STATE_NONE;
1276 return rc;
1277 }
1278
1279 return sw_load_init(sw);
1280}
Harald Welte52b1f982008-12-23 20:25:15 +00001281
Harald Welte1602ade2009-01-29 21:12:39 +00001282int abis_nm_software_load_status(struct gsm_bts *bts)
1283{
1284 struct abis_nm_sw *sw = &g_sw;
1285 struct stat st;
1286 int rc, percent;
1287
1288 rc = fstat(sw->fd, &st);
1289 if (rc < 0) {
1290 perror("ERROR during stat");
1291 return rc;
1292 }
1293
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001294 if (sw->stream)
1295 percent = (ftell(sw->stream) * 100) / st.st_size;
1296 else
1297 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001298 return percent;
1299}
1300
Harald Welte5e4d1b32009-02-01 13:36:56 +00001301/* Activate the specified software into the BTS */
1302int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1303 gsm_cbfn *cbfn, void *cb_data)
1304{
1305 struct abis_nm_sw *sw = &g_sw;
1306 int rc;
1307
1308 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1309 bts->nr, fname);
1310
1311 if (sw->state != SW_STATE_NONE)
1312 return -EBUSY;
1313
1314 sw->bts = bts;
1315 sw->obj_class = NM_OC_SITE_MANAGER;
1316 sw->obj_instance[0] = 0xff;
1317 sw->obj_instance[1] = 0xff;
1318 sw->obj_instance[2] = 0xff;
1319 sw->state = SW_STATE_WAIT_ACTACK;
1320 sw->cbfn = cbfn;
1321 sw->cb_data = cb_data;
1322
1323 /* Open the file in order to fill some sw struct members */
1324 rc = sw_open_file(sw, fname);
1325 if (rc < 0) {
1326 sw->state = SW_STATE_NONE;
1327 return rc;
1328 }
1329 sw_close_file(sw);
1330
1331 return sw_activate(sw);
1332}
1333
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001334static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1335 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001336{
Harald Welteadaf08b2009-01-18 11:08:10 +00001337 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001338 ch->bts_port = bts_port;
1339 ch->timeslot = ts_nr;
1340 ch->subslot = subslot_nr;
1341}
1342
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001343int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1344 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1345 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001346{
1347 struct abis_om_hdr *oh;
1348 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001349 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001350 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001351
1352 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1353 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1354 bts->bts_nr, trx_nr, 0xff);
1355
Harald Welte8470bf22008-12-25 23:28:35 +00001356 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001357
1358 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1359 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1360
1361 return abis_nm_sendmsg(bts, msg);
1362}
1363
1364/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1365int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001366 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001367{
Harald Welte8470bf22008-12-25 23:28:35 +00001368 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001369 struct abis_om_hdr *oh;
1370 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001371 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001372
1373 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001374 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001375 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1376
1377 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1378 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1379
1380 return abis_nm_sendmsg(bts, msg);
1381}
1382
1383#if 0
1384int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1385 struct abis_nm_abis_channel *chan)
1386{
1387}
1388#endif
1389
1390int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001391 uint8_t e1_port, uint8_t e1_timeslot,
1392 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001393{
1394 struct gsm_bts *bts = ts->trx->bts;
1395 struct abis_om_hdr *oh;
1396 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001397 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001398
1399 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1400 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001401 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001402
1403 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1404 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1405
Harald Weltef325eb42009-02-19 17:07:39 +00001406 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1407 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001408 e1_port, e1_timeslot, e1_subslot);
1409
Harald Welte52b1f982008-12-23 20:25:15 +00001410 return abis_nm_sendmsg(bts, msg);
1411}
1412
1413#if 0
1414int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1415 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001416 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001417{
1418}
1419#endif
1420
Harald Weltefe568f22012-08-14 19:15:57 +02001421/* Chapter 8.11.1 */
1422int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1423 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1424 uint8_t *attr, uint8_t attr_len)
1425{
1426 struct abis_om_hdr *oh;
1427 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001428
1429 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1430
1431 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1432 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1433 bts_nr, trx_nr, ts_nr);
1434 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1435
1436 return abis_nm_sendmsg(bts, msg);
1437}
1438
Harald Welte22af0db2009-02-14 15:41:08 +00001439/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001440int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001441{
1442 struct abis_om_hdr *oh;
1443 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001444 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001445
1446 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1447
1448 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001449 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 +00001450 cur = msgb_put(msg, attr_len);
1451 memcpy(cur, attr, attr_len);
1452
1453 return abis_nm_sendmsg(bts, msg);
1454}
1455
1456/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001457int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001458{
1459 struct abis_om_hdr *oh;
1460 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001461 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001462
1463 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1464
1465 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1466 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001467 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001468 cur = msgb_put(msg, attr_len);
1469 memcpy(cur, attr, attr_len);
1470
1471 return abis_nm_sendmsg(trx->bts, msg);
1472}
1473
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001474int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1475{
1476 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1477 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1478}
1479
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001480static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1481 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001482{
1483 int i;
1484
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001485 *reason = "Reason unknown";
1486
Harald Welte39c7deb2009-08-09 21:49:48 +02001487 /* As it turns out, the BS-11 has some very peculiar restrictions
1488 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301489 switch (ts->trx->bts->type) {
1490 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001491 switch (chan_comb) {
1492 case NM_CHANC_TCHHalf:
1493 case NM_CHANC_TCHHalf2:
1494 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001495 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001496 return -EINVAL;
1497 case NM_CHANC_SDCCH:
1498 /* only one SDCCH/8 per TRX */
1499 for (i = 0; i < TRX_NR_TS; i++) {
1500 if (i == ts->nr)
1501 continue;
1502 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001503 NM_CHANC_SDCCH) {
1504 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001505 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001506 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001507 }
1508 /* not allowed for TS0 of BCCH-TRX */
1509 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001510 ts->nr == 0) {
1511 *reason = "SDCCH/8 must be on TS0.";
1512 return -EINVAL;
1513 }
1514
Harald Welte39c7deb2009-08-09 21:49:48 +02001515 /* not on the same TRX that has a BCCH+SDCCH4
1516 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001517 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001518 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001519 ts->trx->ts[0].nm_chan_comb == 8)) {
1520 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1521 return -EINVAL;
1522 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001523 break;
1524 case NM_CHANC_mainBCCH:
1525 case NM_CHANC_BCCHComb:
1526 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001527 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1528 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001529 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001530 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001531 break;
1532 case NM_CHANC_BCCH:
1533 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001534 if (ts->trx != ts->trx->bts->c0) {
1535 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001536 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001537 }
1538 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1539 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001540 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001541 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001542 break;
1543 case 8: /* this is not like 08.58, but in fact
1544 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1545 /* FIXME: only one CBCH allowed per cell */
1546 break;
1547 }
Harald Welted6575f92009-12-02 02:45:23 +05301548 break;
1549 case GSM_BTS_TYPE_NANOBTS:
1550 switch (ts->nr) {
1551 case 0:
1552 if (ts->trx->nr == 0) {
1553 /* only on TRX0 */
1554 switch (chan_comb) {
1555 case NM_CHANC_BCCH:
1556 case NM_CHANC_mainBCCH:
1557 case NM_CHANC_BCCHComb:
1558 return 0;
1559 break;
1560 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001561 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301562 return -EINVAL;
1563 }
1564 } else {
1565 switch (chan_comb) {
1566 case NM_CHANC_TCHFull:
1567 case NM_CHANC_TCHHalf:
1568 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1569 return 0;
1570 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001571 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301572 return -EINVAL;
1573 }
1574 }
1575 break;
1576 case 1:
1577 if (ts->trx->nr == 0) {
1578 switch (chan_comb) {
1579 case NM_CHANC_SDCCH_CBCH:
1580 if (ts->trx->ts[0].nm_chan_comb ==
1581 NM_CHANC_mainBCCH)
1582 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001583 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301584 return -EINVAL;
1585 case NM_CHANC_SDCCH:
1586 case NM_CHANC_TCHFull:
1587 case NM_CHANC_TCHHalf:
1588 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1589 case NM_CHANC_IPAC_TCHFull_PDCH:
1590 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001591 default:
1592 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1593 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301594 }
1595 } else {
1596 switch (chan_comb) {
1597 case NM_CHANC_SDCCH:
1598 case NM_CHANC_TCHFull:
1599 case NM_CHANC_TCHHalf:
1600 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1601 return 0;
1602 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001603 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301604 return -EINVAL;
1605 }
1606 }
1607 break;
1608 case 2:
1609 case 3:
1610 case 4:
1611 case 5:
1612 case 6:
1613 case 7:
1614 switch (chan_comb) {
1615 case NM_CHANC_TCHFull:
1616 case NM_CHANC_TCHHalf:
1617 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1618 return 0;
1619 case NM_CHANC_IPAC_PDCH:
1620 case NM_CHANC_IPAC_TCHFull_PDCH:
1621 if (ts->trx->nr == 0)
1622 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001623 else {
1624 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301625 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001626 }
Harald Welted6575f92009-12-02 02:45:23 +05301627 }
1628 break;
1629 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001630 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301631 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001632 case GSM_BTS_TYPE_OSMO_SYSMO:
1633 /* no known restrictions */
1634 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301635 default:
1636 /* unknown BTS type */
1637 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001638 }
1639 return 0;
1640}
1641
Harald Welte22af0db2009-02-14 15:41:08 +00001642/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001643int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001644{
1645 struct gsm_bts *bts = ts->trx->bts;
1646 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001647 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001648 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001649 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001650 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001651
1652 if (bts->type == GSM_BTS_TYPE_BS11)
1653 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001654
Harald Weltef325eb42009-02-19 17:07:39 +00001655 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001656 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001657 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001658 LOGP(DNM, LOGL_ERROR,
1659 "Invalid Channel Combination %d on %s. Reason: %s\n",
1660 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001661 return -EINVAL;
1662 }
1663 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001664
Harald Welte52b1f982008-12-23 20:25:15 +00001665 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001666 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001667 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001668 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001669 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001670 if (ts->hopping.enabled) {
1671 unsigned int i;
1672 uint8_t *len;
1673
Harald Welte6e0cd042009-09-12 13:05:33 +02001674 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1675 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001676
1677 /* build the ARFCN list */
1678 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1679 len = msgb_put(msg, 1);
1680 *len = 0;
1681 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1682 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1683 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001684 /* At least BS-11 wants a TLV16 here */
1685 if (bts->type == GSM_BTS_TYPE_BS11)
1686 *len += 1;
1687 else
1688 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001689 }
1690 }
Harald Weltee0590df2009-02-15 03:34:15 +00001691 }
Harald Welte1fe24122014-01-19 17:18:21 +01001692 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001693 if (bts->type == GSM_BTS_TYPE_BS11)
1694 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001695
1696 return abis_nm_sendmsg(bts, msg);
1697}
1698
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001699int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1700 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001701{
1702 struct abis_om_hdr *oh;
1703 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001704 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1705 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001706
1707 if (nack) {
1708 len += 2;
1709 msgtype = NM_MT_SW_ACT_REQ_NACK;
1710 }
Harald Welte34a99682009-02-13 02:41:40 +00001711
1712 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001713 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1714
Harald Welte34a99682009-02-13 02:41:40 +00001715 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001716 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001717 memcpy(ptr, attr, att_len);
1718 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001719 if (nack)
1720 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001721
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001722 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001723}
1724
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001725int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001726{
Harald Welte8470bf22008-12-25 23:28:35 +00001727 struct msgb *msg = nm_msgb_alloc();
1728 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001729 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001730
1731 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1732 fill_om_hdr(oh, len);
1733 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001734 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001735
1736 return abis_nm_sendmsg(bts, msg);
1737}
1738
1739/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001740static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001741{
1742 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001743 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001744
1745 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001746 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001747 0xff, 0xff, 0xff);
1748
1749 return abis_nm_sendmsg(bts, msg);
1750}
1751
Harald Welte34a99682009-02-13 02:41:40 +00001752/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001753int 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 +00001754{
1755 struct abis_om_hdr *oh;
1756 struct msgb *msg = nm_msgb_alloc();
1757
1758 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1759 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1760
Harald Welte15c61722011-05-22 22:45:37 +02001761 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001762 DEBUGPC(DNM, "Sending OPSTART\n");
1763
Harald Welte34a99682009-02-13 02:41:40 +00001764 return abis_nm_sendmsg(bts, msg);
1765}
1766
1767/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001768int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1769 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001770{
1771 struct abis_om_hdr *oh;
1772 struct msgb *msg = nm_msgb_alloc();
1773
1774 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1775 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1776 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1777
1778 return abis_nm_sendmsg(bts, msg);
1779}
1780
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001781int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1782 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001783{
1784 struct abis_om_hdr *oh;
1785 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001786 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001787
1788 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1789 e1_port0, ts0, e1_port1, ts1);
1790
1791 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1792 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1793 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1794
1795 attr = msgb_put(msg, 3);
1796 attr[0] = NM_ATT_MDROP_LINK;
1797 attr[1] = e1_port0;
1798 attr[2] = ts0;
1799
1800 attr = msgb_put(msg, 3);
1801 attr[0] = NM_ATT_MDROP_NEXT;
1802 attr[1] = e1_port1;
1803 attr[2] = ts1;
1804
1805 return abis_nm_sendmsg(bts, msg);
1806}
Harald Welte34a99682009-02-13 02:41:40 +00001807
Harald Weltec7310382009-08-08 00:02:36 +02001808/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001809int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1810 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1811 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001812{
1813 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001814
Harald Welte15c61722011-05-22 22:45:37 +02001815 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001816
1817 if (!msg)
1818 msg = nm_msgb_alloc();
1819
1820 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1821 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1822 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1823 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001824 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001825
1826 return abis_nm_sendmsg(bts, msg);
1827}
1828
Harald Welte52b1f982008-12-23 20:25:15 +00001829int abis_nm_event_reports(struct gsm_bts *bts, int on)
1830{
1831 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001832 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001833 else
Harald Welte227d4072009-01-03 08:16:25 +00001834 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001835}
1836
Harald Welte47d88ae2009-01-04 12:02:08 +00001837/* Siemens (or BS-11) specific commands */
1838
Harald Welte3ffd1372009-02-01 22:15:49 +00001839int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1840{
1841 if (reconnect == 0)
1842 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1843 else
1844 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1845}
1846
Harald Welteb8427972009-02-05 19:27:17 +00001847int abis_nm_bs11_restart(struct gsm_bts *bts)
1848{
1849 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1850}
1851
1852
Harald Welte268bb402009-02-01 19:11:56 +00001853struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001854 uint16_t year;
1855 uint8_t month;
1856 uint8_t day;
1857 uint8_t hour;
1858 uint8_t min;
1859 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001860} __attribute__((packed));
1861
1862
1863void get_bs11_date_time(struct bs11_date_time *aet)
1864{
1865 time_t t;
1866 struct tm *tm;
1867
1868 t = time(NULL);
1869 tm = localtime(&t);
1870 aet->sec = tm->tm_sec;
1871 aet->min = tm->tm_min;
1872 aet->hour = tm->tm_hour;
1873 aet->day = tm->tm_mday;
1874 aet->month = tm->tm_mon;
1875 aet->year = htons(1900 + tm->tm_year);
1876}
1877
Harald Welte05188ee2009-01-18 11:39:08 +00001878int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001879{
Harald Welte4668fda2009-01-03 08:19:29 +00001880 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001881}
1882
Harald Welte05188ee2009-01-18 11:39:08 +00001883int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001884{
1885 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001886 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001887 else
Harald Welte4668fda2009-01-03 08:19:29 +00001888 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001889}
Harald Welte47d88ae2009-01-04 12:02:08 +00001890
Harald Welte05188ee2009-01-18 11:39:08 +00001891int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001892 enum abis_bs11_objtype type, uint8_t idx,
1893 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001894{
1895 struct abis_om_hdr *oh;
1896 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001897 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001898
1899 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001900 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001901 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001902 cur = msgb_put(msg, attr_len);
1903 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001904
1905 return abis_nm_sendmsg(bts, msg);
1906}
1907
Harald Welte78fc0d42009-02-19 02:50:57 +00001908int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001909 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001910{
1911 struct abis_om_hdr *oh;
1912 struct msgb *msg = nm_msgb_alloc();
1913
1914 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1915 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1916 NM_OC_BS11, type, 0, idx);
1917
1918 return abis_nm_sendmsg(bts, msg);
1919}
1920
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001921int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001922{
1923 struct abis_om_hdr *oh;
1924 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001925 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001926
1927 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001928 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001929 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1930 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001931
1932 return abis_nm_sendmsg(bts, msg);
1933}
1934
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001935int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001936{
1937 struct abis_om_hdr *oh;
1938 struct msgb *msg = nm_msgb_alloc();
1939
1940 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1941 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001942 idx, 0xff, 0xff);
1943
1944 return abis_nm_sendmsg(bts, msg);
1945}
1946
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001947int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001948{
1949 struct abis_om_hdr *oh;
1950 struct msgb *msg = nm_msgb_alloc();
1951
1952 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1953 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1954 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001955
1956 return abis_nm_sendmsg(bts, msg);
1957}
Harald Welte05188ee2009-01-18 11:39:08 +00001958
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001959static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001960int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1961{
1962 struct abis_om_hdr *oh;
1963 struct msgb *msg = nm_msgb_alloc();
1964
1965 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1966 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1967 0xff, 0xff, 0xff);
1968 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1969
1970 return abis_nm_sendmsg(bts, msg);
1971}
1972
Harald Welteb6c92ae2009-02-21 20:15:32 +00001973/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001974int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1975 uint8_t e1_timeslot, uint8_t e1_subslot,
1976 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001977{
1978 struct abis_om_hdr *oh;
1979 struct abis_nm_channel *ch;
1980 struct msgb *msg = nm_msgb_alloc();
1981
1982 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001983 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001984 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1985
1986 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1987 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001988 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001989
1990 return abis_nm_sendmsg(bts, msg);
1991}
1992
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001993int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001994{
1995 struct abis_om_hdr *oh;
1996 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001997
1998 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001999 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002000 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2001 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2002
2003 return abis_nm_sendmsg(trx->bts, msg);
2004}
2005
Harald Welte78fc0d42009-02-19 02:50:57 +00002006int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2007{
2008 struct abis_om_hdr *oh;
2009 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002010 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002011
2012 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2013 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2014 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2015 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2016
2017 return abis_nm_sendmsg(trx->bts, msg);
2018}
2019
Harald Welteaaf02d92009-04-29 13:25:57 +00002020int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2021{
2022 struct abis_om_hdr *oh;
2023 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002024 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002025
2026 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2027 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2028 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002029 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002030
2031 return abis_nm_sendmsg(bts, msg);
2032}
2033
Harald Welteef061952009-05-17 12:43:42 +00002034int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2035{
2036 struct abis_om_hdr *oh;
2037 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002038 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002039 NM_ATT_BS11_CCLK_TYPE };
2040
2041 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2042 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2043 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2044 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2045
2046 return abis_nm_sendmsg(bts, msg);
2047
2048}
Harald Welteaaf02d92009-04-29 13:25:57 +00002049
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002050//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002051
Harald Welte1bc09062009-01-18 14:17:52 +00002052int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002053{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002054 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2055}
2056
Daniel Willmann4b054c82010-01-07 00:46:26 +01002057int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2058{
2059 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2060}
2061
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002062int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002063{
Harald Welte05188ee2009-01-18 11:39:08 +00002064 struct abis_om_hdr *oh;
2065 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002066 struct bs11_date_time bdt;
2067
2068 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002069
2070 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002071 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002072 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002073 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002074 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002075 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002076 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002077 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002078 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002079 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002080 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002081 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002082 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002083 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002084 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002085 }
Harald Welte05188ee2009-01-18 11:39:08 +00002086
2087 return abis_nm_sendmsg(bts, msg);
2088}
Harald Welte1bc09062009-01-18 14:17:52 +00002089
2090int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2091{
2092 struct abis_om_hdr *oh;
2093 struct msgb *msg;
2094
2095 if (strlen(password) != 10)
2096 return -EINVAL;
2097
2098 msg = nm_msgb_alloc();
2099 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002100 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002101 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002102 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002103
2104 return abis_nm_sendmsg(bts, msg);
2105}
2106
Harald Weltee69f5fb2009-04-28 16:31:38 +00002107/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2108int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2109{
2110 struct abis_om_hdr *oh;
2111 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002112 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002113
2114 msg = nm_msgb_alloc();
2115 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2116 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2117 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002118
2119 if (locked)
2120 tlv_value = BS11_LI_PLL_LOCKED;
2121 else
2122 tlv_value = BS11_LI_PLL_STANDALONE;
2123
2124 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002125
2126 return abis_nm_sendmsg(bts, msg);
2127}
2128
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002129/* Set the calibration value of the PLL (work value/set value)
2130 * It depends on the login which one is changed */
2131int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2132{
2133 struct abis_om_hdr *oh;
2134 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002135 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002136
2137 msg = nm_msgb_alloc();
2138 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2139 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2140 BS11_OBJ_TRX1, 0x00, 0x00);
2141
2142 tlv_value[0] = value>>8;
2143 tlv_value[1] = value&0xff;
2144
2145 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2146
2147 return abis_nm_sendmsg(bts, msg);
2148}
2149
Harald Welte1bc09062009-01-18 14:17:52 +00002150int abis_nm_bs11_get_state(struct gsm_bts *bts)
2151{
2152 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2153}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002154
2155/* BS11 SWL */
2156
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002157void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002158
Harald Welte5e4d1b32009-02-01 13:36:56 +00002159struct abis_nm_bs11_sw {
2160 struct gsm_bts *bts;
2161 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002162 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002163 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002164 struct llist_head file_list;
2165 gsm_cbfn *user_cb; /* specified by the user */
2166};
2167static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2168
2169struct file_list_entry {
2170 struct llist_head list;
2171 char fname[PATH_MAX];
2172};
2173
2174struct file_list_entry *fl_dequeue(struct llist_head *queue)
2175{
2176 struct llist_head *lh;
2177
2178 if (llist_empty(queue))
2179 return NULL;
2180
2181 lh = queue->next;
2182 llist_del(lh);
2183
2184 return llist_entry(lh, struct file_list_entry, list);
2185}
2186
2187static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2188{
2189 char linebuf[255];
2190 struct llist_head *lh, *lh2;
2191 FILE *swl;
2192 int rc = 0;
2193
2194 swl = fopen(bs11_sw->swl_fname, "r");
2195 if (!swl)
2196 return -ENODEV;
2197
2198 /* zero the stale file list, if any */
2199 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2200 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002201 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002202 }
2203
2204 while (fgets(linebuf, sizeof(linebuf), swl)) {
2205 char file_id[12+1];
2206 char file_version[80+1];
2207 struct file_list_entry *fle;
2208 static char dir[PATH_MAX];
2209
2210 if (strlen(linebuf) < 4)
2211 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002212
Harald Welte5e4d1b32009-02-01 13:36:56 +00002213 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2214 if (rc < 0) {
2215 perror("ERR parsing SWL file");
2216 rc = -EINVAL;
2217 goto out;
2218 }
2219 if (rc < 2)
2220 continue;
2221
Harald Welte470ec292009-06-26 20:25:23 +02002222 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002223 if (!fle) {
2224 rc = -ENOMEM;
2225 goto out;
2226 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002227
2228 /* construct new filename */
2229 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2230 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2231 strcat(fle->fname, "/");
2232 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002233
2234 llist_add_tail(&fle->list, &bs11_sw->file_list);
2235 }
2236
2237out:
2238 fclose(swl);
2239 return rc;
2240}
2241
2242/* bs11 swload specific callback, passed to abis_nm core swload */
2243static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2244 struct msgb *msg, void *data, void *param)
2245{
2246 struct abis_nm_bs11_sw *bs11_sw = data;
2247 struct file_list_entry *fle;
2248 int rc = 0;
2249
Harald Welte5e4d1b32009-02-01 13:36:56 +00002250 switch (event) {
2251 case NM_MT_LOAD_END_ACK:
2252 fle = fl_dequeue(&bs11_sw->file_list);
2253 if (fle) {
2254 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002255 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002256 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002257 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002258 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002259 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002260 } else {
2261 /* activate the SWL */
2262 rc = abis_nm_software_activate(bs11_sw->bts,
2263 bs11_sw->swl_fname,
2264 bs11_swload_cbfn,
2265 bs11_sw);
2266 }
2267 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002268 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002269 case NM_MT_LOAD_END_NACK:
2270 case NM_MT_LOAD_INIT_ACK:
2271 case NM_MT_LOAD_INIT_NACK:
2272 case NM_MT_ACTIVATE_SW_NACK:
2273 case NM_MT_ACTIVATE_SW_ACK:
2274 default:
2275 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002276 if (bs11_sw->user_cb)
2277 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002278 break;
2279 }
2280
2281 return rc;
2282}
2283
2284/* Siemens provides a SWL file that is a mere listing of all the other
2285 * files that are part of a software release. We need to upload first
2286 * the list file, and then each file that is listed in the list file */
2287int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002288 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002289{
2290 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2291 struct file_list_entry *fle;
2292 int rc = 0;
2293
2294 INIT_LLIST_HEAD(&bs11_sw->file_list);
2295 bs11_sw->bts = bts;
2296 bs11_sw->win_size = win_size;
2297 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002298 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002299
2300 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2301 rc = bs11_read_swl_file(bs11_sw);
2302 if (rc < 0)
2303 return rc;
2304
2305 /* dequeue next item in file list */
2306 fle = fl_dequeue(&bs11_sw->file_list);
2307 if (!fle)
2308 return -EINVAL;
2309
2310 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002311 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002312 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002313 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002314 return rc;
2315}
2316
Harald Welte5083b0b2009-02-02 19:20:52 +00002317#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002318static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002319 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2320 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2321 NM_ATT_BS11_LMT_USER_NAME,
2322
2323 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2324
2325 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2326
2327 NM_ATT_BS11_SW_LOAD_STORED };
2328
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002329static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002330 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2331 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2332 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2333 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002334#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002335
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002336static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002337 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2338 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002339 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002340
2341int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2342{
2343 struct abis_om_hdr *oh;
2344 struct msgb *msg = nm_msgb_alloc();
2345
2346 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2347 /* SiemensHW CCTRL object */
2348 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2349 0x03, 0x00, 0x00);
2350 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2351
2352 return abis_nm_sendmsg(bts, msg);
2353}
Harald Welte268bb402009-02-01 19:11:56 +00002354
2355int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2356{
2357 struct abis_om_hdr *oh;
2358 struct msgb *msg = nm_msgb_alloc();
2359 struct bs11_date_time aet;
2360
2361 get_bs11_date_time(&aet);
2362 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2363 /* SiemensHW CCTRL object */
2364 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2365 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002366 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002367
2368 return abis_nm_sendmsg(bts, msg);
2369}
Harald Welte5c1e4582009-02-15 11:57:29 +00002370
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002371int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002372{
2373 struct abis_om_hdr *oh;
2374 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002375 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002376
2377 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2378 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2379 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2380 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2381
2382 return abis_nm_sendmsg(bts, msg);
2383}
2384
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002385int 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 +02002386{
2387 struct abis_om_hdr *oh;
2388 struct msgb *msg = nm_msgb_alloc();
2389 struct bs11_date_time aet;
2390
2391 get_bs11_date_time(&aet);
2392 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2393 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2394 bport, 0xff, 0x02);
2395 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2396
2397 return abis_nm_sendmsg(bts, msg);
2398}
2399
Harald Welte5c1e4582009-02-15 11:57:29 +00002400/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002401static const char ipaccess_magic[] = "com.ipaccess";
2402
Harald Welte677c21f2009-02-17 13:22:23 +00002403
2404static int abis_nm_rx_ipacc(struct msgb *msg)
2405{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002406 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002407 struct abis_om_hdr *oh = msgb_l2(msg);
2408 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002409 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002410 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002411 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002412 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002413
2414 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002415 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002416 return -EINVAL;
2417 }
2418
Harald Welte193fefc2009-04-30 15:16:27 +00002419 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002420 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002421
Harald Welte15c61722011-05-22 22:45:37 +02002422 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002423
Harald Welte746d6092009-10-19 22:11:11 +02002424 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002425
Harald Welte677c21f2009-02-17 13:22:23 +00002426 switch (foh->msg_type) {
2427 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002428 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002429 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2430 memcpy(&addr,
2431 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2432
2433 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2434 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002435 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002436 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002437 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002438 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002439 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2440 DEBUGPC(DNM, "STREAM=0x%02x ",
2441 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002442 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002443 break;
2444 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002445 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002446 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002447 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002448 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002449 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002450 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002451 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002452 case NM_MT_IPACC_SET_NVATTR_ACK:
2453 DEBUGPC(DNM, "SET NVATTR ACK\n");
2454 /* FIXME: decode and show the actual attributes */
2455 break;
2456 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002457 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002458 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002459 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002460 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002461 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002462 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002463 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002464 case NM_MT_IPACC_GET_NVATTR_ACK:
2465 DEBUGPC(DNM, "GET NVATTR ACK\n");
2466 /* FIXME: decode and show the actual attributes */
2467 break;
2468 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002469 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002470 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002471 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002472 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002473 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002474 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002475 break;
Harald Welte15c44172009-10-08 20:15:24 +02002476 case NM_MT_IPACC_SET_ATTR_ACK:
2477 DEBUGPC(DNM, "SET ATTR ACK\n");
2478 break;
2479 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002480 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002481 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002482 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002483 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002484 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002485 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002486 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002487 default:
2488 DEBUGPC(DNM, "unknown\n");
2489 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002490 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002491
2492 /* signal handling */
2493 switch (foh->msg_type) {
2494 case NM_MT_IPACC_RSL_CONNECT_NACK:
2495 case NM_MT_IPACC_SET_NVATTR_NACK:
2496 case NM_MT_IPACC_GET_NVATTR_NACK:
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_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002500 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002501 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002502 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 +01002503 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002504 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002505 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002506 default:
2507 break;
2508 }
2509
Harald Welte677c21f2009-02-17 13:22:23 +00002510 return 0;
2511}
2512
Harald Welte193fefc2009-04-30 15:16:27 +00002513/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002514int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2515 uint8_t obj_class, uint8_t bts_nr,
2516 uint8_t trx_nr, uint8_t ts_nr,
2517 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002518{
2519 struct msgb *msg = nm_msgb_alloc();
2520 struct abis_om_hdr *oh;
2521 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002522 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002523
2524 /* construct the 12.21 OM header, observe the erroneous length */
2525 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2526 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2527 oh->mdisc = ABIS_OM_MDISC_MANUF;
2528
2529 /* add the ip.access magic */
2530 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2531 *data++ = sizeof(ipaccess_magic);
2532 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2533
2534 /* fill the 12.21 FOM header */
2535 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2536 foh->msg_type = msg_type;
2537 foh->obj_class = obj_class;
2538 foh->obj_inst.bts_nr = bts_nr;
2539 foh->obj_inst.trx_nr = trx_nr;
2540 foh->obj_inst.ts_nr = ts_nr;
2541
2542 if (attr && attr_len) {
2543 data = msgb_put(msg, attr_len);
2544 memcpy(data, attr, attr_len);
2545 }
2546
2547 return abis_nm_sendmsg(bts, msg);
2548}
Harald Welte677c21f2009-02-17 13:22:23 +00002549
Harald Welte193fefc2009-04-30 15:16:27 +00002550/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002551int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002552 int attr_len)
2553{
Harald Welte2ef156d2010-01-07 20:39:42 +01002554 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2555 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002556 attr_len);
2557}
2558
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002559int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002560 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002561{
2562 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002563 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002564 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2565 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2566
2567 int attr_len = sizeof(attr);
2568
2569 ia.s_addr = htonl(ip);
2570 attr[1] = stream;
2571 attr[3] = port >> 8;
2572 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002573 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002574
2575 /* if ip == 0, we use the default IP */
2576 if (ip == 0)
2577 attr_len -= 5;
2578
2579 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002580 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002581
2582 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2583 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2584 trx->nr, 0xff, attr, attr_len);
2585}
2586
Harald Welte193fefc2009-04-30 15:16:27 +00002587/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002588int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002589{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002590 struct abis_om_hdr *oh;
2591 struct msgb *msg = nm_msgb_alloc();
2592
2593 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2594 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2595 trx->bts->nr, trx->nr, 0xff);
2596
2597 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002598}
Harald Weltedaef5212009-10-24 10:20:41 +02002599
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002600int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2601 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2602 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002603{
2604 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2605 obj_class, bts_nr, trx_nr, ts_nr,
2606 attr, attr_len);
2607}
Harald Welte0f255852009-11-12 14:48:42 +01002608
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002609void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002610{
2611 /* we simply reuse the GSM48 function and overwrite the RAC
2612 * with the Cell ID */
2613 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002614 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002615}
2616
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002617void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2618{
2619 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2620
Harald Welted64c0bc2011-05-30 12:07:53 +02002621 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002622 if (!trx->bts || !trx->bts->oml_link)
2623 return;
2624
2625 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2626 trx->bts->bts_nr, trx->nr, 0xff,
2627 new_state);
2628}
2629
Harald Welte92b1fe42010-03-25 11:45:30 +08002630static const struct value_string ipacc_testres_names[] = {
2631 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2632 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2633 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2634 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2635 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2636 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002637};
2638
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002639const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002640{
Harald Welte92b1fe42010-03-25 11:45:30 +08002641 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002642}
2643
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002644void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002645{
2646 cid->mcc = (buf[0] & 0xf) * 100;
2647 cid->mcc += (buf[0] >> 4) * 10;
2648 cid->mcc += (buf[1] & 0xf) * 1;
2649
2650 if (buf[1] >> 4 == 0xf) {
2651 cid->mnc = (buf[2] & 0xf) * 10;
2652 cid->mnc += (buf[2] >> 4) * 1;
2653 } else {
2654 cid->mnc = (buf[2] & 0xf) * 100;
2655 cid->mnc += (buf[2] >> 4) * 10;
2656 cid->mnc += (buf[1] >> 4) * 1;
2657 }
2658
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002659 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2660 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002661}
2662
Harald Welte0f255852009-11-12 14:48:42 +01002663/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002664int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002665{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002666 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002667 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002668
Harald Welteaf109b92010-07-22 18:14:36 +02002669 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002670
2671 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2672 return -EINVAL;
2673 cur++;
2674
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002675 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002676 cur += 2;
2677
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002678 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002679 cur += 2;
2680
2681 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2682 binf->freq_qual = *cur >> 2;
2683
Harald Welteaf109b92010-07-22 18:14:36 +02002684 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002685 binf->arfcn |= *cur++;
2686
2687 if (binf->info_type & IPAC_BINF_RXLEV)
2688 binf->rx_lev = *cur & 0x3f;
2689 cur++;
2690
2691 if (binf->info_type & IPAC_BINF_RXQUAL)
2692 binf->rx_qual = *cur & 0x7;
2693 cur++;
2694
2695 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002696 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002697 cur += 2;
2698
2699 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002700 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002701 cur += 2;
2702
2703 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002704 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002705 cur += 4;
2706
Harald Weltea780a3d2010-07-30 22:34:42 +02002707#if 0
2708 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002709 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002710#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002711 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002712 cur++;
2713
Harald Welteb40a38f2009-11-13 11:56:05 +01002714 ipac_parse_cgi(&binf->cgi, cur);
2715 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002716
2717 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2718 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2719 cur += sizeof(binf->ba_list_si2);
2720 }
2721
2722 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2723 memcpy(binf->ba_list_si2bis, cur,
2724 sizeof(binf->ba_list_si2bis));
2725 cur += sizeof(binf->ba_list_si2bis);
2726 }
2727
2728 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2729 memcpy(binf->ba_list_si2ter, cur,
2730 sizeof(binf->ba_list_si2ter));
2731 cur += sizeof(binf->ba_list_si2ter);
2732 }
2733
2734 return 0;
2735}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002736
2737void abis_nm_clear_queue(struct gsm_bts *bts)
2738{
2739 struct msgb *msg;
2740
2741 while (!llist_empty(&bts->abis_queue)) {
2742 msg = msgb_dequeue(&bts->abis_queue);
2743 msgb_free(msg);
2744 }
2745
2746 bts->abis_nm_pend = 0;
2747}