blob: e9dc1d6d639e35097dd195537fe8eef0d8a7aeef [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;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200551 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200552 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200553 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000554 }
Harald Weltead384642008-12-26 10:20:07 +0000555#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000556 /* check if last message is to be acked */
557 if (is_ack_nack(nmh->last_msgtype)) {
558 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100559 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000560 /* we got our ACK, continue sending the next msg */
561 } else if (mt == MT_NACK(nmh->last_msgtype)) {
562 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100563 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000564 /* FIXME: somehow signal this to the caller */
565 } else {
566 /* really strange things happen */
567 return -EINVAL;
568 }
569 }
Harald Weltead384642008-12-26 10:20:07 +0000570#endif
571
Harald Welte97ed1e72009-02-06 13:38:02 +0000572 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000573 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100574 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000575 break;
Harald Welte34a99682009-02-13 02:41:40 +0000576 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100577 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000578 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000579 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100580 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000581 break;
Harald Welte1989c082009-08-06 17:58:31 +0200582 case NM_MT_CONN_MDROP_LINK_ACK:
583 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
584 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100585 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200586 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100587 break;
588 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200589 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100590 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100591 case NM_MT_SET_BTS_ATTR_ACK:
592 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200593 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
594 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Weltefd355a32011-03-04 13:41:31 +0100595 }
596 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000597 }
598
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200599 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100600 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000601}
602
Harald Welte677c21f2009-02-17 13:22:23 +0000603static int abis_nm_rx_ipacc(struct msgb *mb);
604
605static int abis_nm_rcvmsg_manuf(struct msgb *mb)
606{
607 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200608 struct e1inp_sign_link *sign_link = mb->dst;
609 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000610
611 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100612 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200613 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000614 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200615 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000616 break;
617 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100618 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
619 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000620 rc = 0;
621 break;
622 }
623
624 return rc;
625}
626
Harald Welte52b1f982008-12-23 20:25:15 +0000627/* High-Level API */
628/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000629int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000630{
Harald Welte52b1f982008-12-23 20:25:15 +0000631 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000632 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000633
634 /* Various consistency checks */
635 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100636 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000637 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200638 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
639 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000640 }
641 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100642 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000643 oh->sequence);
644 return -EINVAL;
645 }
Harald Welte702d8702008-12-26 20:25:35 +0000646#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200647 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000648 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000649 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100650 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000651 oh->length + sizeof(*oh), l2_len);
652 return -EINVAL;
653 }
Harald Welte702d8702008-12-26 20:25:35 +0000654 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100655 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 +0000656#endif
Harald Weltead384642008-12-26 10:20:07 +0000657 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000658
659 switch (oh->mdisc) {
660 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000661 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000662 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000663 case ABIS_OM_MDISC_MANUF:
664 rc = abis_nm_rcvmsg_manuf(msg);
665 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000666 case ABIS_OM_MDISC_MMI:
667 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100668 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000669 oh->mdisc);
670 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000671 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100672 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000673 oh->mdisc);
674 return -EINVAL;
675 }
676
Harald Weltead384642008-12-26 10:20:07 +0000677 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000678 return rc;
679}
680
681#if 0
682/* initialized all resources */
683struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
684{
685 struct abis_nm_h *nmh;
686
687 nmh = malloc(sizeof(*nmh));
688 if (!nmh)
689 return NULL;
690
691 nmh->cfg = cfg;
692
693 return nmh;
694}
695
696/* free all resources */
697void abis_nm_fini(struct abis_nm_h *nmh)
698{
699 free(nmh);
700}
701#endif
702
703/* Here we are trying to define a high-level API that can be used by
704 * the actual BSC implementation. However, the architecture is currently
705 * still under design. Ideally the calls to this API would be synchronous,
706 * while the underlying stack behind the APi runs in a traditional select
707 * based state machine.
708 */
709
Harald Welte4724f992009-01-18 18:01:49 +0000710/* 6.2 Software Load: */
711enum sw_state {
712 SW_STATE_NONE,
713 SW_STATE_WAIT_INITACK,
714 SW_STATE_WAIT_SEGACK,
715 SW_STATE_WAIT_ENDACK,
716 SW_STATE_WAIT_ACTACK,
717 SW_STATE_ERROR,
718};
Harald Welte52b1f982008-12-23 20:25:15 +0000719
Harald Welte52b1f982008-12-23 20:25:15 +0000720struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000721 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800722 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000723 gsm_cbfn *cbfn;
724 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000725 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000726
Harald Welte52b1f982008-12-23 20:25:15 +0000727 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200728 uint8_t obj_class;
729 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000730
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200731 uint8_t file_id[255];
732 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000733
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200734 uint8_t file_version[255];
735 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000736
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200737 uint8_t window_size;
738 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000739
740 int fd;
741 FILE *stream;
742 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000743 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000744};
745
Harald Welte4724f992009-01-18 18:01:49 +0000746static struct abis_nm_sw g_sw;
747
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100748static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
749{
750 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
751 msgb_v_put(msg, NM_ATT_SW_DESCR);
752 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
753 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
754 sw->file_version);
755 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
756 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
757 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
758 sw->file_version);
759 } else {
760 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
761 }
762}
763
Harald Welte4724f992009-01-18 18:01:49 +0000764/* 6.2.1 / 8.3.1: Load Data Initiate */
765static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000766{
Harald Welte4724f992009-01-18 18:01:49 +0000767 struct abis_om_hdr *oh;
768 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200769 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000770
771 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
772 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
773 sw->obj_instance[0], sw->obj_instance[1],
774 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100775
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100776 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000777 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
778
779 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000780}
781
Harald Welte1602ade2009-01-29 21:12:39 +0000782static int is_last_line(FILE *stream)
783{
784 char next_seg_buf[256];
785 long pos;
786
787 /* check if we're sending the last line */
788 pos = ftell(stream);
789 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
790 fseek(stream, pos, SEEK_SET);
791 return 1;
792 }
793
794 fseek(stream, pos, SEEK_SET);
795 return 0;
796}
797
Harald Welte4724f992009-01-18 18:01:49 +0000798/* 6.2.2 / 8.3.2 Load Data Segment */
799static int sw_load_segment(struct abis_nm_sw *sw)
800{
801 struct abis_om_hdr *oh;
802 struct msgb *msg = nm_msgb_alloc();
803 char seg_buf[256];
804 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000805 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200806 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000807
808 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000809
810 switch (sw->bts->type) {
811 case GSM_BTS_TYPE_BS11:
812 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
813 perror("fgets reading segment");
814 return -EINVAL;
815 }
816 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000817
818 /* check if we're sending the last line */
819 sw->last_seg = is_last_line(sw->stream);
820 if (sw->last_seg)
821 seg_buf[1] = 0;
822 else
823 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000824
825 len = strlen(line_buf) + 2;
826 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200827 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000828 /* BS11 wants CR + LF in excess of the TLV length !?! */
829 tlv[1] -= 2;
830
831 /* we only now know the exact length for the OM hdr */
832 len = strlen(line_buf)+2;
833 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100834 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200835 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100836 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
837 if (len < 0) {
838 perror("read failed");
839 return -EINVAL;
840 }
841
842 if (len != IPACC_SEGMENT_SIZE)
843 sw->last_seg = 1;
844
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100845 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200846 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100847 len += 3;
848 break;
849 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000850 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100851 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000852 /* FIXME: Other BTS types */
853 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000854 }
Harald Welte4724f992009-01-18 18:01:49 +0000855
Harald Welte4724f992009-01-18 18:01:49 +0000856 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
857 sw->obj_instance[0], sw->obj_instance[1],
858 sw->obj_instance[2]);
859
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100860 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000861}
862
863/* 6.2.4 / 8.3.4 Load Data End */
864static int sw_load_end(struct abis_nm_sw *sw)
865{
866 struct abis_om_hdr *oh;
867 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200868 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000869
870 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
871 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
872 sw->obj_instance[0], sw->obj_instance[1],
873 sw->obj_instance[2]);
874
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100875 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000876 return abis_nm_sendmsg(sw->bts, msg);
877}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000878
Harald Welte52b1f982008-12-23 20:25:15 +0000879/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000880static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000881{
Harald Welte4724f992009-01-18 18:01:49 +0000882 struct abis_om_hdr *oh;
883 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200884 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000885
Harald Welte4724f992009-01-18 18:01:49 +0000886 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
887 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
888 sw->obj_instance[0], sw->obj_instance[1],
889 sw->obj_instance[2]);
890
891 /* FIXME: this is BS11 specific format */
892 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
893 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
894 sw->file_version);
895
896 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000897}
Harald Welte4724f992009-01-18 18:01:49 +0000898
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100899struct sdp_firmware {
900 char magic[4];
901 char more_magic[4];
902 unsigned int header_length;
903 unsigned int file_length;
904} __attribute__ ((packed));
905
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100906static int parse_sdp_header(struct abis_nm_sw *sw)
907{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100908 struct sdp_firmware firmware_header;
909 int rc;
910 struct stat stat;
911
912 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
913 if (rc != sizeof(firmware_header)) {
914 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
915 return -1;
916 }
917
918 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
919 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
920 return -1;
921 }
922
923 if (firmware_header.more_magic[0] != 0x10 ||
924 firmware_header.more_magic[1] != 0x02 ||
925 firmware_header.more_magic[2] != 0x00 ||
926 firmware_header.more_magic[3] != 0x00) {
927 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
928 return -1;
929 }
930
931
932 if (fstat(sw->fd, &stat) == -1) {
933 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
934 return -1;
935 }
936
937 if (ntohl(firmware_header.file_length) != stat.st_size) {
938 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
939 return -1;
940 }
941
942 /* go back to the start as we checked the whole filesize.. */
943 lseek(sw->fd, 0l, SEEK_SET);
944 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
945 "There might be checksums in the file that are not\n"
946 "verified and incomplete firmware might be flashed.\n"
947 "There is absolutely no WARRANTY that flashing will\n"
948 "work.\n");
949 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100950}
951
Harald Welte4724f992009-01-18 18:01:49 +0000952static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
953{
954 char file_id[12+1];
955 char file_version[80+1];
956 int rc;
957
958 sw->fd = open(fname, O_RDONLY);
959 if (sw->fd < 0)
960 return sw->fd;
961
962 switch (sw->bts->type) {
963 case GSM_BTS_TYPE_BS11:
964 sw->stream = fdopen(sw->fd, "r");
965 if (!sw->stream) {
966 perror("fdopen");
967 return -1;
968 }
969 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200970 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +0000971 file_id, file_version);
972 if (rc != 2) {
973 perror("parsing header line of software file");
974 return -1;
975 }
976 strcpy((char *)sw->file_id, file_id);
977 sw->file_id_len = strlen(file_id);
978 strcpy((char *)sw->file_version, file_version);
979 sw->file_version_len = strlen(file_version);
980 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +0000981 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +0000982 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100983 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100984 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100985 rc = parse_sdp_header(sw);
986 if (rc < 0) {
987 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
988 return -1;
989 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100990
991 strcpy((char *)sw->file_id, "id");
992 sw->file_id_len = 3;
993 strcpy((char *)sw->file_version, "version");
994 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100995 break;
Harald Welte4724f992009-01-18 18:01:49 +0000996 default:
997 /* We don't know how to treat them yet */
998 close(sw->fd);
999 return -EINVAL;
1000 }
1001
1002 return 0;
1003}
1004
1005static void sw_close_file(struct abis_nm_sw *sw)
1006{
1007 switch (sw->bts->type) {
1008 case GSM_BTS_TYPE_BS11:
1009 fclose(sw->stream);
1010 break;
1011 default:
1012 close(sw->fd);
1013 break;
1014 }
1015}
1016
1017/* Fill the window */
1018static int sw_fill_window(struct abis_nm_sw *sw)
1019{
1020 int rc;
1021
1022 while (sw->seg_in_window < sw->window_size) {
1023 rc = sw_load_segment(sw);
1024 if (rc < 0)
1025 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001026 if (sw->last_seg)
1027 break;
Harald Welte4724f992009-01-18 18:01:49 +00001028 }
1029 return 0;
1030}
1031
1032/* callback function from abis_nm_rcvmsg() handler */
1033static int abis_nm_rcvmsg_sw(struct msgb *mb)
1034{
1035 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001036 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001037 int rc = -1;
1038 struct abis_nm_sw *sw = &g_sw;
1039 enum sw_state old_state = sw->state;
1040
Harald Welte3ffd1372009-02-01 22:15:49 +00001041 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001042
1043 switch (sw->state) {
1044 case SW_STATE_WAIT_INITACK:
1045 switch (foh->msg_type) {
1046 case NM_MT_LOAD_INIT_ACK:
1047 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001048 if (sw->cbfn)
1049 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1050 NM_MT_LOAD_INIT_ACK, mb,
1051 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001052 rc = sw_fill_window(sw);
1053 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001054 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001055 break;
1056 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001057 if (sw->forced) {
1058 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1059 "Init NACK\n");
1060 if (sw->cbfn)
1061 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1062 NM_MT_LOAD_INIT_ACK, mb,
1063 sw->cb_data, NULL);
1064 rc = sw_fill_window(sw);
1065 sw->state = SW_STATE_WAIT_SEGACK;
1066 } else {
1067 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001068 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001069 if (sw->cbfn)
1070 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1071 NM_MT_LOAD_INIT_NACK, mb,
1072 sw->cb_data, NULL);
1073 sw->state = SW_STATE_ERROR;
1074 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001075 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001076 break;
1077 }
1078 break;
1079 case SW_STATE_WAIT_SEGACK:
1080 switch (foh->msg_type) {
1081 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001082 if (sw->cbfn)
1083 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1084 NM_MT_LOAD_SEG_ACK, mb,
1085 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001086 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001087 if (!sw->last_seg) {
1088 /* fill window with more segments */
1089 rc = sw_fill_window(sw);
1090 sw->state = SW_STATE_WAIT_SEGACK;
1091 } else {
1092 /* end the transfer */
1093 sw->state = SW_STATE_WAIT_ENDACK;
1094 rc = sw_load_end(sw);
1095 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001096 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001097 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001098 case NM_MT_LOAD_ABORT:
1099 if (sw->cbfn)
1100 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1101 NM_MT_LOAD_ABORT, mb,
1102 sw->cb_data, NULL);
1103 break;
Harald Welte4724f992009-01-18 18:01:49 +00001104 }
1105 break;
1106 case SW_STATE_WAIT_ENDACK:
1107 switch (foh->msg_type) {
1108 case NM_MT_LOAD_END_ACK:
1109 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001110 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1111 sw->bts->nr);
1112 sw->state = SW_STATE_NONE;
1113 if (sw->cbfn)
1114 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1115 NM_MT_LOAD_END_ACK, mb,
1116 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001117 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001118 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001119 break;
1120 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001121 if (sw->forced) {
1122 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1123 "End NACK\n");
1124 sw->state = SW_STATE_NONE;
1125 if (sw->cbfn)
1126 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1127 NM_MT_LOAD_END_ACK, mb,
1128 sw->cb_data, NULL);
1129 } else {
1130 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001131 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001132 sw->state = SW_STATE_ERROR;
1133 if (sw->cbfn)
1134 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1135 NM_MT_LOAD_END_NACK, mb,
1136 sw->cb_data, NULL);
1137 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001138 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001139 break;
1140 }
1141 case SW_STATE_WAIT_ACTACK:
1142 switch (foh->msg_type) {
1143 case NM_MT_ACTIVATE_SW_ACK:
1144 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001145 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001146 sw->state = SW_STATE_NONE;
1147 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001148 if (sw->cbfn)
1149 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1150 NM_MT_ACTIVATE_SW_ACK, mb,
1151 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001152 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001153 break;
1154 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001155 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001156 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001157 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001158 if (sw->cbfn)
1159 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1160 NM_MT_ACTIVATE_SW_NACK, mb,
1161 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001162 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001163 break;
1164 }
1165 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001166 switch (foh->msg_type) {
1167 case NM_MT_ACTIVATE_SW_ACK:
1168 rc = 0;
1169 break;
1170 }
1171 break;
Harald Welte4724f992009-01-18 18:01:49 +00001172 case SW_STATE_ERROR:
1173 break;
1174 }
1175
1176 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001177 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001178 foh->msg_type, old_state, sw->state);
1179
1180 return rc;
1181}
1182
1183/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001184int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001185 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001186 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001187{
1188 struct abis_nm_sw *sw = &g_sw;
1189 int rc;
1190
Harald Welte5e4d1b32009-02-01 13:36:56 +00001191 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1192 bts->nr, fname);
1193
Harald Welte4724f992009-01-18 18:01:49 +00001194 if (sw->state != SW_STATE_NONE)
1195 return -EBUSY;
1196
1197 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001198 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001199
1200 switch (bts->type) {
1201 case GSM_BTS_TYPE_BS11:
1202 sw->obj_class = NM_OC_SITE_MANAGER;
1203 sw->obj_instance[0] = 0xff;
1204 sw->obj_instance[1] = 0xff;
1205 sw->obj_instance[2] = 0xff;
1206 break;
1207 case GSM_BTS_TYPE_NANOBTS:
1208 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001209 sw->obj_instance[0] = sw->bts->nr;
1210 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001211 sw->obj_instance[2] = 0xff;
1212 break;
1213 case GSM_BTS_TYPE_UNKNOWN:
1214 default:
1215 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1216 return -1;
1217 break;
1218 }
Harald Welte4724f992009-01-18 18:01:49 +00001219 sw->window_size = win_size;
1220 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001221 sw->cbfn = cbfn;
1222 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001223 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001224
1225 rc = sw_open_file(sw, fname);
1226 if (rc < 0) {
1227 sw->state = SW_STATE_NONE;
1228 return rc;
1229 }
1230
1231 return sw_load_init(sw);
1232}
Harald Welte52b1f982008-12-23 20:25:15 +00001233
Harald Welte1602ade2009-01-29 21:12:39 +00001234int abis_nm_software_load_status(struct gsm_bts *bts)
1235{
1236 struct abis_nm_sw *sw = &g_sw;
1237 struct stat st;
1238 int rc, percent;
1239
1240 rc = fstat(sw->fd, &st);
1241 if (rc < 0) {
1242 perror("ERROR during stat");
1243 return rc;
1244 }
1245
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001246 if (sw->stream)
1247 percent = (ftell(sw->stream) * 100) / st.st_size;
1248 else
1249 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001250 return percent;
1251}
1252
Harald Welte5e4d1b32009-02-01 13:36:56 +00001253/* Activate the specified software into the BTS */
1254int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1255 gsm_cbfn *cbfn, void *cb_data)
1256{
1257 struct abis_nm_sw *sw = &g_sw;
1258 int rc;
1259
1260 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1261 bts->nr, fname);
1262
1263 if (sw->state != SW_STATE_NONE)
1264 return -EBUSY;
1265
1266 sw->bts = bts;
1267 sw->obj_class = NM_OC_SITE_MANAGER;
1268 sw->obj_instance[0] = 0xff;
1269 sw->obj_instance[1] = 0xff;
1270 sw->obj_instance[2] = 0xff;
1271 sw->state = SW_STATE_WAIT_ACTACK;
1272 sw->cbfn = cbfn;
1273 sw->cb_data = cb_data;
1274
1275 /* Open the file in order to fill some sw struct members */
1276 rc = sw_open_file(sw, fname);
1277 if (rc < 0) {
1278 sw->state = SW_STATE_NONE;
1279 return rc;
1280 }
1281 sw_close_file(sw);
1282
1283 return sw_activate(sw);
1284}
1285
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001286static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1287 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001288{
Harald Welteadaf08b2009-01-18 11:08:10 +00001289 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001290 ch->bts_port = bts_port;
1291 ch->timeslot = ts_nr;
1292 ch->subslot = subslot_nr;
1293}
1294
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001295int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1296 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1297 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001298{
1299 struct abis_om_hdr *oh;
1300 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001301 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001302 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001303
1304 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1305 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1306 bts->bts_nr, trx_nr, 0xff);
1307
Harald Welte8470bf22008-12-25 23:28:35 +00001308 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001309
1310 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1311 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1312
1313 return abis_nm_sendmsg(bts, msg);
1314}
1315
1316/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1317int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001318 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001319{
Harald Welte8470bf22008-12-25 23:28:35 +00001320 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001321 struct abis_om_hdr *oh;
1322 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001323 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001324
1325 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001326 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001327 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1328
1329 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1330 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1331
1332 return abis_nm_sendmsg(bts, msg);
1333}
1334
1335#if 0
1336int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1337 struct abis_nm_abis_channel *chan)
1338{
1339}
1340#endif
1341
1342int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001343 uint8_t e1_port, uint8_t e1_timeslot,
1344 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001345{
1346 struct gsm_bts *bts = ts->trx->bts;
1347 struct abis_om_hdr *oh;
1348 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001349 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001350
1351 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1352 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001353 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001354
1355 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1356 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1357
Harald Weltef325eb42009-02-19 17:07:39 +00001358 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1359 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001360 e1_port, e1_timeslot, e1_subslot);
1361
Harald Welte52b1f982008-12-23 20:25:15 +00001362 return abis_nm_sendmsg(bts, msg);
1363}
1364
1365#if 0
1366int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1367 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001368 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001369{
1370}
1371#endif
1372
Harald Weltefe568f22012-08-14 19:15:57 +02001373/* Chapter 8.11.1 */
1374int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1375 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1376 uint8_t *attr, uint8_t attr_len)
1377{
1378 struct abis_om_hdr *oh;
1379 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001380
1381 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1382
1383 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1384 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1385 bts_nr, trx_nr, ts_nr);
1386 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1387
1388 return abis_nm_sendmsg(bts, msg);
1389}
1390
Harald Welte22af0db2009-02-14 15:41:08 +00001391/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001392int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001393{
1394 struct abis_om_hdr *oh;
1395 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001396 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001397
1398 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1399
1400 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001401 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 +00001402 cur = msgb_put(msg, attr_len);
1403 memcpy(cur, attr, attr_len);
1404
1405 return abis_nm_sendmsg(bts, msg);
1406}
1407
1408/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001409int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001410{
1411 struct abis_om_hdr *oh;
1412 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001413 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001414
1415 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1416
1417 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1418 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001419 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001420 cur = msgb_put(msg, attr_len);
1421 memcpy(cur, attr, attr_len);
1422
1423 return abis_nm_sendmsg(trx->bts, msg);
1424}
1425
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001426static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1427 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001428{
1429 int i;
1430
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001431 *reason = "Reason unknown";
1432
Harald Welte39c7deb2009-08-09 21:49:48 +02001433 /* As it turns out, the BS-11 has some very peculiar restrictions
1434 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301435 switch (ts->trx->bts->type) {
1436 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001437 switch (chan_comb) {
1438 case NM_CHANC_TCHHalf:
1439 case NM_CHANC_TCHHalf2:
1440 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001441 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001442 return -EINVAL;
1443 case NM_CHANC_SDCCH:
1444 /* only one SDCCH/8 per TRX */
1445 for (i = 0; i < TRX_NR_TS; i++) {
1446 if (i == ts->nr)
1447 continue;
1448 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001449 NM_CHANC_SDCCH) {
1450 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001451 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001452 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001453 }
1454 /* not allowed for TS0 of BCCH-TRX */
1455 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001456 ts->nr == 0) {
1457 *reason = "SDCCH/8 must be on TS0.";
1458 return -EINVAL;
1459 }
1460
Harald Welte39c7deb2009-08-09 21:49:48 +02001461 /* not on the same TRX that has a BCCH+SDCCH4
1462 * combination */
1463 if (ts->trx == ts->trx->bts->c0 &&
1464 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001465 ts->trx->ts[0].nm_chan_comb == 8)) {
1466 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1467 return -EINVAL;
1468 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001469 break;
1470 case NM_CHANC_mainBCCH:
1471 case NM_CHANC_BCCHComb:
1472 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001473 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1474 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001475 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001476 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001477 break;
1478 case NM_CHANC_BCCH:
1479 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001480 if (ts->trx != ts->trx->bts->c0) {
1481 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001482 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001483 }
1484 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1485 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001486 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001487 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001488 break;
1489 case 8: /* this is not like 08.58, but in fact
1490 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1491 /* FIXME: only one CBCH allowed per cell */
1492 break;
1493 }
Harald Welted6575f92009-12-02 02:45:23 +05301494 break;
1495 case GSM_BTS_TYPE_NANOBTS:
1496 switch (ts->nr) {
1497 case 0:
1498 if (ts->trx->nr == 0) {
1499 /* only on TRX0 */
1500 switch (chan_comb) {
1501 case NM_CHANC_BCCH:
1502 case NM_CHANC_mainBCCH:
1503 case NM_CHANC_BCCHComb:
1504 return 0;
1505 break;
1506 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001507 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301508 return -EINVAL;
1509 }
1510 } else {
1511 switch (chan_comb) {
1512 case NM_CHANC_TCHFull:
1513 case NM_CHANC_TCHHalf:
1514 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1515 return 0;
1516 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001517 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301518 return -EINVAL;
1519 }
1520 }
1521 break;
1522 case 1:
1523 if (ts->trx->nr == 0) {
1524 switch (chan_comb) {
1525 case NM_CHANC_SDCCH_CBCH:
1526 if (ts->trx->ts[0].nm_chan_comb ==
1527 NM_CHANC_mainBCCH)
1528 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001529 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301530 return -EINVAL;
1531 case NM_CHANC_SDCCH:
1532 case NM_CHANC_TCHFull:
1533 case NM_CHANC_TCHHalf:
1534 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1535 case NM_CHANC_IPAC_TCHFull_PDCH:
1536 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001537 default:
1538 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1539 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301540 }
1541 } else {
1542 switch (chan_comb) {
1543 case NM_CHANC_SDCCH:
1544 case NM_CHANC_TCHFull:
1545 case NM_CHANC_TCHHalf:
1546 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1547 return 0;
1548 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001549 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301550 return -EINVAL;
1551 }
1552 }
1553 break;
1554 case 2:
1555 case 3:
1556 case 4:
1557 case 5:
1558 case 6:
1559 case 7:
1560 switch (chan_comb) {
1561 case NM_CHANC_TCHFull:
1562 case NM_CHANC_TCHHalf:
1563 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1564 return 0;
1565 case NM_CHANC_IPAC_PDCH:
1566 case NM_CHANC_IPAC_TCHFull_PDCH:
1567 if (ts->trx->nr == 0)
1568 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001569 else {
1570 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301571 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001572 }
Harald Welted6575f92009-12-02 02:45:23 +05301573 }
1574 break;
1575 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001576 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301577 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001578 case GSM_BTS_TYPE_OSMO_SYSMO:
1579 /* no known restrictions */
1580 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301581 default:
1582 /* unknown BTS type */
1583 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001584 }
1585 return 0;
1586}
1587
Harald Welte22af0db2009-02-14 15:41:08 +00001588/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001589int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001590{
1591 struct gsm_bts *bts = ts->trx->bts;
1592 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001593 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001594 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001595 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001596 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001597
1598 if (bts->type == GSM_BTS_TYPE_BS11)
1599 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001600
Harald Weltef325eb42009-02-19 17:07:39 +00001601 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001602 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001603 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001604 LOGP(DNM, LOGL_ERROR,
1605 "Invalid Channel Combination %d on %s. Reason: %s\n",
1606 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001607 return -EINVAL;
1608 }
1609 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001610
Harald Welte52b1f982008-12-23 20:25:15 +00001611 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001612 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001613 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001614 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001615 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001616 if (ts->hopping.enabled) {
1617 unsigned int i;
1618 uint8_t *len;
1619
Harald Welte6e0cd042009-09-12 13:05:33 +02001620 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1621 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001622
1623 /* build the ARFCN list */
1624 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1625 len = msgb_put(msg, 1);
1626 *len = 0;
1627 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1628 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1629 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001630 /* At least BS-11 wants a TLV16 here */
1631 if (bts->type == GSM_BTS_TYPE_BS11)
1632 *len += 1;
1633 else
1634 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001635 }
1636 }
Harald Weltee0590df2009-02-15 03:34:15 +00001637 }
Harald Welte135a6482011-05-30 12:09:13 +02001638 if (ts->tsc == -1)
1639 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1640 else
1641 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001642 if (bts->type == GSM_BTS_TYPE_BS11)
1643 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001644
1645 return abis_nm_sendmsg(bts, msg);
1646}
1647
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001648int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1649 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001650{
1651 struct abis_om_hdr *oh;
1652 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001653 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1654 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001655
1656 if (nack) {
1657 len += 2;
1658 msgtype = NM_MT_SW_ACT_REQ_NACK;
1659 }
Harald Welte34a99682009-02-13 02:41:40 +00001660
1661 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001662 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1663
Harald Welte34a99682009-02-13 02:41:40 +00001664 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001665 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001666 memcpy(ptr, attr, att_len);
1667 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001668 if (nack)
1669 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001670
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001671 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001672}
1673
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001674int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001675{
Harald Welte8470bf22008-12-25 23:28:35 +00001676 struct msgb *msg = nm_msgb_alloc();
1677 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001678 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001679
1680 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1681 fill_om_hdr(oh, len);
1682 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001683 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001684
1685 return abis_nm_sendmsg(bts, msg);
1686}
1687
1688/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001689static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001690{
1691 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001692 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001693
1694 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001695 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001696 0xff, 0xff, 0xff);
1697
1698 return abis_nm_sendmsg(bts, msg);
1699}
1700
Harald Welte34a99682009-02-13 02:41:40 +00001701/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001702int 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 +00001703{
1704 struct abis_om_hdr *oh;
1705 struct msgb *msg = nm_msgb_alloc();
1706
1707 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1708 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1709
Harald Welte15c61722011-05-22 22:45:37 +02001710 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001711 DEBUGPC(DNM, "Sending OPSTART\n");
1712
Harald Welte34a99682009-02-13 02:41:40 +00001713 return abis_nm_sendmsg(bts, msg);
1714}
1715
1716/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001717int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1718 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001719{
1720 struct abis_om_hdr *oh;
1721 struct msgb *msg = nm_msgb_alloc();
1722
1723 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1724 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1725 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1726
1727 return abis_nm_sendmsg(bts, msg);
1728}
1729
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001730int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1731 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001732{
1733 struct abis_om_hdr *oh;
1734 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001735 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001736
1737 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1738 e1_port0, ts0, e1_port1, ts1);
1739
1740 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1741 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1742 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1743
1744 attr = msgb_put(msg, 3);
1745 attr[0] = NM_ATT_MDROP_LINK;
1746 attr[1] = e1_port0;
1747 attr[2] = ts0;
1748
1749 attr = msgb_put(msg, 3);
1750 attr[0] = NM_ATT_MDROP_NEXT;
1751 attr[1] = e1_port1;
1752 attr[2] = ts1;
1753
1754 return abis_nm_sendmsg(bts, msg);
1755}
Harald Welte34a99682009-02-13 02:41:40 +00001756
Harald Weltec7310382009-08-08 00:02:36 +02001757/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001758int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1759 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1760 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001761{
1762 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001763
Harald Welte15c61722011-05-22 22:45:37 +02001764 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001765
1766 if (!msg)
1767 msg = nm_msgb_alloc();
1768
1769 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1770 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1771 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1772 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001773 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001774
1775 return abis_nm_sendmsg(bts, msg);
1776}
1777
Harald Welte52b1f982008-12-23 20:25:15 +00001778int abis_nm_event_reports(struct gsm_bts *bts, int on)
1779{
1780 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001781 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001782 else
Harald Welte227d4072009-01-03 08:16:25 +00001783 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001784}
1785
Harald Welte47d88ae2009-01-04 12:02:08 +00001786/* Siemens (or BS-11) specific commands */
1787
Harald Welte3ffd1372009-02-01 22:15:49 +00001788int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1789{
1790 if (reconnect == 0)
1791 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1792 else
1793 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1794}
1795
Harald Welteb8427972009-02-05 19:27:17 +00001796int abis_nm_bs11_restart(struct gsm_bts *bts)
1797{
1798 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1799}
1800
1801
Harald Welte268bb402009-02-01 19:11:56 +00001802struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001803 uint16_t year;
1804 uint8_t month;
1805 uint8_t day;
1806 uint8_t hour;
1807 uint8_t min;
1808 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001809} __attribute__((packed));
1810
1811
1812void get_bs11_date_time(struct bs11_date_time *aet)
1813{
1814 time_t t;
1815 struct tm *tm;
1816
1817 t = time(NULL);
1818 tm = localtime(&t);
1819 aet->sec = tm->tm_sec;
1820 aet->min = tm->tm_min;
1821 aet->hour = tm->tm_hour;
1822 aet->day = tm->tm_mday;
1823 aet->month = tm->tm_mon;
1824 aet->year = htons(1900 + tm->tm_year);
1825}
1826
Harald Welte05188ee2009-01-18 11:39:08 +00001827int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001828{
Harald Welte4668fda2009-01-03 08:19:29 +00001829 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001830}
1831
Harald Welte05188ee2009-01-18 11:39:08 +00001832int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001833{
1834 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001835 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001836 else
Harald Welte4668fda2009-01-03 08:19:29 +00001837 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001838}
Harald Welte47d88ae2009-01-04 12:02:08 +00001839
Harald Welte05188ee2009-01-18 11:39:08 +00001840int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001841 enum abis_bs11_objtype type, uint8_t idx,
1842 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001843{
1844 struct abis_om_hdr *oh;
1845 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001846 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001847
1848 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001849 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001850 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001851 cur = msgb_put(msg, attr_len);
1852 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001853
1854 return abis_nm_sendmsg(bts, msg);
1855}
1856
Harald Welte78fc0d42009-02-19 02:50:57 +00001857int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001858 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001859{
1860 struct abis_om_hdr *oh;
1861 struct msgb *msg = nm_msgb_alloc();
1862
1863 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1864 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1865 NM_OC_BS11, type, 0, idx);
1866
1867 return abis_nm_sendmsg(bts, msg);
1868}
1869
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001870int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001871{
1872 struct abis_om_hdr *oh;
1873 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001874 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001875
1876 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001877 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001878 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1879 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001880
1881 return abis_nm_sendmsg(bts, msg);
1882}
1883
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001884int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001885{
1886 struct abis_om_hdr *oh;
1887 struct msgb *msg = nm_msgb_alloc();
1888
1889 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1890 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001891 idx, 0xff, 0xff);
1892
1893 return abis_nm_sendmsg(bts, msg);
1894}
1895
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001896int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001897{
1898 struct abis_om_hdr *oh;
1899 struct msgb *msg = nm_msgb_alloc();
1900
1901 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1902 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1903 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001904
1905 return abis_nm_sendmsg(bts, msg);
1906}
Harald Welte05188ee2009-01-18 11:39:08 +00001907
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001908static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001909int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1910{
1911 struct abis_om_hdr *oh;
1912 struct msgb *msg = nm_msgb_alloc();
1913
1914 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1915 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1916 0xff, 0xff, 0xff);
1917 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1918
1919 return abis_nm_sendmsg(bts, msg);
1920}
1921
Harald Welteb6c92ae2009-02-21 20:15:32 +00001922/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001923int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1924 uint8_t e1_timeslot, uint8_t e1_subslot,
1925 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001926{
1927 struct abis_om_hdr *oh;
1928 struct abis_nm_channel *ch;
1929 struct msgb *msg = nm_msgb_alloc();
1930
1931 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001932 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001933 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1934
1935 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1936 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001937 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001938
1939 return abis_nm_sendmsg(bts, msg);
1940}
1941
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001942int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001943{
1944 struct abis_om_hdr *oh;
1945 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001946
1947 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001948 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001949 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1950 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1951
1952 return abis_nm_sendmsg(trx->bts, msg);
1953}
1954
Harald Welte78fc0d42009-02-19 02:50:57 +00001955int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1956{
1957 struct abis_om_hdr *oh;
1958 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001959 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00001960
1961 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1962 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1963 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1964 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1965
1966 return abis_nm_sendmsg(trx->bts, msg);
1967}
1968
Harald Welteaaf02d92009-04-29 13:25:57 +00001969int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1970{
1971 struct abis_om_hdr *oh;
1972 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001973 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00001974
1975 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1976 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1977 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00001978 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00001979
1980 return abis_nm_sendmsg(bts, msg);
1981}
1982
Harald Welteef061952009-05-17 12:43:42 +00001983int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1984{
1985 struct abis_om_hdr *oh;
1986 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001987 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00001988 NM_ATT_BS11_CCLK_TYPE };
1989
1990 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1991 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1992 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1993 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1994
1995 return abis_nm_sendmsg(bts, msg);
1996
1997}
Harald Welteaaf02d92009-04-29 13:25:57 +00001998
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001999//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002000
Harald Welte1bc09062009-01-18 14:17:52 +00002001int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002002{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002003 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2004}
2005
Daniel Willmann4b054c82010-01-07 00:46:26 +01002006int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2007{
2008 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2009}
2010
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002011int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002012{
Harald Welte05188ee2009-01-18 11:39:08 +00002013 struct abis_om_hdr *oh;
2014 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002015 struct bs11_date_time bdt;
2016
2017 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002018
2019 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002020 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002021 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002022 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002023 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002024 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002025 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002026 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002027 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002028 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002029 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002030 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002031 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002032 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002033 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002034 }
Harald Welte05188ee2009-01-18 11:39:08 +00002035
2036 return abis_nm_sendmsg(bts, msg);
2037}
Harald Welte1bc09062009-01-18 14:17:52 +00002038
2039int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2040{
2041 struct abis_om_hdr *oh;
2042 struct msgb *msg;
2043
2044 if (strlen(password) != 10)
2045 return -EINVAL;
2046
2047 msg = nm_msgb_alloc();
2048 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002049 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002050 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002051 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002052
2053 return abis_nm_sendmsg(bts, msg);
2054}
2055
Harald Weltee69f5fb2009-04-28 16:31:38 +00002056/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2057int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2058{
2059 struct abis_om_hdr *oh;
2060 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002061 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002062
2063 msg = nm_msgb_alloc();
2064 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2065 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2066 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002067
2068 if (locked)
2069 tlv_value = BS11_LI_PLL_LOCKED;
2070 else
2071 tlv_value = BS11_LI_PLL_STANDALONE;
2072
2073 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002074
2075 return abis_nm_sendmsg(bts, msg);
2076}
2077
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002078/* Set the calibration value of the PLL (work value/set value)
2079 * It depends on the login which one is changed */
2080int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2081{
2082 struct abis_om_hdr *oh;
2083 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002084 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002085
2086 msg = nm_msgb_alloc();
2087 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2088 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2089 BS11_OBJ_TRX1, 0x00, 0x00);
2090
2091 tlv_value[0] = value>>8;
2092 tlv_value[1] = value&0xff;
2093
2094 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2095
2096 return abis_nm_sendmsg(bts, msg);
2097}
2098
Harald Welte1bc09062009-01-18 14:17:52 +00002099int abis_nm_bs11_get_state(struct gsm_bts *bts)
2100{
2101 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2102}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002103
2104/* BS11 SWL */
2105
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002106void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002107
Harald Welte5e4d1b32009-02-01 13:36:56 +00002108struct abis_nm_bs11_sw {
2109 struct gsm_bts *bts;
2110 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002111 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002112 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002113 struct llist_head file_list;
2114 gsm_cbfn *user_cb; /* specified by the user */
2115};
2116static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2117
2118struct file_list_entry {
2119 struct llist_head list;
2120 char fname[PATH_MAX];
2121};
2122
2123struct file_list_entry *fl_dequeue(struct llist_head *queue)
2124{
2125 struct llist_head *lh;
2126
2127 if (llist_empty(queue))
2128 return NULL;
2129
2130 lh = queue->next;
2131 llist_del(lh);
2132
2133 return llist_entry(lh, struct file_list_entry, list);
2134}
2135
2136static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2137{
2138 char linebuf[255];
2139 struct llist_head *lh, *lh2;
2140 FILE *swl;
2141 int rc = 0;
2142
2143 swl = fopen(bs11_sw->swl_fname, "r");
2144 if (!swl)
2145 return -ENODEV;
2146
2147 /* zero the stale file list, if any */
2148 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2149 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002150 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002151 }
2152
2153 while (fgets(linebuf, sizeof(linebuf), swl)) {
2154 char file_id[12+1];
2155 char file_version[80+1];
2156 struct file_list_entry *fle;
2157 static char dir[PATH_MAX];
2158
2159 if (strlen(linebuf) < 4)
2160 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002161
Harald Welte5e4d1b32009-02-01 13:36:56 +00002162 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2163 if (rc < 0) {
2164 perror("ERR parsing SWL file");
2165 rc = -EINVAL;
2166 goto out;
2167 }
2168 if (rc < 2)
2169 continue;
2170
Harald Welte470ec292009-06-26 20:25:23 +02002171 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002172 if (!fle) {
2173 rc = -ENOMEM;
2174 goto out;
2175 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002176
2177 /* construct new filename */
2178 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2179 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2180 strcat(fle->fname, "/");
2181 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002182
2183 llist_add_tail(&fle->list, &bs11_sw->file_list);
2184 }
2185
2186out:
2187 fclose(swl);
2188 return rc;
2189}
2190
2191/* bs11 swload specific callback, passed to abis_nm core swload */
2192static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2193 struct msgb *msg, void *data, void *param)
2194{
2195 struct abis_nm_bs11_sw *bs11_sw = data;
2196 struct file_list_entry *fle;
2197 int rc = 0;
2198
Harald Welte5e4d1b32009-02-01 13:36:56 +00002199 switch (event) {
2200 case NM_MT_LOAD_END_ACK:
2201 fle = fl_dequeue(&bs11_sw->file_list);
2202 if (fle) {
2203 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002204 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002205 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002206 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002207 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002208 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002209 } else {
2210 /* activate the SWL */
2211 rc = abis_nm_software_activate(bs11_sw->bts,
2212 bs11_sw->swl_fname,
2213 bs11_swload_cbfn,
2214 bs11_sw);
2215 }
2216 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002217 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002218 case NM_MT_LOAD_END_NACK:
2219 case NM_MT_LOAD_INIT_ACK:
2220 case NM_MT_LOAD_INIT_NACK:
2221 case NM_MT_ACTIVATE_SW_NACK:
2222 case NM_MT_ACTIVATE_SW_ACK:
2223 default:
2224 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002225 if (bs11_sw->user_cb)
2226 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002227 break;
2228 }
2229
2230 return rc;
2231}
2232
2233/* Siemens provides a SWL file that is a mere listing of all the other
2234 * files that are part of a software release. We need to upload first
2235 * the list file, and then each file that is listed in the list file */
2236int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002237 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002238{
2239 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2240 struct file_list_entry *fle;
2241 int rc = 0;
2242
2243 INIT_LLIST_HEAD(&bs11_sw->file_list);
2244 bs11_sw->bts = bts;
2245 bs11_sw->win_size = win_size;
2246 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002247 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002248
2249 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2250 rc = bs11_read_swl_file(bs11_sw);
2251 if (rc < 0)
2252 return rc;
2253
2254 /* dequeue next item in file list */
2255 fle = fl_dequeue(&bs11_sw->file_list);
2256 if (!fle)
2257 return -EINVAL;
2258
2259 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002260 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002261 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002262 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002263 return rc;
2264}
2265
Harald Welte5083b0b2009-02-02 19:20:52 +00002266#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002267static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002268 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2269 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2270 NM_ATT_BS11_LMT_USER_NAME,
2271
2272 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2273
2274 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2275
2276 NM_ATT_BS11_SW_LOAD_STORED };
2277
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002278static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002279 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2280 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2281 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2282 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002283#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002284
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002285static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002286 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2287 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002288 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002289
2290int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2291{
2292 struct abis_om_hdr *oh;
2293 struct msgb *msg = nm_msgb_alloc();
2294
2295 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2296 /* SiemensHW CCTRL object */
2297 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2298 0x03, 0x00, 0x00);
2299 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2300
2301 return abis_nm_sendmsg(bts, msg);
2302}
Harald Welte268bb402009-02-01 19:11:56 +00002303
2304int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2305{
2306 struct abis_om_hdr *oh;
2307 struct msgb *msg = nm_msgb_alloc();
2308 struct bs11_date_time aet;
2309
2310 get_bs11_date_time(&aet);
2311 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2312 /* SiemensHW CCTRL object */
2313 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2314 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002315 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002316
2317 return abis_nm_sendmsg(bts, msg);
2318}
Harald Welte5c1e4582009-02-15 11:57:29 +00002319
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002320int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002321{
2322 struct abis_om_hdr *oh;
2323 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002324 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002325
2326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2327 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2328 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2329 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2330
2331 return abis_nm_sendmsg(bts, msg);
2332}
2333
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002334int 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 +02002335{
2336 struct abis_om_hdr *oh;
2337 struct msgb *msg = nm_msgb_alloc();
2338 struct bs11_date_time aet;
2339
2340 get_bs11_date_time(&aet);
2341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2342 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2343 bport, 0xff, 0x02);
2344 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2345
2346 return abis_nm_sendmsg(bts, msg);
2347}
2348
Harald Welte5c1e4582009-02-15 11:57:29 +00002349/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002350static const char ipaccess_magic[] = "com.ipaccess";
2351
Harald Welte677c21f2009-02-17 13:22:23 +00002352
2353static int abis_nm_rx_ipacc(struct msgb *msg)
2354{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002355 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002356 struct abis_om_hdr *oh = msgb_l2(msg);
2357 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002358 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002359 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002360 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002361 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002362
2363 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002364 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002365 return -EINVAL;
2366 }
2367
Harald Welte193fefc2009-04-30 15:16:27 +00002368 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002369 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002370
Harald Welte15c61722011-05-22 22:45:37 +02002371 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002372
Harald Welte746d6092009-10-19 22:11:11 +02002373 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002374
Harald Welte677c21f2009-02-17 13:22:23 +00002375 switch (foh->msg_type) {
2376 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002377 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002378 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2379 memcpy(&addr,
2380 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2381
2382 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2383 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002384 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002385 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002386 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002387 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002388 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2389 DEBUGPC(DNM, "STREAM=0x%02x ",
2390 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002391 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002392 break;
2393 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002394 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002395 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002396 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002397 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002398 else
2399 DEBUGPC(DNM, "\n");
2400 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002401 case NM_MT_IPACC_SET_NVATTR_ACK:
2402 DEBUGPC(DNM, "SET NVATTR ACK\n");
2403 /* FIXME: decode and show the actual attributes */
2404 break;
2405 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002406 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002407 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002408 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002409 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002410 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002411 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002412 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002413 case NM_MT_IPACC_GET_NVATTR_ACK:
2414 DEBUGPC(DNM, "GET NVATTR ACK\n");
2415 /* FIXME: decode and show the actual attributes */
2416 break;
2417 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002418 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002419 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002420 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002421 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002422 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002423 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002424 break;
Harald Welte15c44172009-10-08 20:15:24 +02002425 case NM_MT_IPACC_SET_ATTR_ACK:
2426 DEBUGPC(DNM, "SET ATTR ACK\n");
2427 break;
2428 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002429 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002430 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002431 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002432 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002433 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002434 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002435 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002436 default:
2437 DEBUGPC(DNM, "unknown\n");
2438 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002439 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002440
2441 /* signal handling */
2442 switch (foh->msg_type) {
2443 case NM_MT_IPACC_RSL_CONNECT_NACK:
2444 case NM_MT_IPACC_SET_NVATTR_NACK:
2445 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002446 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 +01002447 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002448 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002449 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002450 case NM_MT_IPACC_SET_NVATTR_ACK:
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_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002454 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002455 default:
2456 break;
2457 }
2458
Harald Welte677c21f2009-02-17 13:22:23 +00002459 return 0;
2460}
2461
Harald Welte193fefc2009-04-30 15:16:27 +00002462/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002463int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2464 uint8_t obj_class, uint8_t bts_nr,
2465 uint8_t trx_nr, uint8_t ts_nr,
2466 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002467{
2468 struct msgb *msg = nm_msgb_alloc();
2469 struct abis_om_hdr *oh;
2470 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002471 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002472
2473 /* construct the 12.21 OM header, observe the erroneous length */
2474 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2475 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2476 oh->mdisc = ABIS_OM_MDISC_MANUF;
2477
2478 /* add the ip.access magic */
2479 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2480 *data++ = sizeof(ipaccess_magic);
2481 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2482
2483 /* fill the 12.21 FOM header */
2484 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2485 foh->msg_type = msg_type;
2486 foh->obj_class = obj_class;
2487 foh->obj_inst.bts_nr = bts_nr;
2488 foh->obj_inst.trx_nr = trx_nr;
2489 foh->obj_inst.ts_nr = ts_nr;
2490
2491 if (attr && attr_len) {
2492 data = msgb_put(msg, attr_len);
2493 memcpy(data, attr, attr_len);
2494 }
2495
2496 return abis_nm_sendmsg(bts, msg);
2497}
Harald Welte677c21f2009-02-17 13:22:23 +00002498
Harald Welte193fefc2009-04-30 15:16:27 +00002499/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002500int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002501 int attr_len)
2502{
Harald Welte2ef156d2010-01-07 20:39:42 +01002503 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2504 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002505 attr_len);
2506}
2507
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002508int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002509 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002510{
2511 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002512 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002513 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2514 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2515
2516 int attr_len = sizeof(attr);
2517
2518 ia.s_addr = htonl(ip);
2519 attr[1] = stream;
2520 attr[3] = port >> 8;
2521 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002522 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002523
2524 /* if ip == 0, we use the default IP */
2525 if (ip == 0)
2526 attr_len -= 5;
2527
2528 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002529 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002530
2531 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2532 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2533 trx->nr, 0xff, attr, attr_len);
2534}
2535
Harald Welte193fefc2009-04-30 15:16:27 +00002536/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002537int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002538{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002539 struct abis_om_hdr *oh;
2540 struct msgb *msg = nm_msgb_alloc();
2541
2542 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2543 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2544 trx->bts->nr, trx->nr, 0xff);
2545
2546 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002547}
Harald Weltedaef5212009-10-24 10:20:41 +02002548
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002549int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2550 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2551 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002552{
2553 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2554 obj_class, bts_nr, trx_nr, ts_nr,
2555 attr, attr_len);
2556}
Harald Welte0f255852009-11-12 14:48:42 +01002557
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002558void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002559{
2560 /* we simply reuse the GSM48 function and overwrite the RAC
2561 * with the Cell ID */
2562 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002563 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002564}
2565
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002566void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2567{
2568 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2569
Harald Welted64c0bc2011-05-30 12:07:53 +02002570 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002571 if (!trx->bts || !trx->bts->oml_link)
2572 return;
2573
2574 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2575 trx->bts->bts_nr, trx->nr, 0xff,
2576 new_state);
2577}
2578
Harald Welte92b1fe42010-03-25 11:45:30 +08002579static const struct value_string ipacc_testres_names[] = {
2580 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2581 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2582 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2583 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2584 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2585 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002586};
2587
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002588const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002589{
Harald Welte92b1fe42010-03-25 11:45:30 +08002590 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002591}
2592
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002593void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002594{
2595 cid->mcc = (buf[0] & 0xf) * 100;
2596 cid->mcc += (buf[0] >> 4) * 10;
2597 cid->mcc += (buf[1] & 0xf) * 1;
2598
2599 if (buf[1] >> 4 == 0xf) {
2600 cid->mnc = (buf[2] & 0xf) * 10;
2601 cid->mnc += (buf[2] >> 4) * 1;
2602 } else {
2603 cid->mnc = (buf[2] & 0xf) * 100;
2604 cid->mnc += (buf[2] >> 4) * 10;
2605 cid->mnc += (buf[1] >> 4) * 1;
2606 }
2607
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002608 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2609 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002610}
2611
Harald Welte0f255852009-11-12 14:48:42 +01002612/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002613int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002614{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002615 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002616 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002617
Harald Welteaf109b92010-07-22 18:14:36 +02002618 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002619
2620 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2621 return -EINVAL;
2622 cur++;
2623
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002624 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002625 cur += 2;
2626
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002627 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002628 cur += 2;
2629
2630 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2631 binf->freq_qual = *cur >> 2;
2632
Harald Welteaf109b92010-07-22 18:14:36 +02002633 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002634 binf->arfcn |= *cur++;
2635
2636 if (binf->info_type & IPAC_BINF_RXLEV)
2637 binf->rx_lev = *cur & 0x3f;
2638 cur++;
2639
2640 if (binf->info_type & IPAC_BINF_RXQUAL)
2641 binf->rx_qual = *cur & 0x7;
2642 cur++;
2643
2644 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002645 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002646 cur += 2;
2647
2648 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002649 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002650 cur += 2;
2651
2652 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002653 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002654 cur += 4;
2655
Harald Weltea780a3d2010-07-30 22:34:42 +02002656#if 0
2657 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002658 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002659#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002660 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002661 cur++;
2662
Harald Welteb40a38f2009-11-13 11:56:05 +01002663 ipac_parse_cgi(&binf->cgi, cur);
2664 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002665
2666 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2667 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2668 cur += sizeof(binf->ba_list_si2);
2669 }
2670
2671 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2672 memcpy(binf->ba_list_si2bis, cur,
2673 sizeof(binf->ba_list_si2bis));
2674 cur += sizeof(binf->ba_list_si2bis);
2675 }
2676
2677 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2678 memcpy(binf->ba_list_si2ter, cur,
2679 sizeof(binf->ba_list_si2ter));
2680 cur += sizeof(binf->ba_list_si2ter);
2681 }
2682
2683 return 0;
2684}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002685
2686void abis_nm_clear_queue(struct gsm_bts *bts)
2687{
2688 struct msgb *msg;
2689
2690 while (!llist_empty(&bts->abis_queue)) {
2691 msg = msgb_dequeue(&bts->abis_queue);
2692 msgb_free(msg);
2693 }
2694
2695 bts->abis_nm_pend = 0;
2696}