blob: a01826bd563fa100e072f0c4e46f45e3f49ce2c5 [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));
425
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200426 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200427 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
428 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
429 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
430 DEBUGP(DNM, "SW config not found! Can't continue.\n");
431 return -EINVAL;
432 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200433 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200434 }
435
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100436 /* Use the first SW_DESCR present in SW config */
437 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
438 if (sw_descr_len < 0)
439 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200440
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200441 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000442 foh->obj_inst.bts_nr,
443 foh->obj_inst.trx_nr,
444 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100445 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000446}
447
Harald Weltee0590df2009-02-15 03:34:15 +0000448/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
449static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
450{
451 struct abis_om_hdr *oh = msgb_l2(mb);
452 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200453 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000454 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200455 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000456
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200457 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000458 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
459 return -EINVAL;
460
461 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
462
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200463 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000464}
465
Harald Welteee670472009-02-22 21:58:49 +0000466static int abis_nm_rx_lmt_event(struct msgb *mb)
467{
468 struct abis_om_hdr *oh = msgb_l2(mb);
469 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200470 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000471 struct tlv_parsed tp;
472
473 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200474 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000475 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
476 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200477 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000478 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
479 }
480 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
481 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200482 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000483 DEBUGPC(DNM, "Level=%u ", level);
484 }
485 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
486 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
487 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
488 DEBUGPC(DNM, "Username=%s ", name);
489 }
490 DEBUGPC(DNM, "\n");
491 /* FIXME: parse LMT LOGON TIME */
492 return 0;
493}
494
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200495void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100496{
497 int wait = 0;
498 struct msgb *msg;
499 /* the queue is empty */
500 while (!llist_empty(&bts->abis_queue)) {
501 msg = msgb_dequeue(&bts->abis_queue);
502 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200503 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100504
505 if (wait)
506 break;
507 }
508
509 bts->abis_nm_pend = wait;
510}
511
Harald Welte52b1f982008-12-23 20:25:15 +0000512/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000513static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000514{
Harald Welte6c96ba52009-05-01 13:03:40 +0000515 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000516 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200517 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200518 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100519 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000520
521 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000522 if (is_report(mt))
523 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000524
Harald Welte15c61722011-05-22 22:45:37 +0200525 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000526 return abis_nm_rcvmsg_sw(mb);
527
Harald Welte15c61722011-05-22 22:45:37 +0200528 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800529 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000530 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200531
Harald Welte15c61722011-05-22 22:45:37 +0200532 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200533
Harald Welte15c61722011-05-22 22:45:37 +0200534 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000535
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200536 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000537 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200538 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200539 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000540 else
541 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200542
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800543 nack_data.msg = mb;
544 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200545 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200546 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200547 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000548 }
Harald Weltead384642008-12-26 10:20:07 +0000549#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000550 /* check if last message is to be acked */
551 if (is_ack_nack(nmh->last_msgtype)) {
552 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100553 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000554 /* we got our ACK, continue sending the next msg */
555 } else if (mt == MT_NACK(nmh->last_msgtype)) {
556 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100557 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000558 /* FIXME: somehow signal this to the caller */
559 } else {
560 /* really strange things happen */
561 return -EINVAL;
562 }
563 }
Harald Weltead384642008-12-26 10:20:07 +0000564#endif
565
Harald Welte97ed1e72009-02-06 13:38:02 +0000566 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000567 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100568 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000569 break;
Harald Welte34a99682009-02-13 02:41:40 +0000570 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100571 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000572 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000573 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100574 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000575 break;
Harald Welte1989c082009-08-06 17:58:31 +0200576 case NM_MT_CONN_MDROP_LINK_ACK:
577 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
578 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100579 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200580 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100581 break;
582 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200583 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100584 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100585 case NM_MT_SET_BTS_ATTR_ACK:
586 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200587 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
588 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Weltefd355a32011-03-04 13:41:31 +0100589 }
590 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000591 }
592
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200593 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100594 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000595}
596
Harald Welte677c21f2009-02-17 13:22:23 +0000597static int abis_nm_rx_ipacc(struct msgb *mb);
598
599static int abis_nm_rcvmsg_manuf(struct msgb *mb)
600{
601 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200602 struct e1inp_sign_link *sign_link = mb->dst;
603 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000604
605 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100606 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000607 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200608 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000609 break;
610 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100611 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
612 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000613 rc = 0;
614 break;
615 }
616
617 return rc;
618}
619
Harald Welte52b1f982008-12-23 20:25:15 +0000620/* High-Level API */
621/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000622int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000623{
Harald Welte52b1f982008-12-23 20:25:15 +0000624 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000625 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000626
627 /* Various consistency checks */
628 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100629 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000630 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200631 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
632 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000633 }
634 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100635 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000636 oh->sequence);
637 return -EINVAL;
638 }
Harald Welte702d8702008-12-26 20:25:35 +0000639#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200640 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000641 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000642 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100643 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000644 oh->length + sizeof(*oh), l2_len);
645 return -EINVAL;
646 }
Harald Welte702d8702008-12-26 20:25:35 +0000647 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100648 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 +0000649#endif
Harald Weltead384642008-12-26 10:20:07 +0000650 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000651
652 switch (oh->mdisc) {
653 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000654 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000655 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000656 case ABIS_OM_MDISC_MANUF:
657 rc = abis_nm_rcvmsg_manuf(msg);
658 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000659 case ABIS_OM_MDISC_MMI:
660 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100661 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000662 oh->mdisc);
663 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000664 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100665 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000666 oh->mdisc);
667 return -EINVAL;
668 }
669
Harald Weltead384642008-12-26 10:20:07 +0000670 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000671 return rc;
672}
673
674#if 0
675/* initialized all resources */
676struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
677{
678 struct abis_nm_h *nmh;
679
680 nmh = malloc(sizeof(*nmh));
681 if (!nmh)
682 return NULL;
683
684 nmh->cfg = cfg;
685
686 return nmh;
687}
688
689/* free all resources */
690void abis_nm_fini(struct abis_nm_h *nmh)
691{
692 free(nmh);
693}
694#endif
695
696/* Here we are trying to define a high-level API that can be used by
697 * the actual BSC implementation. However, the architecture is currently
698 * still under design. Ideally the calls to this API would be synchronous,
699 * while the underlying stack behind the APi runs in a traditional select
700 * based state machine.
701 */
702
Harald Welte4724f992009-01-18 18:01:49 +0000703/* 6.2 Software Load: */
704enum sw_state {
705 SW_STATE_NONE,
706 SW_STATE_WAIT_INITACK,
707 SW_STATE_WAIT_SEGACK,
708 SW_STATE_WAIT_ENDACK,
709 SW_STATE_WAIT_ACTACK,
710 SW_STATE_ERROR,
711};
Harald Welte52b1f982008-12-23 20:25:15 +0000712
Harald Welte52b1f982008-12-23 20:25:15 +0000713struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000714 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800715 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000716 gsm_cbfn *cbfn;
717 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000718 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000719
Harald Welte52b1f982008-12-23 20:25:15 +0000720 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200721 uint8_t obj_class;
722 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000723
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200724 uint8_t file_id[255];
725 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000726
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200727 uint8_t file_version[255];
728 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000729
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200730 uint8_t window_size;
731 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000732
733 int fd;
734 FILE *stream;
735 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000736 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000737};
738
Harald Welte4724f992009-01-18 18:01:49 +0000739static struct abis_nm_sw g_sw;
740
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100741static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
742{
743 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
744 msgb_v_put(msg, NM_ATT_SW_DESCR);
745 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
746 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
747 sw->file_version);
748 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
749 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
750 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
751 sw->file_version);
752 } else {
753 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
754 }
755}
756
Harald Welte4724f992009-01-18 18:01:49 +0000757/* 6.2.1 / 8.3.1: Load Data Initiate */
758static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000759{
Harald Welte4724f992009-01-18 18:01:49 +0000760 struct abis_om_hdr *oh;
761 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200762 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000763
764 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
765 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
766 sw->obj_instance[0], sw->obj_instance[1],
767 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100768
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100769 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000770 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
771
772 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000773}
774
Harald Welte1602ade2009-01-29 21:12:39 +0000775static int is_last_line(FILE *stream)
776{
777 char next_seg_buf[256];
778 long pos;
779
780 /* check if we're sending the last line */
781 pos = ftell(stream);
782 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
783 fseek(stream, pos, SEEK_SET);
784 return 1;
785 }
786
787 fseek(stream, pos, SEEK_SET);
788 return 0;
789}
790
Harald Welte4724f992009-01-18 18:01:49 +0000791/* 6.2.2 / 8.3.2 Load Data Segment */
792static int sw_load_segment(struct abis_nm_sw *sw)
793{
794 struct abis_om_hdr *oh;
795 struct msgb *msg = nm_msgb_alloc();
796 char seg_buf[256];
797 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000798 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200799 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000800
801 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000802
803 switch (sw->bts->type) {
804 case GSM_BTS_TYPE_BS11:
805 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
806 perror("fgets reading segment");
807 return -EINVAL;
808 }
809 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000810
811 /* check if we're sending the last line */
812 sw->last_seg = is_last_line(sw->stream);
813 if (sw->last_seg)
814 seg_buf[1] = 0;
815 else
816 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000817
818 len = strlen(line_buf) + 2;
819 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200820 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000821 /* BS11 wants CR + LF in excess of the TLV length !?! */
822 tlv[1] -= 2;
823
824 /* we only now know the exact length for the OM hdr */
825 len = strlen(line_buf)+2;
826 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100827 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200828 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100829 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
830 if (len < 0) {
831 perror("read failed");
832 return -EINVAL;
833 }
834
835 if (len != IPACC_SEGMENT_SIZE)
836 sw->last_seg = 1;
837
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100838 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200839 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100840 len += 3;
841 break;
842 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000843 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100844 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000845 /* FIXME: Other BTS types */
846 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000847 }
Harald Welte4724f992009-01-18 18:01:49 +0000848
Harald Welte4724f992009-01-18 18:01:49 +0000849 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
850 sw->obj_instance[0], sw->obj_instance[1],
851 sw->obj_instance[2]);
852
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100853 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000854}
855
856/* 6.2.4 / 8.3.4 Load Data End */
857static int sw_load_end(struct abis_nm_sw *sw)
858{
859 struct abis_om_hdr *oh;
860 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200861 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000862
863 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
864 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
865 sw->obj_instance[0], sw->obj_instance[1],
866 sw->obj_instance[2]);
867
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100868 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000869 return abis_nm_sendmsg(sw->bts, msg);
870}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000871
Harald Welte52b1f982008-12-23 20:25:15 +0000872/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000873static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000874{
Harald Welte4724f992009-01-18 18:01:49 +0000875 struct abis_om_hdr *oh;
876 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200877 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000878
Harald Welte4724f992009-01-18 18:01:49 +0000879 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
880 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
881 sw->obj_instance[0], sw->obj_instance[1],
882 sw->obj_instance[2]);
883
884 /* FIXME: this is BS11 specific format */
885 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
886 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
887 sw->file_version);
888
889 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000890}
Harald Welte4724f992009-01-18 18:01:49 +0000891
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100892struct sdp_firmware {
893 char magic[4];
894 char more_magic[4];
895 unsigned int header_length;
896 unsigned int file_length;
897} __attribute__ ((packed));
898
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100899static int parse_sdp_header(struct abis_nm_sw *sw)
900{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100901 struct sdp_firmware firmware_header;
902 int rc;
903 struct stat stat;
904
905 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
906 if (rc != sizeof(firmware_header)) {
907 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
908 return -1;
909 }
910
911 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
912 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
913 return -1;
914 }
915
916 if (firmware_header.more_magic[0] != 0x10 ||
917 firmware_header.more_magic[1] != 0x02 ||
918 firmware_header.more_magic[2] != 0x00 ||
919 firmware_header.more_magic[3] != 0x00) {
920 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
921 return -1;
922 }
923
924
925 if (fstat(sw->fd, &stat) == -1) {
926 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
927 return -1;
928 }
929
930 if (ntohl(firmware_header.file_length) != stat.st_size) {
931 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
932 return -1;
933 }
934
935 /* go back to the start as we checked the whole filesize.. */
936 lseek(sw->fd, 0l, SEEK_SET);
937 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
938 "There might be checksums in the file that are not\n"
939 "verified and incomplete firmware might be flashed.\n"
940 "There is absolutely no WARRANTY that flashing will\n"
941 "work.\n");
942 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100943}
944
Harald Welte4724f992009-01-18 18:01:49 +0000945static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
946{
947 char file_id[12+1];
948 char file_version[80+1];
949 int rc;
950
951 sw->fd = open(fname, O_RDONLY);
952 if (sw->fd < 0)
953 return sw->fd;
954
955 switch (sw->bts->type) {
956 case GSM_BTS_TYPE_BS11:
957 sw->stream = fdopen(sw->fd, "r");
958 if (!sw->stream) {
959 perror("fdopen");
960 return -1;
961 }
962 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200963 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +0000964 file_id, file_version);
965 if (rc != 2) {
966 perror("parsing header line of software file");
967 return -1;
968 }
969 strcpy((char *)sw->file_id, file_id);
970 sw->file_id_len = strlen(file_id);
971 strcpy((char *)sw->file_version, file_version);
972 sw->file_version_len = strlen(file_version);
973 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +0000974 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +0000975 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100976 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100977 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100978 rc = parse_sdp_header(sw);
979 if (rc < 0) {
980 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
981 return -1;
982 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100983
984 strcpy((char *)sw->file_id, "id");
985 sw->file_id_len = 3;
986 strcpy((char *)sw->file_version, "version");
987 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100988 break;
Harald Welte4724f992009-01-18 18:01:49 +0000989 default:
990 /* We don't know how to treat them yet */
991 close(sw->fd);
992 return -EINVAL;
993 }
994
995 return 0;
996}
997
998static void sw_close_file(struct abis_nm_sw *sw)
999{
1000 switch (sw->bts->type) {
1001 case GSM_BTS_TYPE_BS11:
1002 fclose(sw->stream);
1003 break;
1004 default:
1005 close(sw->fd);
1006 break;
1007 }
1008}
1009
1010/* Fill the window */
1011static int sw_fill_window(struct abis_nm_sw *sw)
1012{
1013 int rc;
1014
1015 while (sw->seg_in_window < sw->window_size) {
1016 rc = sw_load_segment(sw);
1017 if (rc < 0)
1018 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001019 if (sw->last_seg)
1020 break;
Harald Welte4724f992009-01-18 18:01:49 +00001021 }
1022 return 0;
1023}
1024
1025/* callback function from abis_nm_rcvmsg() handler */
1026static int abis_nm_rcvmsg_sw(struct msgb *mb)
1027{
1028 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001029 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001030 int rc = -1;
1031 struct abis_nm_sw *sw = &g_sw;
1032 enum sw_state old_state = sw->state;
1033
Harald Welte3ffd1372009-02-01 22:15:49 +00001034 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001035
1036 switch (sw->state) {
1037 case SW_STATE_WAIT_INITACK:
1038 switch (foh->msg_type) {
1039 case NM_MT_LOAD_INIT_ACK:
1040 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001041 if (sw->cbfn)
1042 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1043 NM_MT_LOAD_INIT_ACK, mb,
1044 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001045 rc = sw_fill_window(sw);
1046 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001047 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001048 break;
1049 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001050 if (sw->forced) {
1051 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1052 "Init NACK\n");
1053 if (sw->cbfn)
1054 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1055 NM_MT_LOAD_INIT_ACK, mb,
1056 sw->cb_data, NULL);
1057 rc = sw_fill_window(sw);
1058 sw->state = SW_STATE_WAIT_SEGACK;
1059 } else {
1060 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001061 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001062 if (sw->cbfn)
1063 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1064 NM_MT_LOAD_INIT_NACK, mb,
1065 sw->cb_data, NULL);
1066 sw->state = SW_STATE_ERROR;
1067 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001068 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001069 break;
1070 }
1071 break;
1072 case SW_STATE_WAIT_SEGACK:
1073 switch (foh->msg_type) {
1074 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001075 if (sw->cbfn)
1076 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1077 NM_MT_LOAD_SEG_ACK, mb,
1078 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001079 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001080 if (!sw->last_seg) {
1081 /* fill window with more segments */
1082 rc = sw_fill_window(sw);
1083 sw->state = SW_STATE_WAIT_SEGACK;
1084 } else {
1085 /* end the transfer */
1086 sw->state = SW_STATE_WAIT_ENDACK;
1087 rc = sw_load_end(sw);
1088 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001089 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001090 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001091 case NM_MT_LOAD_ABORT:
1092 if (sw->cbfn)
1093 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1094 NM_MT_LOAD_ABORT, mb,
1095 sw->cb_data, NULL);
1096 break;
Harald Welte4724f992009-01-18 18:01:49 +00001097 }
1098 break;
1099 case SW_STATE_WAIT_ENDACK:
1100 switch (foh->msg_type) {
1101 case NM_MT_LOAD_END_ACK:
1102 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001103 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1104 sw->bts->nr);
1105 sw->state = SW_STATE_NONE;
1106 if (sw->cbfn)
1107 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1108 NM_MT_LOAD_END_ACK, mb,
1109 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001110 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001111 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001112 break;
1113 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001114 if (sw->forced) {
1115 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1116 "End NACK\n");
1117 sw->state = SW_STATE_NONE;
1118 if (sw->cbfn)
1119 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1120 NM_MT_LOAD_END_ACK, mb,
1121 sw->cb_data, NULL);
1122 } else {
1123 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001124 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001125 sw->state = SW_STATE_ERROR;
1126 if (sw->cbfn)
1127 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1128 NM_MT_LOAD_END_NACK, mb,
1129 sw->cb_data, NULL);
1130 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001131 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001132 break;
1133 }
1134 case SW_STATE_WAIT_ACTACK:
1135 switch (foh->msg_type) {
1136 case NM_MT_ACTIVATE_SW_ACK:
1137 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001138 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001139 sw->state = SW_STATE_NONE;
1140 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001141 if (sw->cbfn)
1142 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1143 NM_MT_ACTIVATE_SW_ACK, mb,
1144 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001145 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001146 break;
1147 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001148 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001149 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001150 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001151 if (sw->cbfn)
1152 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1153 NM_MT_ACTIVATE_SW_NACK, mb,
1154 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001155 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001156 break;
1157 }
1158 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001159 switch (foh->msg_type) {
1160 case NM_MT_ACTIVATE_SW_ACK:
1161 rc = 0;
1162 break;
1163 }
1164 break;
Harald Welte4724f992009-01-18 18:01:49 +00001165 case SW_STATE_ERROR:
1166 break;
1167 }
1168
1169 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001170 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001171 foh->msg_type, old_state, sw->state);
1172
1173 return rc;
1174}
1175
1176/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001177int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001178 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001179 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001180{
1181 struct abis_nm_sw *sw = &g_sw;
1182 int rc;
1183
Harald Welte5e4d1b32009-02-01 13:36:56 +00001184 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1185 bts->nr, fname);
1186
Harald Welte4724f992009-01-18 18:01:49 +00001187 if (sw->state != SW_STATE_NONE)
1188 return -EBUSY;
1189
1190 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001191 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001192
1193 switch (bts->type) {
1194 case GSM_BTS_TYPE_BS11:
1195 sw->obj_class = NM_OC_SITE_MANAGER;
1196 sw->obj_instance[0] = 0xff;
1197 sw->obj_instance[1] = 0xff;
1198 sw->obj_instance[2] = 0xff;
1199 break;
1200 case GSM_BTS_TYPE_NANOBTS:
1201 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001202 sw->obj_instance[0] = sw->bts->nr;
1203 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001204 sw->obj_instance[2] = 0xff;
1205 break;
1206 case GSM_BTS_TYPE_UNKNOWN:
1207 default:
1208 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1209 return -1;
1210 break;
1211 }
Harald Welte4724f992009-01-18 18:01:49 +00001212 sw->window_size = win_size;
1213 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001214 sw->cbfn = cbfn;
1215 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001216 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001217
1218 rc = sw_open_file(sw, fname);
1219 if (rc < 0) {
1220 sw->state = SW_STATE_NONE;
1221 return rc;
1222 }
1223
1224 return sw_load_init(sw);
1225}
Harald Welte52b1f982008-12-23 20:25:15 +00001226
Harald Welte1602ade2009-01-29 21:12:39 +00001227int abis_nm_software_load_status(struct gsm_bts *bts)
1228{
1229 struct abis_nm_sw *sw = &g_sw;
1230 struct stat st;
1231 int rc, percent;
1232
1233 rc = fstat(sw->fd, &st);
1234 if (rc < 0) {
1235 perror("ERROR during stat");
1236 return rc;
1237 }
1238
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001239 if (sw->stream)
1240 percent = (ftell(sw->stream) * 100) / st.st_size;
1241 else
1242 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001243 return percent;
1244}
1245
Harald Welte5e4d1b32009-02-01 13:36:56 +00001246/* Activate the specified software into the BTS */
1247int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1248 gsm_cbfn *cbfn, void *cb_data)
1249{
1250 struct abis_nm_sw *sw = &g_sw;
1251 int rc;
1252
1253 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1254 bts->nr, fname);
1255
1256 if (sw->state != SW_STATE_NONE)
1257 return -EBUSY;
1258
1259 sw->bts = bts;
1260 sw->obj_class = NM_OC_SITE_MANAGER;
1261 sw->obj_instance[0] = 0xff;
1262 sw->obj_instance[1] = 0xff;
1263 sw->obj_instance[2] = 0xff;
1264 sw->state = SW_STATE_WAIT_ACTACK;
1265 sw->cbfn = cbfn;
1266 sw->cb_data = cb_data;
1267
1268 /* Open the file in order to fill some sw struct members */
1269 rc = sw_open_file(sw, fname);
1270 if (rc < 0) {
1271 sw->state = SW_STATE_NONE;
1272 return rc;
1273 }
1274 sw_close_file(sw);
1275
1276 return sw_activate(sw);
1277}
1278
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001279static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1280 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001281{
Harald Welteadaf08b2009-01-18 11:08:10 +00001282 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001283 ch->bts_port = bts_port;
1284 ch->timeslot = ts_nr;
1285 ch->subslot = subslot_nr;
1286}
1287
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001288int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1289 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1290 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001291{
1292 struct abis_om_hdr *oh;
1293 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001294 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001295 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001296
1297 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1298 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1299 bts->bts_nr, trx_nr, 0xff);
1300
Harald Welte8470bf22008-12-25 23:28:35 +00001301 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001302
1303 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1304 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1305
1306 return abis_nm_sendmsg(bts, msg);
1307}
1308
1309/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1310int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001311 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001312{
Harald Welte8470bf22008-12-25 23:28:35 +00001313 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001314 struct abis_om_hdr *oh;
1315 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001316 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001317
1318 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001319 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001320 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1321
1322 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1323 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1324
1325 return abis_nm_sendmsg(bts, msg);
1326}
1327
1328#if 0
1329int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1330 struct abis_nm_abis_channel *chan)
1331{
1332}
1333#endif
1334
1335int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001336 uint8_t e1_port, uint8_t e1_timeslot,
1337 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001338{
1339 struct gsm_bts *bts = ts->trx->bts;
1340 struct abis_om_hdr *oh;
1341 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001342 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001343
1344 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1345 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001346 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001347
1348 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1349 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1350
Harald Weltef325eb42009-02-19 17:07:39 +00001351 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1352 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001353 e1_port, e1_timeslot, e1_subslot);
1354
Harald Welte52b1f982008-12-23 20:25:15 +00001355 return abis_nm_sendmsg(bts, msg);
1356}
1357
1358#if 0
1359int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1360 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001361 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001362{
1363}
1364#endif
1365
Harald Welte22af0db2009-02-14 15:41:08 +00001366/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001367int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001368{
1369 struct abis_om_hdr *oh;
1370 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001371 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001372
1373 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1374
1375 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001376 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 +00001377 cur = msgb_put(msg, attr_len);
1378 memcpy(cur, attr, attr_len);
1379
1380 return abis_nm_sendmsg(bts, msg);
1381}
1382
1383/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001384int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001385{
1386 struct abis_om_hdr *oh;
1387 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001388 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001389
1390 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1391
1392 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1393 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001394 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001395 cur = msgb_put(msg, attr_len);
1396 memcpy(cur, attr, attr_len);
1397
1398 return abis_nm_sendmsg(trx->bts, msg);
1399}
1400
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001401static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001402{
1403 int i;
1404
1405 /* As it turns out, the BS-11 has some very peculiar restrictions
1406 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301407 switch (ts->trx->bts->type) {
1408 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001409 switch (chan_comb) {
1410 case NM_CHANC_TCHHalf:
1411 case NM_CHANC_TCHHalf2:
1412 /* not supported */
1413 return -EINVAL;
1414 case NM_CHANC_SDCCH:
1415 /* only one SDCCH/8 per TRX */
1416 for (i = 0; i < TRX_NR_TS; i++) {
1417 if (i == ts->nr)
1418 continue;
1419 if (ts->trx->ts[i].nm_chan_comb ==
1420 NM_CHANC_SDCCH)
1421 return -EINVAL;
1422 }
1423 /* not allowed for TS0 of BCCH-TRX */
1424 if (ts->trx == ts->trx->bts->c0 &&
1425 ts->nr == 0)
1426 return -EINVAL;
1427 /* not on the same TRX that has a BCCH+SDCCH4
1428 * combination */
1429 if (ts->trx == ts->trx->bts->c0 &&
1430 (ts->trx->ts[0].nm_chan_comb == 5 ||
1431 ts->trx->ts[0].nm_chan_comb == 8))
1432 return -EINVAL;
1433 break;
1434 case NM_CHANC_mainBCCH:
1435 case NM_CHANC_BCCHComb:
1436 /* allowed only for TS0 of C0 */
1437 if (ts->trx != ts->trx->bts->c0 ||
1438 ts->nr != 0)
1439 return -EINVAL;
1440 break;
1441 case NM_CHANC_BCCH:
1442 /* allowed only for TS 2/4/6 of C0 */
1443 if (ts->trx != ts->trx->bts->c0)
1444 return -EINVAL;
1445 if (ts->nr != 2 && ts->nr != 4 &&
1446 ts->nr != 6)
1447 return -EINVAL;
1448 break;
1449 case 8: /* this is not like 08.58, but in fact
1450 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1451 /* FIXME: only one CBCH allowed per cell */
1452 break;
1453 }
Harald Welted6575f92009-12-02 02:45:23 +05301454 break;
1455 case GSM_BTS_TYPE_NANOBTS:
1456 switch (ts->nr) {
1457 case 0:
1458 if (ts->trx->nr == 0) {
1459 /* only on TRX0 */
1460 switch (chan_comb) {
1461 case NM_CHANC_BCCH:
1462 case NM_CHANC_mainBCCH:
1463 case NM_CHANC_BCCHComb:
1464 return 0;
1465 break;
1466 default:
1467 return -EINVAL;
1468 }
1469 } else {
1470 switch (chan_comb) {
1471 case NM_CHANC_TCHFull:
1472 case NM_CHANC_TCHHalf:
1473 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1474 return 0;
1475 default:
1476 return -EINVAL;
1477 }
1478 }
1479 break;
1480 case 1:
1481 if (ts->trx->nr == 0) {
1482 switch (chan_comb) {
1483 case NM_CHANC_SDCCH_CBCH:
1484 if (ts->trx->ts[0].nm_chan_comb ==
1485 NM_CHANC_mainBCCH)
1486 return 0;
1487 return -EINVAL;
1488 case NM_CHANC_SDCCH:
1489 case NM_CHANC_TCHFull:
1490 case NM_CHANC_TCHHalf:
1491 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1492 case NM_CHANC_IPAC_TCHFull_PDCH:
1493 return 0;
1494 }
1495 } else {
1496 switch (chan_comb) {
1497 case NM_CHANC_SDCCH:
1498 case NM_CHANC_TCHFull:
1499 case NM_CHANC_TCHHalf:
1500 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1501 return 0;
1502 default:
1503 return -EINVAL;
1504 }
1505 }
1506 break;
1507 case 2:
1508 case 3:
1509 case 4:
1510 case 5:
1511 case 6:
1512 case 7:
1513 switch (chan_comb) {
1514 case NM_CHANC_TCHFull:
1515 case NM_CHANC_TCHHalf:
1516 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1517 return 0;
1518 case NM_CHANC_IPAC_PDCH:
1519 case NM_CHANC_IPAC_TCHFull_PDCH:
1520 if (ts->trx->nr == 0)
1521 return 0;
1522 else
1523 return -EINVAL;
1524 }
1525 break;
1526 }
1527 return -EINVAL;
1528 default:
1529 /* unknown BTS type */
1530 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001531 }
1532 return 0;
1533}
1534
Harald Welte22af0db2009-02-14 15:41:08 +00001535/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001536int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001537{
1538 struct gsm_bts *bts = ts->trx->bts;
1539 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001540 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001541 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001542 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00001543
1544 if (bts->type == GSM_BTS_TYPE_BS11)
1545 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001546
Harald Weltef325eb42009-02-19 17:07:39 +00001547 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001548 if (verify_chan_comb(ts, chan_comb) < 0) {
1549 msgb_free(msg);
1550 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1551 return -EINVAL;
1552 }
1553 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001554
Harald Welte52b1f982008-12-23 20:25:15 +00001555 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001556 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001557 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001558 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001559 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001560 if (ts->hopping.enabled) {
1561 unsigned int i;
1562 uint8_t *len;
1563
Harald Welte6e0cd042009-09-12 13:05:33 +02001564 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1565 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001566
1567 /* build the ARFCN list */
1568 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1569 len = msgb_put(msg, 1);
1570 *len = 0;
1571 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1572 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1573 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001574 /* At least BS-11 wants a TLV16 here */
1575 if (bts->type == GSM_BTS_TYPE_BS11)
1576 *len += 1;
1577 else
1578 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001579 }
1580 }
Harald Weltee0590df2009-02-15 03:34:15 +00001581 }
Harald Welte135a6482011-05-30 12:09:13 +02001582 if (ts->tsc == -1)
1583 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1584 else
1585 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001586 if (bts->type == GSM_BTS_TYPE_BS11)
1587 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001588
1589 return abis_nm_sendmsg(bts, msg);
1590}
1591
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001592int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1593 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001594{
1595 struct abis_om_hdr *oh;
1596 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001597 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1598 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001599
1600 if (nack) {
1601 len += 2;
1602 msgtype = NM_MT_SW_ACT_REQ_NACK;
1603 }
Harald Welte34a99682009-02-13 02:41:40 +00001604
1605 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001606 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1607
Harald Welte34a99682009-02-13 02:41:40 +00001608 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001609 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001610 memcpy(ptr, attr, att_len);
1611 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001612 if (nack)
1613 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001614
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001615 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001616}
1617
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001618int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001619{
Harald Welte8470bf22008-12-25 23:28:35 +00001620 struct msgb *msg = nm_msgb_alloc();
1621 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001622 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001623
1624 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1625 fill_om_hdr(oh, len);
1626 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001627 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001628
1629 return abis_nm_sendmsg(bts, msg);
1630}
1631
1632/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001633static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001634{
1635 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001636 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001637
1638 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001639 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001640 0xff, 0xff, 0xff);
1641
1642 return abis_nm_sendmsg(bts, msg);
1643}
1644
Harald Welte34a99682009-02-13 02:41:40 +00001645/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001646int 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 +00001647{
1648 struct abis_om_hdr *oh;
1649 struct msgb *msg = nm_msgb_alloc();
1650
1651 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1652 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1653
Harald Welte15c61722011-05-22 22:45:37 +02001654 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001655 DEBUGPC(DNM, "Sending OPSTART\n");
1656
Harald Welte34a99682009-02-13 02:41:40 +00001657 return abis_nm_sendmsg(bts, msg);
1658}
1659
1660/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001661int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1662 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001663{
1664 struct abis_om_hdr *oh;
1665 struct msgb *msg = nm_msgb_alloc();
1666
1667 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1668 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1669 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1670
1671 return abis_nm_sendmsg(bts, msg);
1672}
1673
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001674int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1675 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001676{
1677 struct abis_om_hdr *oh;
1678 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001679 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001680
1681 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1682 e1_port0, ts0, e1_port1, ts1);
1683
1684 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1685 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1686 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1687
1688 attr = msgb_put(msg, 3);
1689 attr[0] = NM_ATT_MDROP_LINK;
1690 attr[1] = e1_port0;
1691 attr[2] = ts0;
1692
1693 attr = msgb_put(msg, 3);
1694 attr[0] = NM_ATT_MDROP_NEXT;
1695 attr[1] = e1_port1;
1696 attr[2] = ts1;
1697
1698 return abis_nm_sendmsg(bts, msg);
1699}
Harald Welte34a99682009-02-13 02:41:40 +00001700
Harald Weltec7310382009-08-08 00:02:36 +02001701/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001702int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1703 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1704 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001705{
1706 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001707
Harald Welte15c61722011-05-22 22:45:37 +02001708 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001709
1710 if (!msg)
1711 msg = nm_msgb_alloc();
1712
1713 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1714 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1715 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1716 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001717 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001718
1719 return abis_nm_sendmsg(bts, msg);
1720}
1721
Harald Welte52b1f982008-12-23 20:25:15 +00001722int abis_nm_event_reports(struct gsm_bts *bts, int on)
1723{
1724 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001725 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001726 else
Harald Welte227d4072009-01-03 08:16:25 +00001727 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001728}
1729
Harald Welte47d88ae2009-01-04 12:02:08 +00001730/* Siemens (or BS-11) specific commands */
1731
Harald Welte3ffd1372009-02-01 22:15:49 +00001732int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1733{
1734 if (reconnect == 0)
1735 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1736 else
1737 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1738}
1739
Harald Welteb8427972009-02-05 19:27:17 +00001740int abis_nm_bs11_restart(struct gsm_bts *bts)
1741{
1742 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1743}
1744
1745
Harald Welte268bb402009-02-01 19:11:56 +00001746struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001747 uint16_t year;
1748 uint8_t month;
1749 uint8_t day;
1750 uint8_t hour;
1751 uint8_t min;
1752 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001753} __attribute__((packed));
1754
1755
1756void get_bs11_date_time(struct bs11_date_time *aet)
1757{
1758 time_t t;
1759 struct tm *tm;
1760
1761 t = time(NULL);
1762 tm = localtime(&t);
1763 aet->sec = tm->tm_sec;
1764 aet->min = tm->tm_min;
1765 aet->hour = tm->tm_hour;
1766 aet->day = tm->tm_mday;
1767 aet->month = tm->tm_mon;
1768 aet->year = htons(1900 + tm->tm_year);
1769}
1770
Harald Welte05188ee2009-01-18 11:39:08 +00001771int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001772{
Harald Welte4668fda2009-01-03 08:19:29 +00001773 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001774}
1775
Harald Welte05188ee2009-01-18 11:39:08 +00001776int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001777{
1778 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001779 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001780 else
Harald Welte4668fda2009-01-03 08:19:29 +00001781 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001782}
Harald Welte47d88ae2009-01-04 12:02:08 +00001783
Harald Welte05188ee2009-01-18 11:39:08 +00001784int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001785 enum abis_bs11_objtype type, uint8_t idx,
1786 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001787{
1788 struct abis_om_hdr *oh;
1789 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001790 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001791
1792 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001793 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001794 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001795 cur = msgb_put(msg, attr_len);
1796 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001797
1798 return abis_nm_sendmsg(bts, msg);
1799}
1800
Harald Welte78fc0d42009-02-19 02:50:57 +00001801int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001802 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001803{
1804 struct abis_om_hdr *oh;
1805 struct msgb *msg = nm_msgb_alloc();
1806
1807 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1808 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1809 NM_OC_BS11, type, 0, idx);
1810
1811 return abis_nm_sendmsg(bts, msg);
1812}
1813
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001814int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001815{
1816 struct abis_om_hdr *oh;
1817 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001818 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001819
1820 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001821 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001822 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1823 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001824
1825 return abis_nm_sendmsg(bts, msg);
1826}
1827
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001828int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001829{
1830 struct abis_om_hdr *oh;
1831 struct msgb *msg = nm_msgb_alloc();
1832
1833 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1834 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001835 idx, 0xff, 0xff);
1836
1837 return abis_nm_sendmsg(bts, msg);
1838}
1839
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001840int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001841{
1842 struct abis_om_hdr *oh;
1843 struct msgb *msg = nm_msgb_alloc();
1844
1845 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1846 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1847 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001848
1849 return abis_nm_sendmsg(bts, msg);
1850}
Harald Welte05188ee2009-01-18 11:39:08 +00001851
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001852static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001853int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1854{
1855 struct abis_om_hdr *oh;
1856 struct msgb *msg = nm_msgb_alloc();
1857
1858 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1859 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1860 0xff, 0xff, 0xff);
1861 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1862
1863 return abis_nm_sendmsg(bts, msg);
1864}
1865
Harald Welteb6c92ae2009-02-21 20:15:32 +00001866/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001867int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1868 uint8_t e1_timeslot, uint8_t e1_subslot,
1869 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001870{
1871 struct abis_om_hdr *oh;
1872 struct abis_nm_channel *ch;
1873 struct msgb *msg = nm_msgb_alloc();
1874
1875 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001876 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001877 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1878
1879 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1880 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001881 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001882
1883 return abis_nm_sendmsg(bts, msg);
1884}
1885
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001886int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001887{
1888 struct abis_om_hdr *oh;
1889 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001890
1891 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001892 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001893 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1894 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1895
1896 return abis_nm_sendmsg(trx->bts, msg);
1897}
1898
Harald Welte78fc0d42009-02-19 02:50:57 +00001899int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1900{
1901 struct abis_om_hdr *oh;
1902 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001903 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00001904
1905 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1906 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1907 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1908 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1909
1910 return abis_nm_sendmsg(trx->bts, msg);
1911}
1912
Harald Welteaaf02d92009-04-29 13:25:57 +00001913int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1914{
1915 struct abis_om_hdr *oh;
1916 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001917 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00001918
1919 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1920 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1921 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00001922 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00001923
1924 return abis_nm_sendmsg(bts, msg);
1925}
1926
Harald Welteef061952009-05-17 12:43:42 +00001927int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1928{
1929 struct abis_om_hdr *oh;
1930 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001931 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00001932 NM_ATT_BS11_CCLK_TYPE };
1933
1934 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1935 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1936 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1937 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1938
1939 return abis_nm_sendmsg(bts, msg);
1940
1941}
Harald Welteaaf02d92009-04-29 13:25:57 +00001942
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001943//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00001944
Harald Welte1bc09062009-01-18 14:17:52 +00001945int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00001946{
Daniel Willmann493db4e2010-01-07 00:43:11 +01001947 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1948}
1949
Daniel Willmann4b054c82010-01-07 00:46:26 +01001950int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1951{
1952 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1953}
1954
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001955int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001956{
Harald Welte05188ee2009-01-18 11:39:08 +00001957 struct abis_om_hdr *oh;
1958 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00001959 struct bs11_date_time bdt;
1960
1961 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00001962
1963 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00001964 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001965 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001966 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00001967 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001968 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00001969 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001970 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00001971 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01001972 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00001973 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001974 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00001975 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00001976 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001977 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00001978 }
Harald Welte05188ee2009-01-18 11:39:08 +00001979
1980 return abis_nm_sendmsg(bts, msg);
1981}
Harald Welte1bc09062009-01-18 14:17:52 +00001982
1983int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
1984{
1985 struct abis_om_hdr *oh;
1986 struct msgb *msg;
1987
1988 if (strlen(password) != 10)
1989 return -EINVAL;
1990
1991 msg = nm_msgb_alloc();
1992 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001993 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00001994 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001995 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00001996
1997 return abis_nm_sendmsg(bts, msg);
1998}
1999
Harald Weltee69f5fb2009-04-28 16:31:38 +00002000/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2001int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2002{
2003 struct abis_om_hdr *oh;
2004 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002005 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002006
2007 msg = nm_msgb_alloc();
2008 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2009 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2010 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002011
2012 if (locked)
2013 tlv_value = BS11_LI_PLL_LOCKED;
2014 else
2015 tlv_value = BS11_LI_PLL_STANDALONE;
2016
2017 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002018
2019 return abis_nm_sendmsg(bts, msg);
2020}
2021
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002022/* Set the calibration value of the PLL (work value/set value)
2023 * It depends on the login which one is changed */
2024int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2025{
2026 struct abis_om_hdr *oh;
2027 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002028 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002029
2030 msg = nm_msgb_alloc();
2031 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2032 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2033 BS11_OBJ_TRX1, 0x00, 0x00);
2034
2035 tlv_value[0] = value>>8;
2036 tlv_value[1] = value&0xff;
2037
2038 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2039
2040 return abis_nm_sendmsg(bts, msg);
2041}
2042
Harald Welte1bc09062009-01-18 14:17:52 +00002043int abis_nm_bs11_get_state(struct gsm_bts *bts)
2044{
2045 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2046}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002047
2048/* BS11 SWL */
2049
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002050void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002051
Harald Welte5e4d1b32009-02-01 13:36:56 +00002052struct abis_nm_bs11_sw {
2053 struct gsm_bts *bts;
2054 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002055 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002056 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002057 struct llist_head file_list;
2058 gsm_cbfn *user_cb; /* specified by the user */
2059};
2060static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2061
2062struct file_list_entry {
2063 struct llist_head list;
2064 char fname[PATH_MAX];
2065};
2066
2067struct file_list_entry *fl_dequeue(struct llist_head *queue)
2068{
2069 struct llist_head *lh;
2070
2071 if (llist_empty(queue))
2072 return NULL;
2073
2074 lh = queue->next;
2075 llist_del(lh);
2076
2077 return llist_entry(lh, struct file_list_entry, list);
2078}
2079
2080static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2081{
2082 char linebuf[255];
2083 struct llist_head *lh, *lh2;
2084 FILE *swl;
2085 int rc = 0;
2086
2087 swl = fopen(bs11_sw->swl_fname, "r");
2088 if (!swl)
2089 return -ENODEV;
2090
2091 /* zero the stale file list, if any */
2092 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2093 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002094 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002095 }
2096
2097 while (fgets(linebuf, sizeof(linebuf), swl)) {
2098 char file_id[12+1];
2099 char file_version[80+1];
2100 struct file_list_entry *fle;
2101 static char dir[PATH_MAX];
2102
2103 if (strlen(linebuf) < 4)
2104 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002105
Harald Welte5e4d1b32009-02-01 13:36:56 +00002106 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2107 if (rc < 0) {
2108 perror("ERR parsing SWL file");
2109 rc = -EINVAL;
2110 goto out;
2111 }
2112 if (rc < 2)
2113 continue;
2114
Harald Welte470ec292009-06-26 20:25:23 +02002115 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002116 if (!fle) {
2117 rc = -ENOMEM;
2118 goto out;
2119 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002120
2121 /* construct new filename */
2122 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2123 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2124 strcat(fle->fname, "/");
2125 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002126
2127 llist_add_tail(&fle->list, &bs11_sw->file_list);
2128 }
2129
2130out:
2131 fclose(swl);
2132 return rc;
2133}
2134
2135/* bs11 swload specific callback, passed to abis_nm core swload */
2136static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2137 struct msgb *msg, void *data, void *param)
2138{
2139 struct abis_nm_bs11_sw *bs11_sw = data;
2140 struct file_list_entry *fle;
2141 int rc = 0;
2142
Harald Welte5e4d1b32009-02-01 13:36:56 +00002143 switch (event) {
2144 case NM_MT_LOAD_END_ACK:
2145 fle = fl_dequeue(&bs11_sw->file_list);
2146 if (fle) {
2147 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002148 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002149 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002150 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002151 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002152 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002153 } else {
2154 /* activate the SWL */
2155 rc = abis_nm_software_activate(bs11_sw->bts,
2156 bs11_sw->swl_fname,
2157 bs11_swload_cbfn,
2158 bs11_sw);
2159 }
2160 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002161 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002162 case NM_MT_LOAD_END_NACK:
2163 case NM_MT_LOAD_INIT_ACK:
2164 case NM_MT_LOAD_INIT_NACK:
2165 case NM_MT_ACTIVATE_SW_NACK:
2166 case NM_MT_ACTIVATE_SW_ACK:
2167 default:
2168 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002169 if (bs11_sw->user_cb)
2170 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002171 break;
2172 }
2173
2174 return rc;
2175}
2176
2177/* Siemens provides a SWL file that is a mere listing of all the other
2178 * files that are part of a software release. We need to upload first
2179 * the list file, and then each file that is listed in the list file */
2180int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002181 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002182{
2183 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2184 struct file_list_entry *fle;
2185 int rc = 0;
2186
2187 INIT_LLIST_HEAD(&bs11_sw->file_list);
2188 bs11_sw->bts = bts;
2189 bs11_sw->win_size = win_size;
2190 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002191 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002192
2193 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2194 rc = bs11_read_swl_file(bs11_sw);
2195 if (rc < 0)
2196 return rc;
2197
2198 /* dequeue next item in file list */
2199 fle = fl_dequeue(&bs11_sw->file_list);
2200 if (!fle)
2201 return -EINVAL;
2202
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(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002205 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002206 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002207 return rc;
2208}
2209
Harald Welte5083b0b2009-02-02 19:20:52 +00002210#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002211static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002212 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2213 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2214 NM_ATT_BS11_LMT_USER_NAME,
2215
2216 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2217
2218 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2219
2220 NM_ATT_BS11_SW_LOAD_STORED };
2221
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002222static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002223 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2224 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2225 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2226 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002227#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002228
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002229static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002230 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2231 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002232 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002233
2234int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2235{
2236 struct abis_om_hdr *oh;
2237 struct msgb *msg = nm_msgb_alloc();
2238
2239 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2240 /* SiemensHW CCTRL object */
2241 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2242 0x03, 0x00, 0x00);
2243 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2244
2245 return abis_nm_sendmsg(bts, msg);
2246}
Harald Welte268bb402009-02-01 19:11:56 +00002247
2248int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2249{
2250 struct abis_om_hdr *oh;
2251 struct msgb *msg = nm_msgb_alloc();
2252 struct bs11_date_time aet;
2253
2254 get_bs11_date_time(&aet);
2255 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2256 /* SiemensHW CCTRL object */
2257 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2258 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002259 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002260
2261 return abis_nm_sendmsg(bts, msg);
2262}
Harald Welte5c1e4582009-02-15 11:57:29 +00002263
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002264int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002265{
2266 struct abis_om_hdr *oh;
2267 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002268 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002269
2270 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2271 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2272 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2273 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2274
2275 return abis_nm_sendmsg(bts, msg);
2276}
2277
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002278int 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 +02002279{
2280 struct abis_om_hdr *oh;
2281 struct msgb *msg = nm_msgb_alloc();
2282 struct bs11_date_time aet;
2283
2284 get_bs11_date_time(&aet);
2285 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2286 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2287 bport, 0xff, 0x02);
2288 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2289
2290 return abis_nm_sendmsg(bts, msg);
2291}
2292
Harald Welte5c1e4582009-02-15 11:57:29 +00002293/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002294static const char ipaccess_magic[] = "com.ipaccess";
2295
Harald Welte677c21f2009-02-17 13:22:23 +00002296
2297static int abis_nm_rx_ipacc(struct msgb *msg)
2298{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002299 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002300 struct abis_om_hdr *oh = msgb_l2(msg);
2301 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002302 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002303 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002304 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002305 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002306
2307 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002308 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002309 return -EINVAL;
2310 }
2311
Harald Welte193fefc2009-04-30 15:16:27 +00002312 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002313 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002314
Harald Welte15c61722011-05-22 22:45:37 +02002315 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002316
Harald Welte746d6092009-10-19 22:11:11 +02002317 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002318
Harald Welte677c21f2009-02-17 13:22:23 +00002319 switch (foh->msg_type) {
2320 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002321 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002322 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2323 memcpy(&addr,
2324 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2325
2326 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2327 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002328 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002329 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002330 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002331 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002332 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2333 DEBUGPC(DNM, "STREAM=0x%02x ",
2334 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002335 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002336 break;
2337 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002338 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002339 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002340 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002341 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002342 else
2343 DEBUGPC(DNM, "\n");
2344 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002345 case NM_MT_IPACC_SET_NVATTR_ACK:
2346 DEBUGPC(DNM, "SET NVATTR ACK\n");
2347 /* FIXME: decode and show the actual attributes */
2348 break;
2349 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002350 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002351 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002352 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002353 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002354 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002355 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002356 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002357 case NM_MT_IPACC_GET_NVATTR_ACK:
2358 DEBUGPC(DNM, "GET NVATTR ACK\n");
2359 /* FIXME: decode and show the actual attributes */
2360 break;
2361 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002362 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002363 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002364 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002365 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002366 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002367 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002368 break;
Harald Welte15c44172009-10-08 20:15:24 +02002369 case NM_MT_IPACC_SET_ATTR_ACK:
2370 DEBUGPC(DNM, "SET ATTR ACK\n");
2371 break;
2372 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002373 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002374 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002375 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002376 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002377 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002378 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002379 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002380 default:
2381 DEBUGPC(DNM, "unknown\n");
2382 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002383 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002384
2385 /* signal handling */
2386 switch (foh->msg_type) {
2387 case NM_MT_IPACC_RSL_CONNECT_NACK:
2388 case NM_MT_IPACC_SET_NVATTR_NACK:
2389 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002390 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 +01002391 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002392 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002393 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002394 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002395 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 +01002396 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002397 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002398 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002399 default:
2400 break;
2401 }
2402
Harald Welte677c21f2009-02-17 13:22:23 +00002403 return 0;
2404}
2405
Harald Welte193fefc2009-04-30 15:16:27 +00002406/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002407int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2408 uint8_t obj_class, uint8_t bts_nr,
2409 uint8_t trx_nr, uint8_t ts_nr,
2410 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002411{
2412 struct msgb *msg = nm_msgb_alloc();
2413 struct abis_om_hdr *oh;
2414 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002415 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002416
2417 /* construct the 12.21 OM header, observe the erroneous length */
2418 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2419 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2420 oh->mdisc = ABIS_OM_MDISC_MANUF;
2421
2422 /* add the ip.access magic */
2423 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2424 *data++ = sizeof(ipaccess_magic);
2425 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2426
2427 /* fill the 12.21 FOM header */
2428 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2429 foh->msg_type = msg_type;
2430 foh->obj_class = obj_class;
2431 foh->obj_inst.bts_nr = bts_nr;
2432 foh->obj_inst.trx_nr = trx_nr;
2433 foh->obj_inst.ts_nr = ts_nr;
2434
2435 if (attr && attr_len) {
2436 data = msgb_put(msg, attr_len);
2437 memcpy(data, attr, attr_len);
2438 }
2439
2440 return abis_nm_sendmsg(bts, msg);
2441}
Harald Welte677c21f2009-02-17 13:22:23 +00002442
Harald Welte193fefc2009-04-30 15:16:27 +00002443/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002444int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002445 int attr_len)
2446{
Harald Welte2ef156d2010-01-07 20:39:42 +01002447 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2448 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002449 attr_len);
2450}
2451
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002452int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002453 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002454{
2455 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002456 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002457 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2458 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2459
2460 int attr_len = sizeof(attr);
2461
2462 ia.s_addr = htonl(ip);
2463 attr[1] = stream;
2464 attr[3] = port >> 8;
2465 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002466 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002467
2468 /* if ip == 0, we use the default IP */
2469 if (ip == 0)
2470 attr_len -= 5;
2471
2472 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002473 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002474
2475 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2476 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2477 trx->nr, 0xff, attr, attr_len);
2478}
2479
Harald Welte193fefc2009-04-30 15:16:27 +00002480/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002481int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002482{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002483 struct abis_om_hdr *oh;
2484 struct msgb *msg = nm_msgb_alloc();
2485
2486 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2487 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2488 trx->bts->nr, trx->nr, 0xff);
2489
2490 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002491}
Harald Weltedaef5212009-10-24 10:20:41 +02002492
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002493int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2494 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2495 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002496{
2497 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2498 obj_class, bts_nr, trx_nr, ts_nr,
2499 attr, attr_len);
2500}
Harald Welte0f255852009-11-12 14:48:42 +01002501
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002502void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002503{
2504 /* we simply reuse the GSM48 function and overwrite the RAC
2505 * with the Cell ID */
2506 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002507 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002508}
2509
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002510void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2511{
2512 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2513
Harald Welted64c0bc2011-05-30 12:07:53 +02002514 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002515 if (!trx->bts || !trx->bts->oml_link)
2516 return;
2517
2518 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2519 trx->bts->bts_nr, trx->nr, 0xff,
2520 new_state);
2521}
2522
Harald Welte92b1fe42010-03-25 11:45:30 +08002523static const struct value_string ipacc_testres_names[] = {
2524 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2525 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2526 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2527 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2528 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2529 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002530};
2531
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002532const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002533{
Harald Welte92b1fe42010-03-25 11:45:30 +08002534 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002535}
2536
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002537void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002538{
2539 cid->mcc = (buf[0] & 0xf) * 100;
2540 cid->mcc += (buf[0] >> 4) * 10;
2541 cid->mcc += (buf[1] & 0xf) * 1;
2542
2543 if (buf[1] >> 4 == 0xf) {
2544 cid->mnc = (buf[2] & 0xf) * 10;
2545 cid->mnc += (buf[2] >> 4) * 1;
2546 } else {
2547 cid->mnc = (buf[2] & 0xf) * 100;
2548 cid->mnc += (buf[2] >> 4) * 10;
2549 cid->mnc += (buf[1] >> 4) * 1;
2550 }
2551
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002552 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2553 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002554}
2555
Harald Welte0f255852009-11-12 14:48:42 +01002556/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002557int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002558{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002559 uint8_t *cur = buf;
2560 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01002561
Harald Welteaf109b92010-07-22 18:14:36 +02002562 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002563
2564 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2565 return -EINVAL;
2566 cur++;
2567
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002568 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002569 cur += 2;
2570
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002571 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002572 cur += 2;
2573
2574 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2575 binf->freq_qual = *cur >> 2;
2576
Harald Welteaf109b92010-07-22 18:14:36 +02002577 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002578 binf->arfcn |= *cur++;
2579
2580 if (binf->info_type & IPAC_BINF_RXLEV)
2581 binf->rx_lev = *cur & 0x3f;
2582 cur++;
2583
2584 if (binf->info_type & IPAC_BINF_RXQUAL)
2585 binf->rx_qual = *cur & 0x7;
2586 cur++;
2587
2588 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002589 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002590 cur += 2;
2591
2592 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002593 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002594 cur += 2;
2595
2596 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002597 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002598 cur += 4;
2599
Harald Weltea780a3d2010-07-30 22:34:42 +02002600#if 0
2601 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002602 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002603#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002604 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002605 cur++;
2606
Harald Welteb40a38f2009-11-13 11:56:05 +01002607 ipac_parse_cgi(&binf->cgi, cur);
2608 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002609
2610 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2611 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2612 cur += sizeof(binf->ba_list_si2);
2613 }
2614
2615 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2616 memcpy(binf->ba_list_si2bis, cur,
2617 sizeof(binf->ba_list_si2bis));
2618 cur += sizeof(binf->ba_list_si2bis);
2619 }
2620
2621 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2622 memcpy(binf->ba_list_si2ter, cur,
2623 sizeof(binf->ba_list_si2ter));
2624 cur += sizeof(binf->ba_list_si2ter);
2625 }
2626
2627 return 0;
2628}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002629
2630void abis_nm_clear_queue(struct gsm_bts *bts)
2631{
2632 struct msgb *msg;
2633
2634 while (!llist_empty(&bts->abis_queue)) {
2635 msg = msgb_dequeue(&bts->abis_queue);
2636 msgb_free(msg);
2637 }
2638
2639 bts->abis_nm_pend = 0;
2640}