blob: e95c0a9058f40175819ec96640d1d33be00d2919 [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 Freytherc42ad8b2011-04-18 17:04:00 +0200362static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100363{
364 static const struct tlv_definition sw_descr_def = {
365 .def = {
366 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
367 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
368 },
369 };
370
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200371 uint8_t tag;
372 uint16_t tag_len;
373 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100374 int ofs = 0, len;
375
376 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
377 * nested nature and the fact you have to assume it contains only two sub
378 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
379
380 if (sw_descr[0] != NM_ATT_SW_DESCR) {
381 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
382 return -1;
383 }
384 ofs += 1;
385
386 len = tlv_parse_one(&tag, &tag_len, &val,
387 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
388 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
389 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
390 return -2;
391 }
392 ofs += len;
393
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
396 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
397 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
398 return -3;
399 }
400 ofs += len;
401
402 return ofs;
403}
404
Harald Welte34a99682009-02-13 02:41:40 +0000405static int abis_nm_rx_sw_act_req(struct msgb *mb)
406{
407 struct abis_om_hdr *oh = msgb_l2(mb);
408 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200409 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200410 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200411 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100412 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000413
Harald Welte15c61722011-05-22 22:45:37 +0200414 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200415
416 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000417
Harald Welte97a282b2010-03-14 15:37:43 +0800418 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000419
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200420 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000421 foh->obj_inst.bts_nr,
422 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800423 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000424 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100425 if (ret != 0) {
426 LOGP(DNM, LOGL_ERROR,
427 "Sending SW ActReq ACK failed: %d\n", ret);
428 return ret;
429 }
Harald Welte34a99682009-02-13 02:41:40 +0000430
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200431 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200432 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
433 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
434 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100435 LOGP(DNM, LOGL_ERROR,
436 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200437 return -EINVAL;
438 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200439 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200440 }
441
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100442 /* Use the first SW_DESCR present in SW config */
443 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
444 if (sw_descr_len < 0)
445 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200446
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200447 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000448 foh->obj_inst.bts_nr,
449 foh->obj_inst.trx_nr,
450 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100451 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000452}
453
Harald Weltee0590df2009-02-15 03:34:15 +0000454/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
455static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
456{
457 struct abis_om_hdr *oh = msgb_l2(mb);
458 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200459 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000460 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200461 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000462
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200463 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000464 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
465 return -EINVAL;
466
467 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
468
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200469 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000470}
471
Harald Welteee670472009-02-22 21:58:49 +0000472static int abis_nm_rx_lmt_event(struct msgb *mb)
473{
474 struct abis_om_hdr *oh = msgb_l2(mb);
475 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200476 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000477 struct tlv_parsed tp;
478
479 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200480 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000481 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
482 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200483 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000484 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
485 }
486 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
487 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200488 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000489 DEBUGPC(DNM, "Level=%u ", level);
490 }
491 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
492 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
493 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
494 DEBUGPC(DNM, "Username=%s ", name);
495 }
496 DEBUGPC(DNM, "\n");
497 /* FIXME: parse LMT LOGON TIME */
498 return 0;
499}
500
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200501void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100502{
503 int wait = 0;
504 struct msgb *msg;
505 /* the queue is empty */
506 while (!llist_empty(&bts->abis_queue)) {
507 msg = msgb_dequeue(&bts->abis_queue);
508 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200509 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100510
511 if (wait)
512 break;
513 }
514
515 bts->abis_nm_pend = wait;
516}
517
Harald Welte52b1f982008-12-23 20:25:15 +0000518/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000519static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000520{
Harald Welte6c96ba52009-05-01 13:03:40 +0000521 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000522 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200523 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200524 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100525 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000526
527 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000528 if (is_report(mt))
529 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000530
Harald Welte15c61722011-05-22 22:45:37 +0200531 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000532 return abis_nm_rcvmsg_sw(mb);
533
Harald Welte15c61722011-05-22 22:45:37 +0200534 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800535 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000536 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200537
Harald Welte15c61722011-05-22 22:45:37 +0200538 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200539
Harald Welte15c61722011-05-22 22:45:37 +0200540 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000541
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200542 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000543 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200544 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200545 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000546 else
547 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200548
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800549 nack_data.msg = mb;
550 nack_data.mt = mt;
Holger Hans Peter Freytherde1674a2012-11-11 18:26:23 +0100551 nack_data.bts = sign_link->trx->bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200552 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200553 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200554 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000555 }
Harald Weltead384642008-12-26 10:20:07 +0000556#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000557 /* check if last message is to be acked */
558 if (is_ack_nack(nmh->last_msgtype)) {
559 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100560 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000561 /* we got our ACK, continue sending the next msg */
562 } else if (mt == MT_NACK(nmh->last_msgtype)) {
563 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100564 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000565 /* FIXME: somehow signal this to the caller */
566 } else {
567 /* really strange things happen */
568 return -EINVAL;
569 }
570 }
Harald Weltead384642008-12-26 10:20:07 +0000571#endif
572
Harald Welte97ed1e72009-02-06 13:38:02 +0000573 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000574 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100575 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000576 break;
Harald Welte34a99682009-02-13 02:41:40 +0000577 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100578 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000579 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000580 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100581 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000582 break;
Harald Welte1989c082009-08-06 17:58:31 +0200583 case NM_MT_CONN_MDROP_LINK_ACK:
584 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
585 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100586 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200587 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100588 break;
589 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200590 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100591 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100592 case NM_MT_SET_BTS_ATTR_ACK:
593 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200594 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
595 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Weltefd355a32011-03-04 13:41:31 +0100596 }
597 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000598 }
599
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200600 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100601 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000602}
603
Harald Welte677c21f2009-02-17 13:22:23 +0000604static int abis_nm_rx_ipacc(struct msgb *mb);
605
606static int abis_nm_rcvmsg_manuf(struct msgb *mb)
607{
608 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200609 struct e1inp_sign_link *sign_link = mb->dst;
610 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000611
612 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100613 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200614 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000615 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200616 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000617 break;
618 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100619 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
620 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000621 rc = 0;
622 break;
623 }
624
625 return rc;
626}
627
Harald Welte52b1f982008-12-23 20:25:15 +0000628/* High-Level API */
629/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000630int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000631{
Harald Welte52b1f982008-12-23 20:25:15 +0000632 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000633 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000634
635 /* Various consistency checks */
636 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100637 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000638 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200639 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
640 rc = -EINVAL;
641 goto err;
642 }
Harald Welte52b1f982008-12-23 20:25:15 +0000643 }
644 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100645 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000646 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200647 rc = -EINVAL;
648 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000649 }
Harald Welte702d8702008-12-26 20:25:35 +0000650#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200651 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000652 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000653 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100654 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000655 oh->length + sizeof(*oh), l2_len);
656 return -EINVAL;
657 }
Harald Welte702d8702008-12-26 20:25:35 +0000658 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100659 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 +0000660#endif
Harald Weltead384642008-12-26 10:20:07 +0000661 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000662
663 switch (oh->mdisc) {
664 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000665 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000666 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000667 case ABIS_OM_MDISC_MANUF:
668 rc = abis_nm_rcvmsg_manuf(msg);
669 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000670 case ABIS_OM_MDISC_MMI:
671 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100672 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000673 oh->mdisc);
674 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000675 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100676 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000677 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200678 rc = -EINVAL;
679 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000680 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200681err:
Harald Weltead384642008-12-26 10:20:07 +0000682 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000683 return rc;
684}
685
686#if 0
687/* initialized all resources */
688struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
689{
690 struct abis_nm_h *nmh;
691
692 nmh = malloc(sizeof(*nmh));
693 if (!nmh)
694 return NULL;
695
696 nmh->cfg = cfg;
697
698 return nmh;
699}
700
701/* free all resources */
702void abis_nm_fini(struct abis_nm_h *nmh)
703{
704 free(nmh);
705}
706#endif
707
708/* Here we are trying to define a high-level API that can be used by
709 * the actual BSC implementation. However, the architecture is currently
710 * still under design. Ideally the calls to this API would be synchronous,
711 * while the underlying stack behind the APi runs in a traditional select
712 * based state machine.
713 */
714
Harald Welte4724f992009-01-18 18:01:49 +0000715/* 6.2 Software Load: */
716enum sw_state {
717 SW_STATE_NONE,
718 SW_STATE_WAIT_INITACK,
719 SW_STATE_WAIT_SEGACK,
720 SW_STATE_WAIT_ENDACK,
721 SW_STATE_WAIT_ACTACK,
722 SW_STATE_ERROR,
723};
Harald Welte52b1f982008-12-23 20:25:15 +0000724
Harald Welte52b1f982008-12-23 20:25:15 +0000725struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000726 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800727 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000728 gsm_cbfn *cbfn;
729 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000730 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000731
Harald Welte52b1f982008-12-23 20:25:15 +0000732 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200733 uint8_t obj_class;
734 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000735
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200736 uint8_t file_id[255];
737 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000738
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200739 uint8_t file_version[255];
740 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000741
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200742 uint8_t window_size;
743 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000744
745 int fd;
746 FILE *stream;
747 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000748 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000749};
750
Harald Welte4724f992009-01-18 18:01:49 +0000751static struct abis_nm_sw g_sw;
752
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100753static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
754{
755 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
756 msgb_v_put(msg, NM_ATT_SW_DESCR);
757 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
758 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
759 sw->file_version);
760 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
761 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
762 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
763 sw->file_version);
764 } else {
765 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
766 }
767}
768
Harald Welte4724f992009-01-18 18:01:49 +0000769/* 6.2.1 / 8.3.1: Load Data Initiate */
770static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000771{
Harald Welte4724f992009-01-18 18:01:49 +0000772 struct abis_om_hdr *oh;
773 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200774 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000775
776 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
777 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
778 sw->obj_instance[0], sw->obj_instance[1],
779 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100780
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100781 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000782 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
783
784 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000785}
786
Harald Welte1602ade2009-01-29 21:12:39 +0000787static int is_last_line(FILE *stream)
788{
789 char next_seg_buf[256];
790 long pos;
791
792 /* check if we're sending the last line */
793 pos = ftell(stream);
794 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
795 fseek(stream, pos, SEEK_SET);
796 return 1;
797 }
798
799 fseek(stream, pos, SEEK_SET);
800 return 0;
801}
802
Harald Welte4724f992009-01-18 18:01:49 +0000803/* 6.2.2 / 8.3.2 Load Data Segment */
804static int sw_load_segment(struct abis_nm_sw *sw)
805{
806 struct abis_om_hdr *oh;
807 struct msgb *msg = nm_msgb_alloc();
808 char seg_buf[256];
809 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000810 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200811 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000812
813 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000814
815 switch (sw->bts->type) {
816 case GSM_BTS_TYPE_BS11:
817 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
818 perror("fgets reading segment");
819 return -EINVAL;
820 }
821 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000822
823 /* check if we're sending the last line */
824 sw->last_seg = is_last_line(sw->stream);
825 if (sw->last_seg)
826 seg_buf[1] = 0;
827 else
828 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000829
830 len = strlen(line_buf) + 2;
831 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200832 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000833 /* BS11 wants CR + LF in excess of the TLV length !?! */
834 tlv[1] -= 2;
835
836 /* we only now know the exact length for the OM hdr */
837 len = strlen(line_buf)+2;
838 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100839 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200840 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100841 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
842 if (len < 0) {
843 perror("read failed");
844 return -EINVAL;
845 }
846
847 if (len != IPACC_SEGMENT_SIZE)
848 sw->last_seg = 1;
849
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100850 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200851 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100852 len += 3;
853 break;
854 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000855 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100856 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000857 /* FIXME: Other BTS types */
858 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000859 }
Harald Welte4724f992009-01-18 18:01:49 +0000860
Harald Welte4724f992009-01-18 18:01:49 +0000861 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
862 sw->obj_instance[0], sw->obj_instance[1],
863 sw->obj_instance[2]);
864
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100865 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000866}
867
868/* 6.2.4 / 8.3.4 Load Data End */
869static int sw_load_end(struct abis_nm_sw *sw)
870{
871 struct abis_om_hdr *oh;
872 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200873 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000874
875 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
876 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
877 sw->obj_instance[0], sw->obj_instance[1],
878 sw->obj_instance[2]);
879
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100880 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000881 return abis_nm_sendmsg(sw->bts, msg);
882}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000883
Harald Welte52b1f982008-12-23 20:25:15 +0000884/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000885static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000886{
Harald Welte4724f992009-01-18 18:01:49 +0000887 struct abis_om_hdr *oh;
888 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200889 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000890
Harald Welte4724f992009-01-18 18:01:49 +0000891 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
892 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
893 sw->obj_instance[0], sw->obj_instance[1],
894 sw->obj_instance[2]);
895
896 /* FIXME: this is BS11 specific format */
897 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
898 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
899 sw->file_version);
900
901 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000902}
Harald Welte4724f992009-01-18 18:01:49 +0000903
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100904struct sdp_firmware {
905 char magic[4];
906 char more_magic[4];
907 unsigned int header_length;
908 unsigned int file_length;
909} __attribute__ ((packed));
910
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100911static int parse_sdp_header(struct abis_nm_sw *sw)
912{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100913 struct sdp_firmware firmware_header;
914 int rc;
915 struct stat stat;
916
917 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
918 if (rc != sizeof(firmware_header)) {
919 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
920 return -1;
921 }
922
923 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
924 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
925 return -1;
926 }
927
928 if (firmware_header.more_magic[0] != 0x10 ||
929 firmware_header.more_magic[1] != 0x02 ||
930 firmware_header.more_magic[2] != 0x00 ||
931 firmware_header.more_magic[3] != 0x00) {
932 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
933 return -1;
934 }
935
936
937 if (fstat(sw->fd, &stat) == -1) {
938 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
939 return -1;
940 }
941
942 if (ntohl(firmware_header.file_length) != stat.st_size) {
943 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
944 return -1;
945 }
946
947 /* go back to the start as we checked the whole filesize.. */
948 lseek(sw->fd, 0l, SEEK_SET);
949 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
950 "There might be checksums in the file that are not\n"
951 "verified and incomplete firmware might be flashed.\n"
952 "There is absolutely no WARRANTY that flashing will\n"
953 "work.\n");
954 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100955}
956
Harald Welte4724f992009-01-18 18:01:49 +0000957static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
958{
959 char file_id[12+1];
960 char file_version[80+1];
961 int rc;
962
963 sw->fd = open(fname, O_RDONLY);
964 if (sw->fd < 0)
965 return sw->fd;
966
967 switch (sw->bts->type) {
968 case GSM_BTS_TYPE_BS11:
969 sw->stream = fdopen(sw->fd, "r");
970 if (!sw->stream) {
971 perror("fdopen");
972 return -1;
973 }
974 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200975 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +0000976 file_id, file_version);
977 if (rc != 2) {
978 perror("parsing header line of software file");
979 return -1;
980 }
981 strcpy((char *)sw->file_id, file_id);
982 sw->file_id_len = strlen(file_id);
983 strcpy((char *)sw->file_version, file_version);
984 sw->file_version_len = strlen(file_version);
985 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +0000986 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +0000987 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100988 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100989 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100990 rc = parse_sdp_header(sw);
991 if (rc < 0) {
992 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
993 return -1;
994 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100995
996 strcpy((char *)sw->file_id, "id");
997 sw->file_id_len = 3;
998 strcpy((char *)sw->file_version, "version");
999 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001000 break;
Harald Welte4724f992009-01-18 18:01:49 +00001001 default:
1002 /* We don't know how to treat them yet */
1003 close(sw->fd);
1004 return -EINVAL;
1005 }
1006
1007 return 0;
1008}
1009
1010static void sw_close_file(struct abis_nm_sw *sw)
1011{
1012 switch (sw->bts->type) {
1013 case GSM_BTS_TYPE_BS11:
1014 fclose(sw->stream);
1015 break;
1016 default:
1017 close(sw->fd);
1018 break;
1019 }
1020}
1021
1022/* Fill the window */
1023static int sw_fill_window(struct abis_nm_sw *sw)
1024{
1025 int rc;
1026
1027 while (sw->seg_in_window < sw->window_size) {
1028 rc = sw_load_segment(sw);
1029 if (rc < 0)
1030 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001031 if (sw->last_seg)
1032 break;
Harald Welte4724f992009-01-18 18:01:49 +00001033 }
1034 return 0;
1035}
1036
1037/* callback function from abis_nm_rcvmsg() handler */
1038static int abis_nm_rcvmsg_sw(struct msgb *mb)
1039{
1040 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001041 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001042 int rc = -1;
1043 struct abis_nm_sw *sw = &g_sw;
1044 enum sw_state old_state = sw->state;
1045
Harald Welte3ffd1372009-02-01 22:15:49 +00001046 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001047
1048 switch (sw->state) {
1049 case SW_STATE_WAIT_INITACK:
1050 switch (foh->msg_type) {
1051 case NM_MT_LOAD_INIT_ACK:
1052 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001053 if (sw->cbfn)
1054 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1055 NM_MT_LOAD_INIT_ACK, mb,
1056 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001057 rc = sw_fill_window(sw);
1058 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001059 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001060 break;
1061 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001062 if (sw->forced) {
1063 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1064 "Init NACK\n");
1065 if (sw->cbfn)
1066 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1067 NM_MT_LOAD_INIT_ACK, mb,
1068 sw->cb_data, NULL);
1069 rc = sw_fill_window(sw);
1070 sw->state = SW_STATE_WAIT_SEGACK;
1071 } else {
1072 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001073 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001074 if (sw->cbfn)
1075 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1076 NM_MT_LOAD_INIT_NACK, mb,
1077 sw->cb_data, NULL);
1078 sw->state = SW_STATE_ERROR;
1079 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001080 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001081 break;
1082 }
1083 break;
1084 case SW_STATE_WAIT_SEGACK:
1085 switch (foh->msg_type) {
1086 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001087 if (sw->cbfn)
1088 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1089 NM_MT_LOAD_SEG_ACK, mb,
1090 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001091 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001092 if (!sw->last_seg) {
1093 /* fill window with more segments */
1094 rc = sw_fill_window(sw);
1095 sw->state = SW_STATE_WAIT_SEGACK;
1096 } else {
1097 /* end the transfer */
1098 sw->state = SW_STATE_WAIT_ENDACK;
1099 rc = sw_load_end(sw);
1100 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001101 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001102 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001103 case NM_MT_LOAD_ABORT:
1104 if (sw->cbfn)
1105 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1106 NM_MT_LOAD_ABORT, mb,
1107 sw->cb_data, NULL);
1108 break;
Harald Welte4724f992009-01-18 18:01:49 +00001109 }
1110 break;
1111 case SW_STATE_WAIT_ENDACK:
1112 switch (foh->msg_type) {
1113 case NM_MT_LOAD_END_ACK:
1114 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001115 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1116 sw->bts->nr);
1117 sw->state = SW_STATE_NONE;
1118 if (sw->cbfn)
1119 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1120 NM_MT_LOAD_END_ACK, mb,
1121 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001122 rc = 0;
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 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001126 if (sw->forced) {
1127 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1128 "End NACK\n");
1129 sw->state = SW_STATE_NONE;
1130 if (sw->cbfn)
1131 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1132 NM_MT_LOAD_END_ACK, mb,
1133 sw->cb_data, NULL);
1134 } else {
1135 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001136 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001137 sw->state = SW_STATE_ERROR;
1138 if (sw->cbfn)
1139 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1140 NM_MT_LOAD_END_NACK, mb,
1141 sw->cb_data, NULL);
1142 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001143 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001144 break;
1145 }
1146 case SW_STATE_WAIT_ACTACK:
1147 switch (foh->msg_type) {
1148 case NM_MT_ACTIVATE_SW_ACK:
1149 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001150 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001151 sw->state = SW_STATE_NONE;
1152 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001153 if (sw->cbfn)
1154 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1155 NM_MT_ACTIVATE_SW_ACK, mb,
1156 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001157 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001158 break;
1159 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001160 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001161 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001162 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001163 if (sw->cbfn)
1164 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1165 NM_MT_ACTIVATE_SW_NACK, mb,
1166 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001167 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001168 break;
1169 }
1170 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001171 switch (foh->msg_type) {
1172 case NM_MT_ACTIVATE_SW_ACK:
1173 rc = 0;
1174 break;
1175 }
1176 break;
Harald Welte4724f992009-01-18 18:01:49 +00001177 case SW_STATE_ERROR:
1178 break;
1179 }
1180
1181 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001182 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001183 foh->msg_type, old_state, sw->state);
1184
1185 return rc;
1186}
1187
1188/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001189int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001190 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001191 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001192{
1193 struct abis_nm_sw *sw = &g_sw;
1194 int rc;
1195
Harald Welte5e4d1b32009-02-01 13:36:56 +00001196 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1197 bts->nr, fname);
1198
Harald Welte4724f992009-01-18 18:01:49 +00001199 if (sw->state != SW_STATE_NONE)
1200 return -EBUSY;
1201
1202 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001203 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001204
1205 switch (bts->type) {
1206 case GSM_BTS_TYPE_BS11:
1207 sw->obj_class = NM_OC_SITE_MANAGER;
1208 sw->obj_instance[0] = 0xff;
1209 sw->obj_instance[1] = 0xff;
1210 sw->obj_instance[2] = 0xff;
1211 break;
1212 case GSM_BTS_TYPE_NANOBTS:
1213 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001214 sw->obj_instance[0] = sw->bts->nr;
1215 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001216 sw->obj_instance[2] = 0xff;
1217 break;
1218 case GSM_BTS_TYPE_UNKNOWN:
1219 default:
1220 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1221 return -1;
1222 break;
1223 }
Harald Welte4724f992009-01-18 18:01:49 +00001224 sw->window_size = win_size;
1225 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001226 sw->cbfn = cbfn;
1227 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001228 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001229
1230 rc = sw_open_file(sw, fname);
1231 if (rc < 0) {
1232 sw->state = SW_STATE_NONE;
1233 return rc;
1234 }
1235
1236 return sw_load_init(sw);
1237}
Harald Welte52b1f982008-12-23 20:25:15 +00001238
Harald Welte1602ade2009-01-29 21:12:39 +00001239int abis_nm_software_load_status(struct gsm_bts *bts)
1240{
1241 struct abis_nm_sw *sw = &g_sw;
1242 struct stat st;
1243 int rc, percent;
1244
1245 rc = fstat(sw->fd, &st);
1246 if (rc < 0) {
1247 perror("ERROR during stat");
1248 return rc;
1249 }
1250
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001251 if (sw->stream)
1252 percent = (ftell(sw->stream) * 100) / st.st_size;
1253 else
1254 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001255 return percent;
1256}
1257
Harald Welte5e4d1b32009-02-01 13:36:56 +00001258/* Activate the specified software into the BTS */
1259int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1260 gsm_cbfn *cbfn, void *cb_data)
1261{
1262 struct abis_nm_sw *sw = &g_sw;
1263 int rc;
1264
1265 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1266 bts->nr, fname);
1267
1268 if (sw->state != SW_STATE_NONE)
1269 return -EBUSY;
1270
1271 sw->bts = bts;
1272 sw->obj_class = NM_OC_SITE_MANAGER;
1273 sw->obj_instance[0] = 0xff;
1274 sw->obj_instance[1] = 0xff;
1275 sw->obj_instance[2] = 0xff;
1276 sw->state = SW_STATE_WAIT_ACTACK;
1277 sw->cbfn = cbfn;
1278 sw->cb_data = cb_data;
1279
1280 /* Open the file in order to fill some sw struct members */
1281 rc = sw_open_file(sw, fname);
1282 if (rc < 0) {
1283 sw->state = SW_STATE_NONE;
1284 return rc;
1285 }
1286 sw_close_file(sw);
1287
1288 return sw_activate(sw);
1289}
1290
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001291static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1292 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001293{
Harald Welteadaf08b2009-01-18 11:08:10 +00001294 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001295 ch->bts_port = bts_port;
1296 ch->timeslot = ts_nr;
1297 ch->subslot = subslot_nr;
1298}
1299
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001300int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1301 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1302 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001303{
1304 struct abis_om_hdr *oh;
1305 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001306 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001307 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001308
1309 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1310 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1311 bts->bts_nr, trx_nr, 0xff);
1312
Harald Welte8470bf22008-12-25 23:28:35 +00001313 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001314
1315 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1316 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1317
1318 return abis_nm_sendmsg(bts, msg);
1319}
1320
1321/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1322int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001323 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001324{
Harald Welte8470bf22008-12-25 23:28:35 +00001325 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001326 struct abis_om_hdr *oh;
1327 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001328 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001329
1330 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001331 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001332 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1333
1334 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1335 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1336
1337 return abis_nm_sendmsg(bts, msg);
1338}
1339
1340#if 0
1341int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1342 struct abis_nm_abis_channel *chan)
1343{
1344}
1345#endif
1346
1347int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001348 uint8_t e1_port, uint8_t e1_timeslot,
1349 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001350{
1351 struct gsm_bts *bts = ts->trx->bts;
1352 struct abis_om_hdr *oh;
1353 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001354 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001355
1356 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1357 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001358 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001359
1360 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1361 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1362
Harald Weltef325eb42009-02-19 17:07:39 +00001363 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1364 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001365 e1_port, e1_timeslot, e1_subslot);
1366
Harald Welte52b1f982008-12-23 20:25:15 +00001367 return abis_nm_sendmsg(bts, msg);
1368}
1369
1370#if 0
1371int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1372 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001373 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001374{
1375}
1376#endif
1377
Harald Weltefe568f22012-08-14 19:15:57 +02001378/* Chapter 8.11.1 */
1379int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1380 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1381 uint8_t *attr, uint8_t attr_len)
1382{
1383 struct abis_om_hdr *oh;
1384 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001385
1386 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1387
1388 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1389 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1390 bts_nr, trx_nr, ts_nr);
1391 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1392
1393 return abis_nm_sendmsg(bts, msg);
1394}
1395
Harald Welte22af0db2009-02-14 15:41:08 +00001396/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001397int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001398{
1399 struct abis_om_hdr *oh;
1400 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001401 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001402
1403 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1404
1405 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001406 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 +00001407 cur = msgb_put(msg, attr_len);
1408 memcpy(cur, attr, attr_len);
1409
1410 return abis_nm_sendmsg(bts, msg);
1411}
1412
1413/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001414int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001415{
1416 struct abis_om_hdr *oh;
1417 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001418 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001419
1420 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1421
1422 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1423 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001424 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001425 cur = msgb_put(msg, attr_len);
1426 memcpy(cur, attr, attr_len);
1427
1428 return abis_nm_sendmsg(trx->bts, msg);
1429}
1430
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001431static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1432 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001433{
1434 int i;
1435
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001436 *reason = "Reason unknown";
1437
Harald Welte39c7deb2009-08-09 21:49:48 +02001438 /* As it turns out, the BS-11 has some very peculiar restrictions
1439 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301440 switch (ts->trx->bts->type) {
1441 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001442 switch (chan_comb) {
1443 case NM_CHANC_TCHHalf:
1444 case NM_CHANC_TCHHalf2:
1445 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001446 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001447 return -EINVAL;
1448 case NM_CHANC_SDCCH:
1449 /* only one SDCCH/8 per TRX */
1450 for (i = 0; i < TRX_NR_TS; i++) {
1451 if (i == ts->nr)
1452 continue;
1453 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001454 NM_CHANC_SDCCH) {
1455 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001456 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001457 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001458 }
1459 /* not allowed for TS0 of BCCH-TRX */
1460 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001461 ts->nr == 0) {
1462 *reason = "SDCCH/8 must be on TS0.";
1463 return -EINVAL;
1464 }
1465
Harald Welte39c7deb2009-08-09 21:49:48 +02001466 /* not on the same TRX that has a BCCH+SDCCH4
1467 * combination */
1468 if (ts->trx == ts->trx->bts->c0 &&
1469 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001470 ts->trx->ts[0].nm_chan_comb == 8)) {
1471 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1472 return -EINVAL;
1473 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001474 break;
1475 case NM_CHANC_mainBCCH:
1476 case NM_CHANC_BCCHComb:
1477 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001478 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1479 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001480 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001481 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001482 break;
1483 case NM_CHANC_BCCH:
1484 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001485 if (ts->trx != ts->trx->bts->c0) {
1486 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001487 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001488 }
1489 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1490 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001491 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001492 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001493 break;
1494 case 8: /* this is not like 08.58, but in fact
1495 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1496 /* FIXME: only one CBCH allowed per cell */
1497 break;
1498 }
Harald Welted6575f92009-12-02 02:45:23 +05301499 break;
1500 case GSM_BTS_TYPE_NANOBTS:
1501 switch (ts->nr) {
1502 case 0:
1503 if (ts->trx->nr == 0) {
1504 /* only on TRX0 */
1505 switch (chan_comb) {
1506 case NM_CHANC_BCCH:
1507 case NM_CHANC_mainBCCH:
1508 case NM_CHANC_BCCHComb:
1509 return 0;
1510 break;
1511 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001512 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301513 return -EINVAL;
1514 }
1515 } else {
1516 switch (chan_comb) {
1517 case NM_CHANC_TCHFull:
1518 case NM_CHANC_TCHHalf:
1519 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1520 return 0;
1521 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001522 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301523 return -EINVAL;
1524 }
1525 }
1526 break;
1527 case 1:
1528 if (ts->trx->nr == 0) {
1529 switch (chan_comb) {
1530 case NM_CHANC_SDCCH_CBCH:
1531 if (ts->trx->ts[0].nm_chan_comb ==
1532 NM_CHANC_mainBCCH)
1533 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001534 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301535 return -EINVAL;
1536 case NM_CHANC_SDCCH:
1537 case NM_CHANC_TCHFull:
1538 case NM_CHANC_TCHHalf:
1539 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1540 case NM_CHANC_IPAC_TCHFull_PDCH:
1541 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001542 default:
1543 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1544 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301545 }
1546 } else {
1547 switch (chan_comb) {
1548 case NM_CHANC_SDCCH:
1549 case NM_CHANC_TCHFull:
1550 case NM_CHANC_TCHHalf:
1551 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1552 return 0;
1553 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001554 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301555 return -EINVAL;
1556 }
1557 }
1558 break;
1559 case 2:
1560 case 3:
1561 case 4:
1562 case 5:
1563 case 6:
1564 case 7:
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 case NM_CHANC_IPAC_PDCH:
1571 case NM_CHANC_IPAC_TCHFull_PDCH:
1572 if (ts->trx->nr == 0)
1573 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001574 else {
1575 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301576 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001577 }
Harald Welted6575f92009-12-02 02:45:23 +05301578 }
1579 break;
1580 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001581 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301582 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001583 case GSM_BTS_TYPE_OSMO_SYSMO:
1584 /* no known restrictions */
1585 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301586 default:
1587 /* unknown BTS type */
1588 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001589 }
1590 return 0;
1591}
1592
Harald Welte22af0db2009-02-14 15:41:08 +00001593/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001594int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001595{
1596 struct gsm_bts *bts = ts->trx->bts;
1597 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001598 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001599 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001600 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001601 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001602
1603 if (bts->type == GSM_BTS_TYPE_BS11)
1604 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001605
Harald Weltef325eb42009-02-19 17:07:39 +00001606 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001607 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001608 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001609 LOGP(DNM, LOGL_ERROR,
1610 "Invalid Channel Combination %d on %s. Reason: %s\n",
1611 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001612 return -EINVAL;
1613 }
1614 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001615
Harald Welte52b1f982008-12-23 20:25:15 +00001616 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001617 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001618 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001619 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001620 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001621 if (ts->hopping.enabled) {
1622 unsigned int i;
1623 uint8_t *len;
1624
Harald Welte6e0cd042009-09-12 13:05:33 +02001625 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1626 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001627
1628 /* build the ARFCN list */
1629 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1630 len = msgb_put(msg, 1);
1631 *len = 0;
1632 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1633 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1634 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001635 /* At least BS-11 wants a TLV16 here */
1636 if (bts->type == GSM_BTS_TYPE_BS11)
1637 *len += 1;
1638 else
1639 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001640 }
1641 }
Harald Weltee0590df2009-02-15 03:34:15 +00001642 }
Harald Welte135a6482011-05-30 12:09:13 +02001643 if (ts->tsc == -1)
1644 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1645 else
1646 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001647 if (bts->type == GSM_BTS_TYPE_BS11)
1648 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001649
1650 return abis_nm_sendmsg(bts, msg);
1651}
1652
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001653int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1654 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001655{
1656 struct abis_om_hdr *oh;
1657 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001658 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1659 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001660
1661 if (nack) {
1662 len += 2;
1663 msgtype = NM_MT_SW_ACT_REQ_NACK;
1664 }
Harald Welte34a99682009-02-13 02:41:40 +00001665
1666 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001667 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1668
Harald Welte34a99682009-02-13 02:41:40 +00001669 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001670 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001671 memcpy(ptr, attr, att_len);
1672 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001673 if (nack)
1674 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001675
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001676 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001677}
1678
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001679int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001680{
Harald Welte8470bf22008-12-25 23:28:35 +00001681 struct msgb *msg = nm_msgb_alloc();
1682 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001683 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001684
1685 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1686 fill_om_hdr(oh, len);
1687 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001688 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001689
1690 return abis_nm_sendmsg(bts, msg);
1691}
1692
1693/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001694static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001695{
1696 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001697 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001698
1699 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001700 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001701 0xff, 0xff, 0xff);
1702
1703 return abis_nm_sendmsg(bts, msg);
1704}
1705
Harald Welte34a99682009-02-13 02:41:40 +00001706/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001707int 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 +00001708{
1709 struct abis_om_hdr *oh;
1710 struct msgb *msg = nm_msgb_alloc();
1711
1712 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1713 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1714
Harald Welte15c61722011-05-22 22:45:37 +02001715 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001716 DEBUGPC(DNM, "Sending OPSTART\n");
1717
Harald Welte34a99682009-02-13 02:41:40 +00001718 return abis_nm_sendmsg(bts, msg);
1719}
1720
1721/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001722int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1723 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001724{
1725 struct abis_om_hdr *oh;
1726 struct msgb *msg = nm_msgb_alloc();
1727
1728 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1729 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1730 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1731
1732 return abis_nm_sendmsg(bts, msg);
1733}
1734
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001735int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1736 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001737{
1738 struct abis_om_hdr *oh;
1739 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001740 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001741
1742 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1743 e1_port0, ts0, e1_port1, ts1);
1744
1745 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1746 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1747 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1748
1749 attr = msgb_put(msg, 3);
1750 attr[0] = NM_ATT_MDROP_LINK;
1751 attr[1] = e1_port0;
1752 attr[2] = ts0;
1753
1754 attr = msgb_put(msg, 3);
1755 attr[0] = NM_ATT_MDROP_NEXT;
1756 attr[1] = e1_port1;
1757 attr[2] = ts1;
1758
1759 return abis_nm_sendmsg(bts, msg);
1760}
Harald Welte34a99682009-02-13 02:41:40 +00001761
Harald Weltec7310382009-08-08 00:02:36 +02001762/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001763int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1764 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1765 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001766{
1767 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001768
Harald Welte15c61722011-05-22 22:45:37 +02001769 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001770
1771 if (!msg)
1772 msg = nm_msgb_alloc();
1773
1774 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1775 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1776 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1777 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001778 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001779
1780 return abis_nm_sendmsg(bts, msg);
1781}
1782
Harald Welte52b1f982008-12-23 20:25:15 +00001783int abis_nm_event_reports(struct gsm_bts *bts, int on)
1784{
1785 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001786 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001787 else
Harald Welte227d4072009-01-03 08:16:25 +00001788 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001789}
1790
Harald Welte47d88ae2009-01-04 12:02:08 +00001791/* Siemens (or BS-11) specific commands */
1792
Harald Welte3ffd1372009-02-01 22:15:49 +00001793int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1794{
1795 if (reconnect == 0)
1796 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1797 else
1798 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1799}
1800
Harald Welteb8427972009-02-05 19:27:17 +00001801int abis_nm_bs11_restart(struct gsm_bts *bts)
1802{
1803 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1804}
1805
1806
Harald Welte268bb402009-02-01 19:11:56 +00001807struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001808 uint16_t year;
1809 uint8_t month;
1810 uint8_t day;
1811 uint8_t hour;
1812 uint8_t min;
1813 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001814} __attribute__((packed));
1815
1816
1817void get_bs11_date_time(struct bs11_date_time *aet)
1818{
1819 time_t t;
1820 struct tm *tm;
1821
1822 t = time(NULL);
1823 tm = localtime(&t);
1824 aet->sec = tm->tm_sec;
1825 aet->min = tm->tm_min;
1826 aet->hour = tm->tm_hour;
1827 aet->day = tm->tm_mday;
1828 aet->month = tm->tm_mon;
1829 aet->year = htons(1900 + tm->tm_year);
1830}
1831
Harald Welte05188ee2009-01-18 11:39:08 +00001832int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001833{
Harald Welte4668fda2009-01-03 08:19:29 +00001834 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001835}
1836
Harald Welte05188ee2009-01-18 11:39:08 +00001837int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001838{
1839 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001840 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001841 else
Harald Welte4668fda2009-01-03 08:19:29 +00001842 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001843}
Harald Welte47d88ae2009-01-04 12:02:08 +00001844
Harald Welte05188ee2009-01-18 11:39:08 +00001845int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001846 enum abis_bs11_objtype type, uint8_t idx,
1847 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001848{
1849 struct abis_om_hdr *oh;
1850 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001851 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001852
1853 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001854 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001855 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001856 cur = msgb_put(msg, attr_len);
1857 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001858
1859 return abis_nm_sendmsg(bts, msg);
1860}
1861
Harald Welte78fc0d42009-02-19 02:50:57 +00001862int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001863 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001864{
1865 struct abis_om_hdr *oh;
1866 struct msgb *msg = nm_msgb_alloc();
1867
1868 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1869 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1870 NM_OC_BS11, type, 0, idx);
1871
1872 return abis_nm_sendmsg(bts, msg);
1873}
1874
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001875int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001876{
1877 struct abis_om_hdr *oh;
1878 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001879 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001880
1881 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001882 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001883 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1884 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001885
1886 return abis_nm_sendmsg(bts, msg);
1887}
1888
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001889int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001890{
1891 struct abis_om_hdr *oh;
1892 struct msgb *msg = nm_msgb_alloc();
1893
1894 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1895 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001896 idx, 0xff, 0xff);
1897
1898 return abis_nm_sendmsg(bts, msg);
1899}
1900
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001901int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001902{
1903 struct abis_om_hdr *oh;
1904 struct msgb *msg = nm_msgb_alloc();
1905
1906 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1907 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1908 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001909
1910 return abis_nm_sendmsg(bts, msg);
1911}
Harald Welte05188ee2009-01-18 11:39:08 +00001912
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001913static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001914int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1915{
1916 struct abis_om_hdr *oh;
1917 struct msgb *msg = nm_msgb_alloc();
1918
1919 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1920 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1921 0xff, 0xff, 0xff);
1922 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1923
1924 return abis_nm_sendmsg(bts, msg);
1925}
1926
Harald Welteb6c92ae2009-02-21 20:15:32 +00001927/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001928int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1929 uint8_t e1_timeslot, uint8_t e1_subslot,
1930 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001931{
1932 struct abis_om_hdr *oh;
1933 struct abis_nm_channel *ch;
1934 struct msgb *msg = nm_msgb_alloc();
1935
1936 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001937 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001938 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1939
1940 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1941 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001942 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001943
1944 return abis_nm_sendmsg(bts, msg);
1945}
1946
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001947int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001948{
1949 struct abis_om_hdr *oh;
1950 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001951
1952 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001953 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001954 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1955 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1956
1957 return abis_nm_sendmsg(trx->bts, msg);
1958}
1959
Harald Welte78fc0d42009-02-19 02:50:57 +00001960int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1961{
1962 struct abis_om_hdr *oh;
1963 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001964 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00001965
1966 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1967 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1968 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1969 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1970
1971 return abis_nm_sendmsg(trx->bts, msg);
1972}
1973
Harald Welteaaf02d92009-04-29 13:25:57 +00001974int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1975{
1976 struct abis_om_hdr *oh;
1977 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001978 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00001979
1980 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1981 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1982 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00001983 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00001984
1985 return abis_nm_sendmsg(bts, msg);
1986}
1987
Harald Welteef061952009-05-17 12:43:42 +00001988int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1989{
1990 struct abis_om_hdr *oh;
1991 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001992 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00001993 NM_ATT_BS11_CCLK_TYPE };
1994
1995 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1996 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1997 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1998 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1999
2000 return abis_nm_sendmsg(bts, msg);
2001
2002}
Harald Welteaaf02d92009-04-29 13:25:57 +00002003
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002004//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002005
Harald Welte1bc09062009-01-18 14:17:52 +00002006int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002007{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002008 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2009}
2010
Daniel Willmann4b054c82010-01-07 00:46:26 +01002011int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2012{
2013 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2014}
2015
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002016int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002017{
Harald Welte05188ee2009-01-18 11:39:08 +00002018 struct abis_om_hdr *oh;
2019 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002020 struct bs11_date_time bdt;
2021
2022 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002023
2024 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002025 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002026 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002027 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002028 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002029 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002030 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002031 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002032 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002033 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002034 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002035 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002036 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002037 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002038 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002039 }
Harald Welte05188ee2009-01-18 11:39:08 +00002040
2041 return abis_nm_sendmsg(bts, msg);
2042}
Harald Welte1bc09062009-01-18 14:17:52 +00002043
2044int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2045{
2046 struct abis_om_hdr *oh;
2047 struct msgb *msg;
2048
2049 if (strlen(password) != 10)
2050 return -EINVAL;
2051
2052 msg = nm_msgb_alloc();
2053 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002054 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002055 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002056 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002057
2058 return abis_nm_sendmsg(bts, msg);
2059}
2060
Harald Weltee69f5fb2009-04-28 16:31:38 +00002061/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2062int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2063{
2064 struct abis_om_hdr *oh;
2065 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002066 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002067
2068 msg = nm_msgb_alloc();
2069 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2070 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2071 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002072
2073 if (locked)
2074 tlv_value = BS11_LI_PLL_LOCKED;
2075 else
2076 tlv_value = BS11_LI_PLL_STANDALONE;
2077
2078 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002079
2080 return abis_nm_sendmsg(bts, msg);
2081}
2082
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002083/* Set the calibration value of the PLL (work value/set value)
2084 * It depends on the login which one is changed */
2085int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2086{
2087 struct abis_om_hdr *oh;
2088 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002089 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002090
2091 msg = nm_msgb_alloc();
2092 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2093 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2094 BS11_OBJ_TRX1, 0x00, 0x00);
2095
2096 tlv_value[0] = value>>8;
2097 tlv_value[1] = value&0xff;
2098
2099 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2100
2101 return abis_nm_sendmsg(bts, msg);
2102}
2103
Harald Welte1bc09062009-01-18 14:17:52 +00002104int abis_nm_bs11_get_state(struct gsm_bts *bts)
2105{
2106 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2107}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002108
2109/* BS11 SWL */
2110
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002111void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002112
Harald Welte5e4d1b32009-02-01 13:36:56 +00002113struct abis_nm_bs11_sw {
2114 struct gsm_bts *bts;
2115 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002116 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002117 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002118 struct llist_head file_list;
2119 gsm_cbfn *user_cb; /* specified by the user */
2120};
2121static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2122
2123struct file_list_entry {
2124 struct llist_head list;
2125 char fname[PATH_MAX];
2126};
2127
2128struct file_list_entry *fl_dequeue(struct llist_head *queue)
2129{
2130 struct llist_head *lh;
2131
2132 if (llist_empty(queue))
2133 return NULL;
2134
2135 lh = queue->next;
2136 llist_del(lh);
2137
2138 return llist_entry(lh, struct file_list_entry, list);
2139}
2140
2141static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2142{
2143 char linebuf[255];
2144 struct llist_head *lh, *lh2;
2145 FILE *swl;
2146 int rc = 0;
2147
2148 swl = fopen(bs11_sw->swl_fname, "r");
2149 if (!swl)
2150 return -ENODEV;
2151
2152 /* zero the stale file list, if any */
2153 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2154 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002155 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002156 }
2157
2158 while (fgets(linebuf, sizeof(linebuf), swl)) {
2159 char file_id[12+1];
2160 char file_version[80+1];
2161 struct file_list_entry *fle;
2162 static char dir[PATH_MAX];
2163
2164 if (strlen(linebuf) < 4)
2165 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002166
Harald Welte5e4d1b32009-02-01 13:36:56 +00002167 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2168 if (rc < 0) {
2169 perror("ERR parsing SWL file");
2170 rc = -EINVAL;
2171 goto out;
2172 }
2173 if (rc < 2)
2174 continue;
2175
Harald Welte470ec292009-06-26 20:25:23 +02002176 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002177 if (!fle) {
2178 rc = -ENOMEM;
2179 goto out;
2180 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002181
2182 /* construct new filename */
2183 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2184 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2185 strcat(fle->fname, "/");
2186 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002187
2188 llist_add_tail(&fle->list, &bs11_sw->file_list);
2189 }
2190
2191out:
2192 fclose(swl);
2193 return rc;
2194}
2195
2196/* bs11 swload specific callback, passed to abis_nm core swload */
2197static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2198 struct msgb *msg, void *data, void *param)
2199{
2200 struct abis_nm_bs11_sw *bs11_sw = data;
2201 struct file_list_entry *fle;
2202 int rc = 0;
2203
Harald Welte5e4d1b32009-02-01 13:36:56 +00002204 switch (event) {
2205 case NM_MT_LOAD_END_ACK:
2206 fle = fl_dequeue(&bs11_sw->file_list);
2207 if (fle) {
2208 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002209 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002210 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002211 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002212 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002213 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002214 } else {
2215 /* activate the SWL */
2216 rc = abis_nm_software_activate(bs11_sw->bts,
2217 bs11_sw->swl_fname,
2218 bs11_swload_cbfn,
2219 bs11_sw);
2220 }
2221 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002222 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002223 case NM_MT_LOAD_END_NACK:
2224 case NM_MT_LOAD_INIT_ACK:
2225 case NM_MT_LOAD_INIT_NACK:
2226 case NM_MT_ACTIVATE_SW_NACK:
2227 case NM_MT_ACTIVATE_SW_ACK:
2228 default:
2229 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002230 if (bs11_sw->user_cb)
2231 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002232 break;
2233 }
2234
2235 return rc;
2236}
2237
2238/* Siemens provides a SWL file that is a mere listing of all the other
2239 * files that are part of a software release. We need to upload first
2240 * the list file, and then each file that is listed in the list file */
2241int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002242 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002243{
2244 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2245 struct file_list_entry *fle;
2246 int rc = 0;
2247
2248 INIT_LLIST_HEAD(&bs11_sw->file_list);
2249 bs11_sw->bts = bts;
2250 bs11_sw->win_size = win_size;
2251 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002252 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002253
2254 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2255 rc = bs11_read_swl_file(bs11_sw);
2256 if (rc < 0)
2257 return rc;
2258
2259 /* dequeue next item in file list */
2260 fle = fl_dequeue(&bs11_sw->file_list);
2261 if (!fle)
2262 return -EINVAL;
2263
2264 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002265 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002266 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002267 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002268 return rc;
2269}
2270
Harald Welte5083b0b2009-02-02 19:20:52 +00002271#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002272static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002273 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2274 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2275 NM_ATT_BS11_LMT_USER_NAME,
2276
2277 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2278
2279 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2280
2281 NM_ATT_BS11_SW_LOAD_STORED };
2282
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002283static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002284 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2285 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2286 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2287 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002288#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002289
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002290static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002291 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2292 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002293 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002294
2295int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2296{
2297 struct abis_om_hdr *oh;
2298 struct msgb *msg = nm_msgb_alloc();
2299
2300 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2301 /* SiemensHW CCTRL object */
2302 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2303 0x03, 0x00, 0x00);
2304 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2305
2306 return abis_nm_sendmsg(bts, msg);
2307}
Harald Welte268bb402009-02-01 19:11:56 +00002308
2309int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2310{
2311 struct abis_om_hdr *oh;
2312 struct msgb *msg = nm_msgb_alloc();
2313 struct bs11_date_time aet;
2314
2315 get_bs11_date_time(&aet);
2316 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2317 /* SiemensHW CCTRL object */
2318 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2319 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002320 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002321
2322 return abis_nm_sendmsg(bts, msg);
2323}
Harald Welte5c1e4582009-02-15 11:57:29 +00002324
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002325int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002326{
2327 struct abis_om_hdr *oh;
2328 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002329 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002330
2331 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2332 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2333 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2334 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2335
2336 return abis_nm_sendmsg(bts, msg);
2337}
2338
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002339int 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 +02002340{
2341 struct abis_om_hdr *oh;
2342 struct msgb *msg = nm_msgb_alloc();
2343 struct bs11_date_time aet;
2344
2345 get_bs11_date_time(&aet);
2346 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2347 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2348 bport, 0xff, 0x02);
2349 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2350
2351 return abis_nm_sendmsg(bts, msg);
2352}
2353
Harald Welte5c1e4582009-02-15 11:57:29 +00002354/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002355static const char ipaccess_magic[] = "com.ipaccess";
2356
Harald Welte677c21f2009-02-17 13:22:23 +00002357
2358static int abis_nm_rx_ipacc(struct msgb *msg)
2359{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002360 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002361 struct abis_om_hdr *oh = msgb_l2(msg);
2362 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002363 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002364 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002365 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002366 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002367
2368 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002369 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002370 return -EINVAL;
2371 }
2372
Harald Welte193fefc2009-04-30 15:16:27 +00002373 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002374 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002375
Harald Welte15c61722011-05-22 22:45:37 +02002376 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002377
Harald Welte746d6092009-10-19 22:11:11 +02002378 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002379
Harald Welte677c21f2009-02-17 13:22:23 +00002380 switch (foh->msg_type) {
2381 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002382 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002383 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2384 memcpy(&addr,
2385 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2386
2387 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2388 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002389 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002390 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002391 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002392 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002393 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2394 DEBUGPC(DNM, "STREAM=0x%02x ",
2395 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002396 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002397 break;
2398 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002399 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002400 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002401 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002402 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002403 else
2404 DEBUGPC(DNM, "\n");
2405 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002406 case NM_MT_IPACC_SET_NVATTR_ACK:
2407 DEBUGPC(DNM, "SET NVATTR ACK\n");
2408 /* FIXME: decode and show the actual attributes */
2409 break;
2410 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002411 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002412 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002413 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002414 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002415 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002416 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002417 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002418 case NM_MT_IPACC_GET_NVATTR_ACK:
2419 DEBUGPC(DNM, "GET NVATTR ACK\n");
2420 /* FIXME: decode and show the actual attributes */
2421 break;
2422 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002423 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002424 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002425 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002426 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002427 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002428 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002429 break;
Harald Welte15c44172009-10-08 20:15:24 +02002430 case NM_MT_IPACC_SET_ATTR_ACK:
2431 DEBUGPC(DNM, "SET ATTR ACK\n");
2432 break;
2433 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002434 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002435 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002436 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002437 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002438 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002439 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002440 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002441 default:
2442 DEBUGPC(DNM, "unknown\n");
2443 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002444 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002445
2446 /* signal handling */
2447 switch (foh->msg_type) {
2448 case NM_MT_IPACC_RSL_CONNECT_NACK:
2449 case NM_MT_IPACC_SET_NVATTR_NACK:
2450 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002451 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 +01002452 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002453 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002454 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002455 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002456 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 +01002457 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002458 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002459 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002460 default:
2461 break;
2462 }
2463
Harald Welte677c21f2009-02-17 13:22:23 +00002464 return 0;
2465}
2466
Harald Welte193fefc2009-04-30 15:16:27 +00002467/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002468int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2469 uint8_t obj_class, uint8_t bts_nr,
2470 uint8_t trx_nr, uint8_t ts_nr,
2471 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002472{
2473 struct msgb *msg = nm_msgb_alloc();
2474 struct abis_om_hdr *oh;
2475 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002476 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002477
2478 /* construct the 12.21 OM header, observe the erroneous length */
2479 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2480 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2481 oh->mdisc = ABIS_OM_MDISC_MANUF;
2482
2483 /* add the ip.access magic */
2484 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2485 *data++ = sizeof(ipaccess_magic);
2486 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2487
2488 /* fill the 12.21 FOM header */
2489 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2490 foh->msg_type = msg_type;
2491 foh->obj_class = obj_class;
2492 foh->obj_inst.bts_nr = bts_nr;
2493 foh->obj_inst.trx_nr = trx_nr;
2494 foh->obj_inst.ts_nr = ts_nr;
2495
2496 if (attr && attr_len) {
2497 data = msgb_put(msg, attr_len);
2498 memcpy(data, attr, attr_len);
2499 }
2500
2501 return abis_nm_sendmsg(bts, msg);
2502}
Harald Welte677c21f2009-02-17 13:22:23 +00002503
Harald Welte193fefc2009-04-30 15:16:27 +00002504/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002505int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002506 int attr_len)
2507{
Harald Welte2ef156d2010-01-07 20:39:42 +01002508 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2509 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002510 attr_len);
2511}
2512
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002513int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002514 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002515{
2516 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002517 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002518 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2519 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2520
2521 int attr_len = sizeof(attr);
2522
2523 ia.s_addr = htonl(ip);
2524 attr[1] = stream;
2525 attr[3] = port >> 8;
2526 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002527 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002528
2529 /* if ip == 0, we use the default IP */
2530 if (ip == 0)
2531 attr_len -= 5;
2532
2533 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002534 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002535
2536 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2537 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2538 trx->nr, 0xff, attr, attr_len);
2539}
2540
Harald Welte193fefc2009-04-30 15:16:27 +00002541/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002542int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002543{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002544 struct abis_om_hdr *oh;
2545 struct msgb *msg = nm_msgb_alloc();
2546
2547 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2548 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2549 trx->bts->nr, trx->nr, 0xff);
2550
2551 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002552}
Harald Weltedaef5212009-10-24 10:20:41 +02002553
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002554int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2555 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2556 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002557{
2558 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2559 obj_class, bts_nr, trx_nr, ts_nr,
2560 attr, attr_len);
2561}
Harald Welte0f255852009-11-12 14:48:42 +01002562
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002563void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002564{
2565 /* we simply reuse the GSM48 function and overwrite the RAC
2566 * with the Cell ID */
2567 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002568 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002569}
2570
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002571void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2572{
2573 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2574
Harald Welted64c0bc2011-05-30 12:07:53 +02002575 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002576 if (!trx->bts || !trx->bts->oml_link)
2577 return;
2578
2579 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2580 trx->bts->bts_nr, trx->nr, 0xff,
2581 new_state);
2582}
2583
Harald Welte92b1fe42010-03-25 11:45:30 +08002584static const struct value_string ipacc_testres_names[] = {
2585 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2586 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2587 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2588 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2589 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2590 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002591};
2592
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002593const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002594{
Harald Welte92b1fe42010-03-25 11:45:30 +08002595 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002596}
2597
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002598void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002599{
2600 cid->mcc = (buf[0] & 0xf) * 100;
2601 cid->mcc += (buf[0] >> 4) * 10;
2602 cid->mcc += (buf[1] & 0xf) * 1;
2603
2604 if (buf[1] >> 4 == 0xf) {
2605 cid->mnc = (buf[2] & 0xf) * 10;
2606 cid->mnc += (buf[2] >> 4) * 1;
2607 } else {
2608 cid->mnc = (buf[2] & 0xf) * 100;
2609 cid->mnc += (buf[2] >> 4) * 10;
2610 cid->mnc += (buf[1] >> 4) * 1;
2611 }
2612
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002613 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2614 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002615}
2616
Harald Welte0f255852009-11-12 14:48:42 +01002617/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002618int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002619{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002620 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002621 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002622
Harald Welteaf109b92010-07-22 18:14:36 +02002623 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002624
2625 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2626 return -EINVAL;
2627 cur++;
2628
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002629 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002630 cur += 2;
2631
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002632 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002633 cur += 2;
2634
2635 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2636 binf->freq_qual = *cur >> 2;
2637
Harald Welteaf109b92010-07-22 18:14:36 +02002638 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002639 binf->arfcn |= *cur++;
2640
2641 if (binf->info_type & IPAC_BINF_RXLEV)
2642 binf->rx_lev = *cur & 0x3f;
2643 cur++;
2644
2645 if (binf->info_type & IPAC_BINF_RXQUAL)
2646 binf->rx_qual = *cur & 0x7;
2647 cur++;
2648
2649 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002650 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002651 cur += 2;
2652
2653 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002654 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002655 cur += 2;
2656
2657 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002658 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002659 cur += 4;
2660
Harald Weltea780a3d2010-07-30 22:34:42 +02002661#if 0
2662 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002663 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002664#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002665 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002666 cur++;
2667
Harald Welteb40a38f2009-11-13 11:56:05 +01002668 ipac_parse_cgi(&binf->cgi, cur);
2669 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002670
2671 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2672 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2673 cur += sizeof(binf->ba_list_si2);
2674 }
2675
2676 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2677 memcpy(binf->ba_list_si2bis, cur,
2678 sizeof(binf->ba_list_si2bis));
2679 cur += sizeof(binf->ba_list_si2bis);
2680 }
2681
2682 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2683 memcpy(binf->ba_list_si2ter, cur,
2684 sizeof(binf->ba_list_si2ter));
2685 cur += sizeof(binf->ba_list_si2ter);
2686 }
2687
2688 return 0;
2689}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002690
2691void abis_nm_clear_queue(struct gsm_bts *bts)
2692{
2693 struct msgb *msg;
2694
2695 while (!llist_empty(&bts->abis_queue)) {
2696 msg = msgb_dequeue(&bts->abis_queue);
2697 msgb_free(msg);
2698 }
2699
2700 bts->abis_nm_pend = 0;
2701}