blob: 6568b53422924e3db45920f3cf40808a92958331 [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000043#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte52b1f982008-12-23 20:25:15 +000047
Harald Welte8470bf22008-12-25 23:28:35 +000048#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000051
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020052int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +000053{
Harald Welte39315c42010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000057}
Harald Weltee0590df2009-02-15 03:34:15 +000058
Harald Welte52b1f982008-12-23 20:25:15 +000059static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
Holger Freytherca362a62009-01-04 21:05:01 +000071#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000072/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
Holger Freytherca362a62009-01-04 21:05:01 +000077#endif
Harald Welte52b1f982008-12-23 20:25:15 +000078
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Welte15c61722011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +000099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
Harald Welte702d8702008-12-26 20:25:35 +0000103 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
109}
110
Harald Welte8470bf22008-12-25 23:28:35 +0000111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte966636f2009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000115}
116
Harald Welte15eae8d2011-09-26 23:43:23 +0200117int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200118{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200119 msg->l2h = msg->data;
120
121 if (!msg->dst) {
122 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
123 return -EINVAL;
124 }
125
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200126 return abis_sendmsg(msg);
127}
128
Harald Welte52b1f982008-12-23 20:25:15 +0000129/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100130static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000131{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200132 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000133
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100134 /* queue OML messages */
135 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
136 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200137 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100138 } else {
139 msgb_enqueue(&bts->abis_queue, msg);
140 return 0;
141 }
142
143}
144
145int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
146{
147 OBSC_NM_W_ACK_CB(msg) = 1;
148 return abis_nm_queue_msg(bts, msg);
149}
150
151static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
152{
153 OBSC_NM_W_ACK_CB(msg) = 0;
154 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000155}
156
Harald Welte4724f992009-01-18 18:01:49 +0000157static int abis_nm_rcvmsg_sw(struct msgb *mb);
158
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100159int nm_is_running(struct gsm_nm_state *s) {
160 return (s->operational == NM_OPSTATE_ENABLED) && (
161 (s->availability == NM_AVSTATE_OK) ||
162 (s->availability == 0xff)
163 );
164}
165
Harald Weltee0590df2009-02-15 03:34:15 +0000166/* Update the administrative state of a given object in our in-memory data
167 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200168static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
169 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000170{
Harald Welteaeedeb42009-05-01 13:08:14 +0000171 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100172 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000173
Harald Welteaf9b8102011-03-06 21:20:38 +0100174 memset(&nsd, 0, sizeof(nsd));
175
Harald Welte978714d2011-06-06 18:31:20 +0200176 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100177 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100178 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200179 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000180 if (!nm_state)
181 return -1;
182
183 new_state = *nm_state;
184 new_state.administrative = adm_state;
185
Harald Weltef38ca9a2011-03-06 22:11:32 +0100186 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100187 nsd.obj_class = obj_class;
188 nsd.old_state = nm_state;
189 nsd.new_state = &new_state;
190 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200191 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000192
193 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000194
Harald Weltef338a032011-01-14 15:55:42 +0100195 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000196}
197
Harald Welte97ed1e72009-02-06 13:38:02 +0000198static int abis_nm_rx_statechg_rep(struct msgb *mb)
199{
Harald Weltee0590df2009-02-15 03:34:15 +0000200 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000201 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200202 struct e1inp_sign_link *sign_link = mb->dst;
203 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000204 struct tlv_parsed tp;
205 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000206
Harald Welte23897662009-05-01 14:52:51 +0000207 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000208
Harald Welte8b697c72009-06-05 19:18:45 +0000209 memset(&new_state, 0, sizeof(new_state));
210
Harald Welte978714d2011-06-06 18:31:20 +0200211 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000212 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100213 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000214 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000215 }
Harald Weltee0590df2009-02-15 03:34:15 +0000216
217 new_state = *nm_state;
218
Harald Welte39315c42010-01-10 18:01:52 +0100219 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000220 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
221 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200222 DEBUGPC(DNM, "OP_STATE=%s ",
223 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000224 }
225 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000226 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
227 new_state.availability = 0xff;
228 else
229 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
231 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000232 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100233 } else
234 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000235 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
236 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200237 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200238 get_value_string(abis_nm_adm_state_names,
239 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000240 }
241 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000242
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100243 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
244 new_state.operational != nm_state->operational ||
245 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000246 /* Update the operational state of a given object in our in-memory data
247 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100248 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200249 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100250 nsd.obj_class = foh->obj_class;
251 nsd.old_state = nm_state;
252 nsd.new_state = &new_state;
253 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100254 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200255 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100256 nm_state->operational = new_state.operational;
257 nm_state->availability = new_state.availability;
258 if (nm_state->administrative == 0)
259 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000260 }
261#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000262 if (op_state == 1) {
263 /* try to enable objects that are disabled */
264 abis_nm_opstart(bts, foh->obj_class,
265 foh->obj_inst.bts_nr,
266 foh->obj_inst.trx_nr,
267 foh->obj_inst.ts_nr);
268 }
Harald Weltee0590df2009-02-15 03:34:15 +0000269#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000270 return 0;
271}
272
Harald Welte0db97b22009-05-01 17:22:47 +0000273static int rx_fail_evt_rep(struct msgb *mb)
274{
275 struct abis_om_hdr *oh = msgb_l2(mb);
276 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200277 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000278 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100279 const uint8_t *p_val;
280 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000281
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200282 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000283
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200284 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000285
286 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200287 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
288 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000289 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200290 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
291 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100292 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
293 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200294 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100295 }
296 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
297 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
298 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
299 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200300 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100301 talloc_free(p_text);
302 }
303 }
Harald Welte0db97b22009-05-01 17:22:47 +0000304
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200305 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000306
307 return 0;
308}
309
Harald Welte97ed1e72009-02-06 13:38:02 +0000310static int abis_nm_rcvmsg_report(struct msgb *mb)
311{
312 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200313 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000314
Harald Welte15c61722011-05-22 22:45:37 +0200315 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000316
Harald Welte97ed1e72009-02-06 13:38:02 +0000317 //nmh->cfg->report_cb(mb, foh);
318
319 switch (mt) {
320 case NM_MT_STATECHG_EVENT_REP:
321 return abis_nm_rx_statechg_rep(mb);
322 break;
Harald Welte34a99682009-02-13 02:41:40 +0000323 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000324 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200325 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000326 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000327 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000328 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200329 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000330 break;
Harald Weltec7310382009-08-08 00:02:36 +0200331 case NM_MT_TEST_REP:
332 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200334 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000335 default:
Harald Welte23897662009-05-01 14:52:51 +0000336 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000337 break;
338
Harald Welte97ed1e72009-02-06 13:38:02 +0000339 };
340
Harald Welte97ed1e72009-02-06 13:38:02 +0000341 return 0;
342}
343
Harald Welte34a99682009-02-13 02:41:40 +0000344/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200345static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
346 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000347{
348 struct abis_om_hdr *oh;
349 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200350 uint8_t len = swdesc_len;
351 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000352
353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
354 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
355
356 trailer = msgb_put(msg, swdesc_len);
357 memcpy(trailer, sw_desc, swdesc_len);
358
359 return abis_nm_sendmsg(bts, msg);
360}
361
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200362static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100363{
364 static const struct tlv_definition sw_descr_def = {
365 .def = {
366 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
367 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
368 },
369 };
370
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200371 uint8_t tag;
372 uint16_t tag_len;
373 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100374 int ofs = 0, len;
375
376 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
377 * nested nature and the fact you have to assume it contains only two sub
378 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
379
380 if (sw_descr[0] != NM_ATT_SW_DESCR) {
381 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
382 return -1;
383 }
384 ofs += 1;
385
386 len = tlv_parse_one(&tag, &tag_len, &val,
387 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
388 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
389 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
390 return -2;
391 }
392 ofs += len;
393
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
396 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
397 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
398 return -3;
399 }
400 ofs += len;
401
402 return ofs;
403}
404
Harald Welte34a99682009-02-13 02:41:40 +0000405static int abis_nm_rx_sw_act_req(struct msgb *mb)
406{
407 struct abis_om_hdr *oh = msgb_l2(mb);
408 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200409 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200410 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200411 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100412 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000413
Harald Welte15c61722011-05-22 22:45:37 +0200414 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200415
416 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000417
Harald Welte97a282b2010-03-14 15:37:43 +0800418 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000419
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200420 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000421 foh->obj_inst.bts_nr,
422 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800423 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000424 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100425 if (ret != 0) {
426 LOGP(DNM, LOGL_ERROR,
427 "Sending SW ActReq ACK failed: %d\n", ret);
428 return ret;
429 }
Harald Welte34a99682009-02-13 02:41:40 +0000430
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200431 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200432 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
433 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
434 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100435 LOGP(DNM, LOGL_ERROR,
436 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200437 return -EINVAL;
438 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200439 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200440 }
441
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100442 /* Use the first SW_DESCR present in SW config */
443 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
444 if (sw_descr_len < 0)
445 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200446
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200447 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000448 foh->obj_inst.bts_nr,
449 foh->obj_inst.trx_nr,
450 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100451 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000452}
453
Harald Weltee0590df2009-02-15 03:34:15 +0000454/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
455static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
456{
457 struct abis_om_hdr *oh = msgb_l2(mb);
458 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200459 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000460 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200461 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000462
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200463 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000464 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
465 return -EINVAL;
466
467 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
468
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200469 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000470}
471
Harald Welteee670472009-02-22 21:58:49 +0000472static int abis_nm_rx_lmt_event(struct msgb *mb)
473{
474 struct abis_om_hdr *oh = msgb_l2(mb);
475 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200476 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000477 struct tlv_parsed tp;
478
479 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200480 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000481 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
482 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200483 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000484 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
485 }
486 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
487 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200488 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000489 DEBUGPC(DNM, "Level=%u ", level);
490 }
491 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
492 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
493 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
494 DEBUGPC(DNM, "Username=%s ", name);
495 }
496 DEBUGPC(DNM, "\n");
497 /* FIXME: parse LMT LOGON TIME */
498 return 0;
499}
500
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200501void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100502{
503 int wait = 0;
504 struct msgb *msg;
505 /* the queue is empty */
506 while (!llist_empty(&bts->abis_queue)) {
507 msg = msgb_dequeue(&bts->abis_queue);
508 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200509 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100510
511 if (wait)
512 break;
513 }
514
515 bts->abis_nm_pend = wait;
516}
517
Harald Welte52b1f982008-12-23 20:25:15 +0000518/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000519static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000520{
Harald Welte6c96ba52009-05-01 13:03:40 +0000521 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000522 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200523 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200524 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100525 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000526
527 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000528 if (is_report(mt))
529 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000530
Harald Welte15c61722011-05-22 22:45:37 +0200531 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000532 return abis_nm_rcvmsg_sw(mb);
533
Harald Welte15c61722011-05-22 22:45:37 +0200534 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800535 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000536 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200537
Harald Welte15c61722011-05-22 22:45:37 +0200538 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200539
Harald Welte15c61722011-05-22 22:45:37 +0200540 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000541
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200542 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000543 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200544 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200545 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000546 else
547 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200548
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800549 nack_data.msg = mb;
550 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200551 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200552 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200553 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000554 }
Harald Weltead384642008-12-26 10:20:07 +0000555#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000556 /* check if last message is to be acked */
557 if (is_ack_nack(nmh->last_msgtype)) {
558 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100559 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000560 /* we got our ACK, continue sending the next msg */
561 } else if (mt == MT_NACK(nmh->last_msgtype)) {
562 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100563 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000564 /* FIXME: somehow signal this to the caller */
565 } else {
566 /* really strange things happen */
567 return -EINVAL;
568 }
569 }
Harald Weltead384642008-12-26 10:20:07 +0000570#endif
571
Harald Welte97ed1e72009-02-06 13:38:02 +0000572 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000573 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100574 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000575 break;
Harald Welte34a99682009-02-13 02:41:40 +0000576 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100577 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000578 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000579 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100580 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000581 break;
Harald Welte1989c082009-08-06 17:58:31 +0200582 case NM_MT_CONN_MDROP_LINK_ACK:
583 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
584 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100585 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200586 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100587 break;
588 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200589 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100590 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100591 case NM_MT_SET_BTS_ATTR_ACK:
592 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200593 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
594 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Weltefd355a32011-03-04 13:41:31 +0100595 }
596 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000597 }
598
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200599 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100600 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000601}
602
Harald Welte677c21f2009-02-17 13:22:23 +0000603static int abis_nm_rx_ipacc(struct msgb *mb);
604
605static int abis_nm_rcvmsg_manuf(struct msgb *mb)
606{
607 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200608 struct e1inp_sign_link *sign_link = mb->dst;
609 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000610
611 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100612 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000613 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200614 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000615 break;
616 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100617 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
618 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000619 rc = 0;
620 break;
621 }
622
623 return rc;
624}
625
Harald Welte52b1f982008-12-23 20:25:15 +0000626/* High-Level API */
627/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000628int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000629{
Harald Welte52b1f982008-12-23 20:25:15 +0000630 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000631 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000632
633 /* Various consistency checks */
634 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100635 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000636 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200637 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
638 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000639 }
640 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100641 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000642 oh->sequence);
643 return -EINVAL;
644 }
Harald Welte702d8702008-12-26 20:25:35 +0000645#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200646 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000647 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000648 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100649 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000650 oh->length + sizeof(*oh), l2_len);
651 return -EINVAL;
652 }
Harald Welte702d8702008-12-26 20:25:35 +0000653 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100654 LOGP(DNM, LOGL_ERROR, "ABIS OML 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 +0000655#endif
Harald Weltead384642008-12-26 10:20:07 +0000656 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000657
658 switch (oh->mdisc) {
659 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000660 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000661 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000662 case ABIS_OM_MDISC_MANUF:
663 rc = abis_nm_rcvmsg_manuf(msg);
664 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000665 case ABIS_OM_MDISC_MMI:
666 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100667 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000668 oh->mdisc);
669 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000670 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100671 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000672 oh->mdisc);
673 return -EINVAL;
674 }
675
Harald Weltead384642008-12-26 10:20:07 +0000676 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000677 return rc;
678}
679
680#if 0
681/* initialized all resources */
682struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
683{
684 struct abis_nm_h *nmh;
685
686 nmh = malloc(sizeof(*nmh));
687 if (!nmh)
688 return NULL;
689
690 nmh->cfg = cfg;
691
692 return nmh;
693}
694
695/* free all resources */
696void abis_nm_fini(struct abis_nm_h *nmh)
697{
698 free(nmh);
699}
700#endif
701
702/* Here we are trying to define a high-level API that can be used by
703 * the actual BSC implementation. However, the architecture is currently
704 * still under design. Ideally the calls to this API would be synchronous,
705 * while the underlying stack behind the APi runs in a traditional select
706 * based state machine.
707 */
708
Harald Welte4724f992009-01-18 18:01:49 +0000709/* 6.2 Software Load: */
710enum sw_state {
711 SW_STATE_NONE,
712 SW_STATE_WAIT_INITACK,
713 SW_STATE_WAIT_SEGACK,
714 SW_STATE_WAIT_ENDACK,
715 SW_STATE_WAIT_ACTACK,
716 SW_STATE_ERROR,
717};
Harald Welte52b1f982008-12-23 20:25:15 +0000718
Harald Welte52b1f982008-12-23 20:25:15 +0000719struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000720 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800721 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000722 gsm_cbfn *cbfn;
723 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000724 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000725
Harald Welte52b1f982008-12-23 20:25:15 +0000726 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200727 uint8_t obj_class;
728 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000729
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200730 uint8_t file_id[255];
731 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000732
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200733 uint8_t file_version[255];
734 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000735
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200736 uint8_t window_size;
737 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000738
739 int fd;
740 FILE *stream;
741 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000742 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000743};
744
Harald Welte4724f992009-01-18 18:01:49 +0000745static struct abis_nm_sw g_sw;
746
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100747static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
748{
749 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
750 msgb_v_put(msg, NM_ATT_SW_DESCR);
751 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
752 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
753 sw->file_version);
754 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
755 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
756 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
757 sw->file_version);
758 } else {
759 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
760 }
761}
762
Harald Welte4724f992009-01-18 18:01:49 +0000763/* 6.2.1 / 8.3.1: Load Data Initiate */
764static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000765{
Harald Welte4724f992009-01-18 18:01:49 +0000766 struct abis_om_hdr *oh;
767 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200768 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000769
770 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
771 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
772 sw->obj_instance[0], sw->obj_instance[1],
773 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100774
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100775 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000776 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
777
778 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000779}
780
Harald Welte1602ade2009-01-29 21:12:39 +0000781static int is_last_line(FILE *stream)
782{
783 char next_seg_buf[256];
784 long pos;
785
786 /* check if we're sending the last line */
787 pos = ftell(stream);
788 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
789 fseek(stream, pos, SEEK_SET);
790 return 1;
791 }
792
793 fseek(stream, pos, SEEK_SET);
794 return 0;
795}
796
Harald Welte4724f992009-01-18 18:01:49 +0000797/* 6.2.2 / 8.3.2 Load Data Segment */
798static int sw_load_segment(struct abis_nm_sw *sw)
799{
800 struct abis_om_hdr *oh;
801 struct msgb *msg = nm_msgb_alloc();
802 char seg_buf[256];
803 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000804 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200805 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000806
807 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000808
809 switch (sw->bts->type) {
810 case GSM_BTS_TYPE_BS11:
811 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
812 perror("fgets reading segment");
813 return -EINVAL;
814 }
815 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000816
817 /* check if we're sending the last line */
818 sw->last_seg = is_last_line(sw->stream);
819 if (sw->last_seg)
820 seg_buf[1] = 0;
821 else
822 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000823
824 len = strlen(line_buf) + 2;
825 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200826 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000827 /* BS11 wants CR + LF in excess of the TLV length !?! */
828 tlv[1] -= 2;
829
830 /* we only now know the exact length for the OM hdr */
831 len = strlen(line_buf)+2;
832 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100833 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200834 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100835 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
836 if (len < 0) {
837 perror("read failed");
838 return -EINVAL;
839 }
840
841 if (len != IPACC_SEGMENT_SIZE)
842 sw->last_seg = 1;
843
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100844 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200845 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100846 len += 3;
847 break;
848 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000849 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100850 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000851 /* FIXME: Other BTS types */
852 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000853 }
Harald Welte4724f992009-01-18 18:01:49 +0000854
Harald Welte4724f992009-01-18 18:01:49 +0000855 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
856 sw->obj_instance[0], sw->obj_instance[1],
857 sw->obj_instance[2]);
858
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100859 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000860}
861
862/* 6.2.4 / 8.3.4 Load Data End */
863static int sw_load_end(struct abis_nm_sw *sw)
864{
865 struct abis_om_hdr *oh;
866 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200867 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000868
869 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
870 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
871 sw->obj_instance[0], sw->obj_instance[1],
872 sw->obj_instance[2]);
873
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100874 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000875 return abis_nm_sendmsg(sw->bts, msg);
876}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000877
Harald Welte52b1f982008-12-23 20:25:15 +0000878/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000879static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000880{
Harald Welte4724f992009-01-18 18:01:49 +0000881 struct abis_om_hdr *oh;
882 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200883 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000884
Harald Welte4724f992009-01-18 18:01:49 +0000885 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
886 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
887 sw->obj_instance[0], sw->obj_instance[1],
888 sw->obj_instance[2]);
889
890 /* FIXME: this is BS11 specific format */
891 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
892 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
893 sw->file_version);
894
895 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000896}
Harald Welte4724f992009-01-18 18:01:49 +0000897
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100898struct sdp_firmware {
899 char magic[4];
900 char more_magic[4];
901 unsigned int header_length;
902 unsigned int file_length;
903} __attribute__ ((packed));
904
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100905static int parse_sdp_header(struct abis_nm_sw *sw)
906{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100907 struct sdp_firmware firmware_header;
908 int rc;
909 struct stat stat;
910
911 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
912 if (rc != sizeof(firmware_header)) {
913 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
914 return -1;
915 }
916
917 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
918 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
919 return -1;
920 }
921
922 if (firmware_header.more_magic[0] != 0x10 ||
923 firmware_header.more_magic[1] != 0x02 ||
924 firmware_header.more_magic[2] != 0x00 ||
925 firmware_header.more_magic[3] != 0x00) {
926 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
927 return -1;
928 }
929
930
931 if (fstat(sw->fd, &stat) == -1) {
932 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
933 return -1;
934 }
935
936 if (ntohl(firmware_header.file_length) != stat.st_size) {
937 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
938 return -1;
939 }
940
941 /* go back to the start as we checked the whole filesize.. */
942 lseek(sw->fd, 0l, SEEK_SET);
943 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
944 "There might be checksums in the file that are not\n"
945 "verified and incomplete firmware might be flashed.\n"
946 "There is absolutely no WARRANTY that flashing will\n"
947 "work.\n");
948 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100949}
950
Harald Welte4724f992009-01-18 18:01:49 +0000951static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
952{
953 char file_id[12+1];
954 char file_version[80+1];
955 int rc;
956
957 sw->fd = open(fname, O_RDONLY);
958 if (sw->fd < 0)
959 return sw->fd;
960
961 switch (sw->bts->type) {
962 case GSM_BTS_TYPE_BS11:
963 sw->stream = fdopen(sw->fd, "r");
964 if (!sw->stream) {
965 perror("fdopen");
966 return -1;
967 }
968 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200969 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +0000970 file_id, file_version);
971 if (rc != 2) {
972 perror("parsing header line of software file");
973 return -1;
974 }
975 strcpy((char *)sw->file_id, file_id);
976 sw->file_id_len = strlen(file_id);
977 strcpy((char *)sw->file_version, file_version);
978 sw->file_version_len = strlen(file_version);
979 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +0000980 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +0000981 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100982 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100983 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100984 rc = parse_sdp_header(sw);
985 if (rc < 0) {
986 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
987 return -1;
988 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100989
990 strcpy((char *)sw->file_id, "id");
991 sw->file_id_len = 3;
992 strcpy((char *)sw->file_version, "version");
993 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100994 break;
Harald Welte4724f992009-01-18 18:01:49 +0000995 default:
996 /* We don't know how to treat them yet */
997 close(sw->fd);
998 return -EINVAL;
999 }
1000
1001 return 0;
1002}
1003
1004static void sw_close_file(struct abis_nm_sw *sw)
1005{
1006 switch (sw->bts->type) {
1007 case GSM_BTS_TYPE_BS11:
1008 fclose(sw->stream);
1009 break;
1010 default:
1011 close(sw->fd);
1012 break;
1013 }
1014}
1015
1016/* Fill the window */
1017static int sw_fill_window(struct abis_nm_sw *sw)
1018{
1019 int rc;
1020
1021 while (sw->seg_in_window < sw->window_size) {
1022 rc = sw_load_segment(sw);
1023 if (rc < 0)
1024 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001025 if (sw->last_seg)
1026 break;
Harald Welte4724f992009-01-18 18:01:49 +00001027 }
1028 return 0;
1029}
1030
1031/* callback function from abis_nm_rcvmsg() handler */
1032static int abis_nm_rcvmsg_sw(struct msgb *mb)
1033{
1034 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001035 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001036 int rc = -1;
1037 struct abis_nm_sw *sw = &g_sw;
1038 enum sw_state old_state = sw->state;
1039
Harald Welte3ffd1372009-02-01 22:15:49 +00001040 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001041
1042 switch (sw->state) {
1043 case SW_STATE_WAIT_INITACK:
1044 switch (foh->msg_type) {
1045 case NM_MT_LOAD_INIT_ACK:
1046 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001047 if (sw->cbfn)
1048 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1049 NM_MT_LOAD_INIT_ACK, mb,
1050 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001051 rc = sw_fill_window(sw);
1052 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001053 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001054 break;
1055 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001056 if (sw->forced) {
1057 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1058 "Init NACK\n");
1059 if (sw->cbfn)
1060 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1061 NM_MT_LOAD_INIT_ACK, mb,
1062 sw->cb_data, NULL);
1063 rc = sw_fill_window(sw);
1064 sw->state = SW_STATE_WAIT_SEGACK;
1065 } else {
1066 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001067 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001068 if (sw->cbfn)
1069 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1070 NM_MT_LOAD_INIT_NACK, mb,
1071 sw->cb_data, NULL);
1072 sw->state = SW_STATE_ERROR;
1073 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001074 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001075 break;
1076 }
1077 break;
1078 case SW_STATE_WAIT_SEGACK:
1079 switch (foh->msg_type) {
1080 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001081 if (sw->cbfn)
1082 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1083 NM_MT_LOAD_SEG_ACK, mb,
1084 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001085 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001086 if (!sw->last_seg) {
1087 /* fill window with more segments */
1088 rc = sw_fill_window(sw);
1089 sw->state = SW_STATE_WAIT_SEGACK;
1090 } else {
1091 /* end the transfer */
1092 sw->state = SW_STATE_WAIT_ENDACK;
1093 rc = sw_load_end(sw);
1094 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001095 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001096 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001097 case NM_MT_LOAD_ABORT:
1098 if (sw->cbfn)
1099 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1100 NM_MT_LOAD_ABORT, mb,
1101 sw->cb_data, NULL);
1102 break;
Harald Welte4724f992009-01-18 18:01:49 +00001103 }
1104 break;
1105 case SW_STATE_WAIT_ENDACK:
1106 switch (foh->msg_type) {
1107 case NM_MT_LOAD_END_ACK:
1108 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001109 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1110 sw->bts->nr);
1111 sw->state = SW_STATE_NONE;
1112 if (sw->cbfn)
1113 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1114 NM_MT_LOAD_END_ACK, mb,
1115 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001116 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001117 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001118 break;
1119 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001120 if (sw->forced) {
1121 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1122 "End NACK\n");
1123 sw->state = SW_STATE_NONE;
1124 if (sw->cbfn)
1125 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1126 NM_MT_LOAD_END_ACK, mb,
1127 sw->cb_data, NULL);
1128 } else {
1129 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001130 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001131 sw->state = SW_STATE_ERROR;
1132 if (sw->cbfn)
1133 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1134 NM_MT_LOAD_END_NACK, mb,
1135 sw->cb_data, NULL);
1136 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001137 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001138 break;
1139 }
1140 case SW_STATE_WAIT_ACTACK:
1141 switch (foh->msg_type) {
1142 case NM_MT_ACTIVATE_SW_ACK:
1143 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001144 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001145 sw->state = SW_STATE_NONE;
1146 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001147 if (sw->cbfn)
1148 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1149 NM_MT_ACTIVATE_SW_ACK, mb,
1150 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001151 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001152 break;
1153 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001154 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001155 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001156 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001157 if (sw->cbfn)
1158 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1159 NM_MT_ACTIVATE_SW_NACK, mb,
1160 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001161 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001162 break;
1163 }
1164 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001165 switch (foh->msg_type) {
1166 case NM_MT_ACTIVATE_SW_ACK:
1167 rc = 0;
1168 break;
1169 }
1170 break;
Harald Welte4724f992009-01-18 18:01:49 +00001171 case SW_STATE_ERROR:
1172 break;
1173 }
1174
1175 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001176 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001177 foh->msg_type, old_state, sw->state);
1178
1179 return rc;
1180}
1181
1182/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001183int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001184 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001185 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001186{
1187 struct abis_nm_sw *sw = &g_sw;
1188 int rc;
1189
Harald Welte5e4d1b32009-02-01 13:36:56 +00001190 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1191 bts->nr, fname);
1192
Harald Welte4724f992009-01-18 18:01:49 +00001193 if (sw->state != SW_STATE_NONE)
1194 return -EBUSY;
1195
1196 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001197 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001198
1199 switch (bts->type) {
1200 case GSM_BTS_TYPE_BS11:
1201 sw->obj_class = NM_OC_SITE_MANAGER;
1202 sw->obj_instance[0] = 0xff;
1203 sw->obj_instance[1] = 0xff;
1204 sw->obj_instance[2] = 0xff;
1205 break;
1206 case GSM_BTS_TYPE_NANOBTS:
1207 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001208 sw->obj_instance[0] = sw->bts->nr;
1209 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001210 sw->obj_instance[2] = 0xff;
1211 break;
1212 case GSM_BTS_TYPE_UNKNOWN:
1213 default:
1214 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1215 return -1;
1216 break;
1217 }
Harald Welte4724f992009-01-18 18:01:49 +00001218 sw->window_size = win_size;
1219 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001220 sw->cbfn = cbfn;
1221 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001222 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001223
1224 rc = sw_open_file(sw, fname);
1225 if (rc < 0) {
1226 sw->state = SW_STATE_NONE;
1227 return rc;
1228 }
1229
1230 return sw_load_init(sw);
1231}
Harald Welte52b1f982008-12-23 20:25:15 +00001232
Harald Welte1602ade2009-01-29 21:12:39 +00001233int abis_nm_software_load_status(struct gsm_bts *bts)
1234{
1235 struct abis_nm_sw *sw = &g_sw;
1236 struct stat st;
1237 int rc, percent;
1238
1239 rc = fstat(sw->fd, &st);
1240 if (rc < 0) {
1241 perror("ERROR during stat");
1242 return rc;
1243 }
1244
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001245 if (sw->stream)
1246 percent = (ftell(sw->stream) * 100) / st.st_size;
1247 else
1248 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001249 return percent;
1250}
1251
Harald Welte5e4d1b32009-02-01 13:36:56 +00001252/* Activate the specified software into the BTS */
1253int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1254 gsm_cbfn *cbfn, void *cb_data)
1255{
1256 struct abis_nm_sw *sw = &g_sw;
1257 int rc;
1258
1259 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1260 bts->nr, fname);
1261
1262 if (sw->state != SW_STATE_NONE)
1263 return -EBUSY;
1264
1265 sw->bts = bts;
1266 sw->obj_class = NM_OC_SITE_MANAGER;
1267 sw->obj_instance[0] = 0xff;
1268 sw->obj_instance[1] = 0xff;
1269 sw->obj_instance[2] = 0xff;
1270 sw->state = SW_STATE_WAIT_ACTACK;
1271 sw->cbfn = cbfn;
1272 sw->cb_data = cb_data;
1273
1274 /* Open the file in order to fill some sw struct members */
1275 rc = sw_open_file(sw, fname);
1276 if (rc < 0) {
1277 sw->state = SW_STATE_NONE;
1278 return rc;
1279 }
1280 sw_close_file(sw);
1281
1282 return sw_activate(sw);
1283}
1284
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001285static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1286 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001287{
Harald Welteadaf08b2009-01-18 11:08:10 +00001288 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001289 ch->bts_port = bts_port;
1290 ch->timeslot = ts_nr;
1291 ch->subslot = subslot_nr;
1292}
1293
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001294int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1295 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1296 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001297{
1298 struct abis_om_hdr *oh;
1299 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001300 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001301 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001302
1303 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1304 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1305 bts->bts_nr, trx_nr, 0xff);
1306
Harald Welte8470bf22008-12-25 23:28:35 +00001307 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001308
1309 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1310 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1311
1312 return abis_nm_sendmsg(bts, msg);
1313}
1314
1315/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1316int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001317 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001318{
Harald Welte8470bf22008-12-25 23:28:35 +00001319 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001320 struct abis_om_hdr *oh;
1321 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001322 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001323
1324 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001325 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001326 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1327
1328 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1329 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1330
1331 return abis_nm_sendmsg(bts, msg);
1332}
1333
1334#if 0
1335int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1336 struct abis_nm_abis_channel *chan)
1337{
1338}
1339#endif
1340
1341int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001342 uint8_t e1_port, uint8_t e1_timeslot,
1343 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001344{
1345 struct gsm_bts *bts = ts->trx->bts;
1346 struct abis_om_hdr *oh;
1347 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001348 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001349
1350 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1351 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001352 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001353
1354 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1355 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1356
Harald Weltef325eb42009-02-19 17:07:39 +00001357 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1358 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001359 e1_port, e1_timeslot, e1_subslot);
1360
Harald Welte52b1f982008-12-23 20:25:15 +00001361 return abis_nm_sendmsg(bts, msg);
1362}
1363
1364#if 0
1365int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1366 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001367 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001368{
1369}
1370#endif
1371
Harald Welte22af0db2009-02-14 15:41:08 +00001372/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001373int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001374{
1375 struct abis_om_hdr *oh;
1376 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001377 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001378
1379 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1380
1381 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001382 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 +00001383 cur = msgb_put(msg, attr_len);
1384 memcpy(cur, attr, attr_len);
1385
1386 return abis_nm_sendmsg(bts, msg);
1387}
1388
1389/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001390int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001391{
1392 struct abis_om_hdr *oh;
1393 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001394 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001395
1396 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1397
1398 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1399 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001400 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001401 cur = msgb_put(msg, attr_len);
1402 memcpy(cur, attr, attr_len);
1403
1404 return abis_nm_sendmsg(trx->bts, msg);
1405}
1406
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001407static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001408{
1409 int i;
1410
1411 /* As it turns out, the BS-11 has some very peculiar restrictions
1412 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301413 switch (ts->trx->bts->type) {
1414 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001415 switch (chan_comb) {
1416 case NM_CHANC_TCHHalf:
1417 case NM_CHANC_TCHHalf2:
1418 /* not supported */
1419 return -EINVAL;
1420 case NM_CHANC_SDCCH:
1421 /* only one SDCCH/8 per TRX */
1422 for (i = 0; i < TRX_NR_TS; i++) {
1423 if (i == ts->nr)
1424 continue;
1425 if (ts->trx->ts[i].nm_chan_comb ==
1426 NM_CHANC_SDCCH)
1427 return -EINVAL;
1428 }
1429 /* not allowed for TS0 of BCCH-TRX */
1430 if (ts->trx == ts->trx->bts->c0 &&
1431 ts->nr == 0)
1432 return -EINVAL;
1433 /* not on the same TRX that has a BCCH+SDCCH4
1434 * combination */
1435 if (ts->trx == ts->trx->bts->c0 &&
1436 (ts->trx->ts[0].nm_chan_comb == 5 ||
1437 ts->trx->ts[0].nm_chan_comb == 8))
1438 return -EINVAL;
1439 break;
1440 case NM_CHANC_mainBCCH:
1441 case NM_CHANC_BCCHComb:
1442 /* allowed only for TS0 of C0 */
1443 if (ts->trx != ts->trx->bts->c0 ||
1444 ts->nr != 0)
1445 return -EINVAL;
1446 break;
1447 case NM_CHANC_BCCH:
1448 /* allowed only for TS 2/4/6 of C0 */
1449 if (ts->trx != ts->trx->bts->c0)
1450 return -EINVAL;
1451 if (ts->nr != 2 && ts->nr != 4 &&
1452 ts->nr != 6)
1453 return -EINVAL;
1454 break;
1455 case 8: /* this is not like 08.58, but in fact
1456 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1457 /* FIXME: only one CBCH allowed per cell */
1458 break;
1459 }
Harald Welted6575f92009-12-02 02:45:23 +05301460 break;
1461 case GSM_BTS_TYPE_NANOBTS:
1462 switch (ts->nr) {
1463 case 0:
1464 if (ts->trx->nr == 0) {
1465 /* only on TRX0 */
1466 switch (chan_comb) {
1467 case NM_CHANC_BCCH:
1468 case NM_CHANC_mainBCCH:
1469 case NM_CHANC_BCCHComb:
1470 return 0;
1471 break;
1472 default:
1473 return -EINVAL;
1474 }
1475 } else {
1476 switch (chan_comb) {
1477 case NM_CHANC_TCHFull:
1478 case NM_CHANC_TCHHalf:
1479 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1480 return 0;
1481 default:
1482 return -EINVAL;
1483 }
1484 }
1485 break;
1486 case 1:
1487 if (ts->trx->nr == 0) {
1488 switch (chan_comb) {
1489 case NM_CHANC_SDCCH_CBCH:
1490 if (ts->trx->ts[0].nm_chan_comb ==
1491 NM_CHANC_mainBCCH)
1492 return 0;
1493 return -EINVAL;
1494 case NM_CHANC_SDCCH:
1495 case NM_CHANC_TCHFull:
1496 case NM_CHANC_TCHHalf:
1497 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1498 case NM_CHANC_IPAC_TCHFull_PDCH:
1499 return 0;
1500 }
1501 } else {
1502 switch (chan_comb) {
1503 case NM_CHANC_SDCCH:
1504 case NM_CHANC_TCHFull:
1505 case NM_CHANC_TCHHalf:
1506 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1507 return 0;
1508 default:
1509 return -EINVAL;
1510 }
1511 }
1512 break;
1513 case 2:
1514 case 3:
1515 case 4:
1516 case 5:
1517 case 6:
1518 case 7:
1519 switch (chan_comb) {
1520 case NM_CHANC_TCHFull:
1521 case NM_CHANC_TCHHalf:
1522 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1523 return 0;
1524 case NM_CHANC_IPAC_PDCH:
1525 case NM_CHANC_IPAC_TCHFull_PDCH:
1526 if (ts->trx->nr == 0)
1527 return 0;
1528 else
1529 return -EINVAL;
1530 }
1531 break;
1532 }
1533 return -EINVAL;
1534 default:
1535 /* unknown BTS type */
1536 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001537 }
1538 return 0;
1539}
1540
Harald Welte22af0db2009-02-14 15:41:08 +00001541/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001542int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001543{
1544 struct gsm_bts *bts = ts->trx->bts;
1545 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001546 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001547 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001548 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00001549
1550 if (bts->type == GSM_BTS_TYPE_BS11)
1551 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001552
Harald Weltef325eb42009-02-19 17:07:39 +00001553 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001554 if (verify_chan_comb(ts, chan_comb) < 0) {
1555 msgb_free(msg);
1556 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1557 return -EINVAL;
1558 }
1559 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001560
Harald Welte52b1f982008-12-23 20:25:15 +00001561 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001562 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001563 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001564 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001565 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001566 if (ts->hopping.enabled) {
1567 unsigned int i;
1568 uint8_t *len;
1569
Harald Welte6e0cd042009-09-12 13:05:33 +02001570 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1571 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001572
1573 /* build the ARFCN list */
1574 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1575 len = msgb_put(msg, 1);
1576 *len = 0;
1577 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1578 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1579 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001580 /* At least BS-11 wants a TLV16 here */
1581 if (bts->type == GSM_BTS_TYPE_BS11)
1582 *len += 1;
1583 else
1584 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001585 }
1586 }
Harald Weltee0590df2009-02-15 03:34:15 +00001587 }
Harald Welte135a6482011-05-30 12:09:13 +02001588 if (ts->tsc == -1)
1589 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1590 else
1591 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001592 if (bts->type == GSM_BTS_TYPE_BS11)
1593 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001594
1595 return abis_nm_sendmsg(bts, msg);
1596}
1597
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001598int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1599 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001600{
1601 struct abis_om_hdr *oh;
1602 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001603 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1604 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001605
1606 if (nack) {
1607 len += 2;
1608 msgtype = NM_MT_SW_ACT_REQ_NACK;
1609 }
Harald Welte34a99682009-02-13 02:41:40 +00001610
1611 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001612 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1613
Harald Welte34a99682009-02-13 02:41:40 +00001614 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001615 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001616 memcpy(ptr, attr, att_len);
1617 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001618 if (nack)
1619 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001620
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001621 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001622}
1623
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001624int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001625{
Harald Welte8470bf22008-12-25 23:28:35 +00001626 struct msgb *msg = nm_msgb_alloc();
1627 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001628 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001629
1630 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1631 fill_om_hdr(oh, len);
1632 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001633 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001634
1635 return abis_nm_sendmsg(bts, msg);
1636}
1637
1638/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001639static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001640{
1641 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001642 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001643
1644 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001645 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001646 0xff, 0xff, 0xff);
1647
1648 return abis_nm_sendmsg(bts, msg);
1649}
1650
Harald Welte34a99682009-02-13 02:41:40 +00001651/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001652int 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 +00001653{
1654 struct abis_om_hdr *oh;
1655 struct msgb *msg = nm_msgb_alloc();
1656
1657 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1658 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1659
Harald Welte15c61722011-05-22 22:45:37 +02001660 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001661 DEBUGPC(DNM, "Sending OPSTART\n");
1662
Harald Welte34a99682009-02-13 02:41:40 +00001663 return abis_nm_sendmsg(bts, msg);
1664}
1665
1666/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001667int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1668 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001669{
1670 struct abis_om_hdr *oh;
1671 struct msgb *msg = nm_msgb_alloc();
1672
1673 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1674 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1675 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1676
1677 return abis_nm_sendmsg(bts, msg);
1678}
1679
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001680int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1681 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001682{
1683 struct abis_om_hdr *oh;
1684 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001685 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001686
1687 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1688 e1_port0, ts0, e1_port1, ts1);
1689
1690 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1691 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1692 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1693
1694 attr = msgb_put(msg, 3);
1695 attr[0] = NM_ATT_MDROP_LINK;
1696 attr[1] = e1_port0;
1697 attr[2] = ts0;
1698
1699 attr = msgb_put(msg, 3);
1700 attr[0] = NM_ATT_MDROP_NEXT;
1701 attr[1] = e1_port1;
1702 attr[2] = ts1;
1703
1704 return abis_nm_sendmsg(bts, msg);
1705}
Harald Welte34a99682009-02-13 02:41:40 +00001706
Harald Weltec7310382009-08-08 00:02:36 +02001707/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001708int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1709 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1710 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001711{
1712 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001713
Harald Welte15c61722011-05-22 22:45:37 +02001714 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001715
1716 if (!msg)
1717 msg = nm_msgb_alloc();
1718
1719 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1720 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1721 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1722 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001723 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001724
1725 return abis_nm_sendmsg(bts, msg);
1726}
1727
Harald Welte52b1f982008-12-23 20:25:15 +00001728int abis_nm_event_reports(struct gsm_bts *bts, int on)
1729{
1730 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001731 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001732 else
Harald Welte227d4072009-01-03 08:16:25 +00001733 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001734}
1735
Harald Welte47d88ae2009-01-04 12:02:08 +00001736/* Siemens (or BS-11) specific commands */
1737
Harald Welte3ffd1372009-02-01 22:15:49 +00001738int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1739{
1740 if (reconnect == 0)
1741 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1742 else
1743 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1744}
1745
Harald Welteb8427972009-02-05 19:27:17 +00001746int abis_nm_bs11_restart(struct gsm_bts *bts)
1747{
1748 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1749}
1750
1751
Harald Welte268bb402009-02-01 19:11:56 +00001752struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001753 uint16_t year;
1754 uint8_t month;
1755 uint8_t day;
1756 uint8_t hour;
1757 uint8_t min;
1758 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001759} __attribute__((packed));
1760
1761
1762void get_bs11_date_time(struct bs11_date_time *aet)
1763{
1764 time_t t;
1765 struct tm *tm;
1766
1767 t = time(NULL);
1768 tm = localtime(&t);
1769 aet->sec = tm->tm_sec;
1770 aet->min = tm->tm_min;
1771 aet->hour = tm->tm_hour;
1772 aet->day = tm->tm_mday;
1773 aet->month = tm->tm_mon;
1774 aet->year = htons(1900 + tm->tm_year);
1775}
1776
Harald Welte05188ee2009-01-18 11:39:08 +00001777int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001778{
Harald Welte4668fda2009-01-03 08:19:29 +00001779 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001780}
1781
Harald Welte05188ee2009-01-18 11:39:08 +00001782int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001783{
1784 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001785 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001786 else
Harald Welte4668fda2009-01-03 08:19:29 +00001787 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001788}
Harald Welte47d88ae2009-01-04 12:02:08 +00001789
Harald Welte05188ee2009-01-18 11:39:08 +00001790int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001791 enum abis_bs11_objtype type, uint8_t idx,
1792 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001793{
1794 struct abis_om_hdr *oh;
1795 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001796 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001797
1798 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001799 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001800 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001801 cur = msgb_put(msg, attr_len);
1802 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001803
1804 return abis_nm_sendmsg(bts, msg);
1805}
1806
Harald Welte78fc0d42009-02-19 02:50:57 +00001807int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001808 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001809{
1810 struct abis_om_hdr *oh;
1811 struct msgb *msg = nm_msgb_alloc();
1812
1813 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1814 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1815 NM_OC_BS11, type, 0, idx);
1816
1817 return abis_nm_sendmsg(bts, msg);
1818}
1819
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001820int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001821{
1822 struct abis_om_hdr *oh;
1823 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001824 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001825
1826 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001827 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001828 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1829 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001830
1831 return abis_nm_sendmsg(bts, msg);
1832}
1833
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001834int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001835{
1836 struct abis_om_hdr *oh;
1837 struct msgb *msg = nm_msgb_alloc();
1838
1839 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1840 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001841 idx, 0xff, 0xff);
1842
1843 return abis_nm_sendmsg(bts, msg);
1844}
1845
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001846int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001847{
1848 struct abis_om_hdr *oh;
1849 struct msgb *msg = nm_msgb_alloc();
1850
1851 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1852 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1853 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001854
1855 return abis_nm_sendmsg(bts, msg);
1856}
Harald Welte05188ee2009-01-18 11:39:08 +00001857
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001858static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001859int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1860{
1861 struct abis_om_hdr *oh;
1862 struct msgb *msg = nm_msgb_alloc();
1863
1864 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1865 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1866 0xff, 0xff, 0xff);
1867 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1868
1869 return abis_nm_sendmsg(bts, msg);
1870}
1871
Harald Welteb6c92ae2009-02-21 20:15:32 +00001872/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001873int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1874 uint8_t e1_timeslot, uint8_t e1_subslot,
1875 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001876{
1877 struct abis_om_hdr *oh;
1878 struct abis_nm_channel *ch;
1879 struct msgb *msg = nm_msgb_alloc();
1880
1881 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001882 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001883 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1884
1885 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1886 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001887 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001888
1889 return abis_nm_sendmsg(bts, msg);
1890}
1891
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001892int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001893{
1894 struct abis_om_hdr *oh;
1895 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001896
1897 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001898 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001899 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1900 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1901
1902 return abis_nm_sendmsg(trx->bts, msg);
1903}
1904
Harald Welte78fc0d42009-02-19 02:50:57 +00001905int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1906{
1907 struct abis_om_hdr *oh;
1908 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001909 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00001910
1911 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1912 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1913 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1914 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1915
1916 return abis_nm_sendmsg(trx->bts, msg);
1917}
1918
Harald Welteaaf02d92009-04-29 13:25:57 +00001919int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1920{
1921 struct abis_om_hdr *oh;
1922 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001923 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00001924
1925 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1926 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1927 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00001928 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00001929
1930 return abis_nm_sendmsg(bts, msg);
1931}
1932
Harald Welteef061952009-05-17 12:43:42 +00001933int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1934{
1935 struct abis_om_hdr *oh;
1936 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001937 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00001938 NM_ATT_BS11_CCLK_TYPE };
1939
1940 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1941 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1942 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1943 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1944
1945 return abis_nm_sendmsg(bts, msg);
1946
1947}
Harald Welteaaf02d92009-04-29 13:25:57 +00001948
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001949//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00001950
Harald Welte1bc09062009-01-18 14:17:52 +00001951int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00001952{
Daniel Willmann493db4e2010-01-07 00:43:11 +01001953 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1954}
1955
Daniel Willmann4b054c82010-01-07 00:46:26 +01001956int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1957{
1958 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1959}
1960
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001961int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001962{
Harald Welte05188ee2009-01-18 11:39:08 +00001963 struct abis_om_hdr *oh;
1964 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00001965 struct bs11_date_time bdt;
1966
1967 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00001968
1969 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00001970 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001971 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001972 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00001973 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001974 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00001975 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001976 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00001977 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01001978 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00001979 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001980 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00001981 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00001982 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001983 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00001984 }
Harald Welte05188ee2009-01-18 11:39:08 +00001985
1986 return abis_nm_sendmsg(bts, msg);
1987}
Harald Welte1bc09062009-01-18 14:17:52 +00001988
1989int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
1990{
1991 struct abis_om_hdr *oh;
1992 struct msgb *msg;
1993
1994 if (strlen(password) != 10)
1995 return -EINVAL;
1996
1997 msg = nm_msgb_alloc();
1998 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001999 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002000 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002001 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002002
2003 return abis_nm_sendmsg(bts, msg);
2004}
2005
Harald Weltee69f5fb2009-04-28 16:31:38 +00002006/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2007int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2008{
2009 struct abis_om_hdr *oh;
2010 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002011 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002012
2013 msg = nm_msgb_alloc();
2014 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2015 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2016 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002017
2018 if (locked)
2019 tlv_value = BS11_LI_PLL_LOCKED;
2020 else
2021 tlv_value = BS11_LI_PLL_STANDALONE;
2022
2023 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002024
2025 return abis_nm_sendmsg(bts, msg);
2026}
2027
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002028/* Set the calibration value of the PLL (work value/set value)
2029 * It depends on the login which one is changed */
2030int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2031{
2032 struct abis_om_hdr *oh;
2033 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002034 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002035
2036 msg = nm_msgb_alloc();
2037 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2038 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2039 BS11_OBJ_TRX1, 0x00, 0x00);
2040
2041 tlv_value[0] = value>>8;
2042 tlv_value[1] = value&0xff;
2043
2044 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2045
2046 return abis_nm_sendmsg(bts, msg);
2047}
2048
Harald Welte1bc09062009-01-18 14:17:52 +00002049int abis_nm_bs11_get_state(struct gsm_bts *bts)
2050{
2051 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2052}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002053
2054/* BS11 SWL */
2055
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002056void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002057
Harald Welte5e4d1b32009-02-01 13:36:56 +00002058struct abis_nm_bs11_sw {
2059 struct gsm_bts *bts;
2060 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002061 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002062 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002063 struct llist_head file_list;
2064 gsm_cbfn *user_cb; /* specified by the user */
2065};
2066static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2067
2068struct file_list_entry {
2069 struct llist_head list;
2070 char fname[PATH_MAX];
2071};
2072
2073struct file_list_entry *fl_dequeue(struct llist_head *queue)
2074{
2075 struct llist_head *lh;
2076
2077 if (llist_empty(queue))
2078 return NULL;
2079
2080 lh = queue->next;
2081 llist_del(lh);
2082
2083 return llist_entry(lh, struct file_list_entry, list);
2084}
2085
2086static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2087{
2088 char linebuf[255];
2089 struct llist_head *lh, *lh2;
2090 FILE *swl;
2091 int rc = 0;
2092
2093 swl = fopen(bs11_sw->swl_fname, "r");
2094 if (!swl)
2095 return -ENODEV;
2096
2097 /* zero the stale file list, if any */
2098 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2099 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002100 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002101 }
2102
2103 while (fgets(linebuf, sizeof(linebuf), swl)) {
2104 char file_id[12+1];
2105 char file_version[80+1];
2106 struct file_list_entry *fle;
2107 static char dir[PATH_MAX];
2108
2109 if (strlen(linebuf) < 4)
2110 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002111
Harald Welte5e4d1b32009-02-01 13:36:56 +00002112 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2113 if (rc < 0) {
2114 perror("ERR parsing SWL file");
2115 rc = -EINVAL;
2116 goto out;
2117 }
2118 if (rc < 2)
2119 continue;
2120
Harald Welte470ec292009-06-26 20:25:23 +02002121 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002122 if (!fle) {
2123 rc = -ENOMEM;
2124 goto out;
2125 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002126
2127 /* construct new filename */
2128 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2129 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2130 strcat(fle->fname, "/");
2131 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002132
2133 llist_add_tail(&fle->list, &bs11_sw->file_list);
2134 }
2135
2136out:
2137 fclose(swl);
2138 return rc;
2139}
2140
2141/* bs11 swload specific callback, passed to abis_nm core swload */
2142static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2143 struct msgb *msg, void *data, void *param)
2144{
2145 struct abis_nm_bs11_sw *bs11_sw = data;
2146 struct file_list_entry *fle;
2147 int rc = 0;
2148
Harald Welte5e4d1b32009-02-01 13:36:56 +00002149 switch (event) {
2150 case NM_MT_LOAD_END_ACK:
2151 fle = fl_dequeue(&bs11_sw->file_list);
2152 if (fle) {
2153 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002154 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002155 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002156 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002157 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002158 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002159 } else {
2160 /* activate the SWL */
2161 rc = abis_nm_software_activate(bs11_sw->bts,
2162 bs11_sw->swl_fname,
2163 bs11_swload_cbfn,
2164 bs11_sw);
2165 }
2166 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002167 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002168 case NM_MT_LOAD_END_NACK:
2169 case NM_MT_LOAD_INIT_ACK:
2170 case NM_MT_LOAD_INIT_NACK:
2171 case NM_MT_ACTIVATE_SW_NACK:
2172 case NM_MT_ACTIVATE_SW_ACK:
2173 default:
2174 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002175 if (bs11_sw->user_cb)
2176 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002177 break;
2178 }
2179
2180 return rc;
2181}
2182
2183/* Siemens provides a SWL file that is a mere listing of all the other
2184 * files that are part of a software release. We need to upload first
2185 * the list file, and then each file that is listed in the list file */
2186int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002187 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002188{
2189 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2190 struct file_list_entry *fle;
2191 int rc = 0;
2192
2193 INIT_LLIST_HEAD(&bs11_sw->file_list);
2194 bs11_sw->bts = bts;
2195 bs11_sw->win_size = win_size;
2196 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002197 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002198
2199 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2200 rc = bs11_read_swl_file(bs11_sw);
2201 if (rc < 0)
2202 return rc;
2203
2204 /* dequeue next item in file list */
2205 fle = fl_dequeue(&bs11_sw->file_list);
2206 if (!fle)
2207 return -EINVAL;
2208
2209 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002210 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002211 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002212 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002213 return rc;
2214}
2215
Harald Welte5083b0b2009-02-02 19:20:52 +00002216#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002217static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002218 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2219 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2220 NM_ATT_BS11_LMT_USER_NAME,
2221
2222 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2223
2224 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2225
2226 NM_ATT_BS11_SW_LOAD_STORED };
2227
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002228static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002229 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2230 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2231 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2232 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002233#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002234
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002235static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002236 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2237 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002238 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002239
2240int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2241{
2242 struct abis_om_hdr *oh;
2243 struct msgb *msg = nm_msgb_alloc();
2244
2245 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2246 /* SiemensHW CCTRL object */
2247 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2248 0x03, 0x00, 0x00);
2249 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2250
2251 return abis_nm_sendmsg(bts, msg);
2252}
Harald Welte268bb402009-02-01 19:11:56 +00002253
2254int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2255{
2256 struct abis_om_hdr *oh;
2257 struct msgb *msg = nm_msgb_alloc();
2258 struct bs11_date_time aet;
2259
2260 get_bs11_date_time(&aet);
2261 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2262 /* SiemensHW CCTRL object */
2263 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2264 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002265 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002266
2267 return abis_nm_sendmsg(bts, msg);
2268}
Harald Welte5c1e4582009-02-15 11:57:29 +00002269
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002270int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002271{
2272 struct abis_om_hdr *oh;
2273 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002274 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002275
2276 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2277 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2278 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2279 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2280
2281 return abis_nm_sendmsg(bts, msg);
2282}
2283
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002284int 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 +02002285{
2286 struct abis_om_hdr *oh;
2287 struct msgb *msg = nm_msgb_alloc();
2288 struct bs11_date_time aet;
2289
2290 get_bs11_date_time(&aet);
2291 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2292 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2293 bport, 0xff, 0x02);
2294 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2295
2296 return abis_nm_sendmsg(bts, msg);
2297}
2298
Harald Welte5c1e4582009-02-15 11:57:29 +00002299/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002300static const char ipaccess_magic[] = "com.ipaccess";
2301
Harald Welte677c21f2009-02-17 13:22:23 +00002302
2303static int abis_nm_rx_ipacc(struct msgb *msg)
2304{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002305 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002306 struct abis_om_hdr *oh = msgb_l2(msg);
2307 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002308 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002309 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002310 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002311 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002312
2313 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002314 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002315 return -EINVAL;
2316 }
2317
Harald Welte193fefc2009-04-30 15:16:27 +00002318 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002319 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002320
Harald Welte15c61722011-05-22 22:45:37 +02002321 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002322
Harald Welte746d6092009-10-19 22:11:11 +02002323 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002324
Harald Welte677c21f2009-02-17 13:22:23 +00002325 switch (foh->msg_type) {
2326 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002327 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002328 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2329 memcpy(&addr,
2330 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2331
2332 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2333 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002334 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002335 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002336 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002337 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002338 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2339 DEBUGPC(DNM, "STREAM=0x%02x ",
2340 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002341 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002342 break;
2343 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002344 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002345 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002346 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002347 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002348 else
2349 DEBUGPC(DNM, "\n");
2350 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002351 case NM_MT_IPACC_SET_NVATTR_ACK:
2352 DEBUGPC(DNM, "SET NVATTR ACK\n");
2353 /* FIXME: decode and show the actual attributes */
2354 break;
2355 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002356 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002357 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002358 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002359 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002360 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002361 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002362 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002363 case NM_MT_IPACC_GET_NVATTR_ACK:
2364 DEBUGPC(DNM, "GET NVATTR ACK\n");
2365 /* FIXME: decode and show the actual attributes */
2366 break;
2367 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002368 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002369 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002370 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002371 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002372 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002373 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002374 break;
Harald Welte15c44172009-10-08 20:15:24 +02002375 case NM_MT_IPACC_SET_ATTR_ACK:
2376 DEBUGPC(DNM, "SET ATTR ACK\n");
2377 break;
2378 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002379 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002380 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002381 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002382 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002383 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002384 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002385 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002386 default:
2387 DEBUGPC(DNM, "unknown\n");
2388 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002389 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002390
2391 /* signal handling */
2392 switch (foh->msg_type) {
2393 case NM_MT_IPACC_RSL_CONNECT_NACK:
2394 case NM_MT_IPACC_SET_NVATTR_NACK:
2395 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002396 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 +01002397 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002398 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002399 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002400 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002401 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 +01002402 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002403 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002404 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002405 default:
2406 break;
2407 }
2408
Harald Welte677c21f2009-02-17 13:22:23 +00002409 return 0;
2410}
2411
Harald Welte193fefc2009-04-30 15:16:27 +00002412/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002413int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2414 uint8_t obj_class, uint8_t bts_nr,
2415 uint8_t trx_nr, uint8_t ts_nr,
2416 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002417{
2418 struct msgb *msg = nm_msgb_alloc();
2419 struct abis_om_hdr *oh;
2420 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002421 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002422
2423 /* construct the 12.21 OM header, observe the erroneous length */
2424 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2425 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2426 oh->mdisc = ABIS_OM_MDISC_MANUF;
2427
2428 /* add the ip.access magic */
2429 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2430 *data++ = sizeof(ipaccess_magic);
2431 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2432
2433 /* fill the 12.21 FOM header */
2434 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2435 foh->msg_type = msg_type;
2436 foh->obj_class = obj_class;
2437 foh->obj_inst.bts_nr = bts_nr;
2438 foh->obj_inst.trx_nr = trx_nr;
2439 foh->obj_inst.ts_nr = ts_nr;
2440
2441 if (attr && attr_len) {
2442 data = msgb_put(msg, attr_len);
2443 memcpy(data, attr, attr_len);
2444 }
2445
2446 return abis_nm_sendmsg(bts, msg);
2447}
Harald Welte677c21f2009-02-17 13:22:23 +00002448
Harald Welte193fefc2009-04-30 15:16:27 +00002449/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002450int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002451 int attr_len)
2452{
Harald Welte2ef156d2010-01-07 20:39:42 +01002453 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2454 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002455 attr_len);
2456}
2457
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002458int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002459 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002460{
2461 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002462 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002463 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2464 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2465
2466 int attr_len = sizeof(attr);
2467
2468 ia.s_addr = htonl(ip);
2469 attr[1] = stream;
2470 attr[3] = port >> 8;
2471 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002472 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002473
2474 /* if ip == 0, we use the default IP */
2475 if (ip == 0)
2476 attr_len -= 5;
2477
2478 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002479 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002480
2481 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2482 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2483 trx->nr, 0xff, attr, attr_len);
2484}
2485
Harald Welte193fefc2009-04-30 15:16:27 +00002486/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002487int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002488{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002489 struct abis_om_hdr *oh;
2490 struct msgb *msg = nm_msgb_alloc();
2491
2492 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2493 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2494 trx->bts->nr, trx->nr, 0xff);
2495
2496 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002497}
Harald Weltedaef5212009-10-24 10:20:41 +02002498
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002499int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2500 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2501 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002502{
2503 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2504 obj_class, bts_nr, trx_nr, ts_nr,
2505 attr, attr_len);
2506}
Harald Welte0f255852009-11-12 14:48:42 +01002507
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002508void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002509{
2510 /* we simply reuse the GSM48 function and overwrite the RAC
2511 * with the Cell ID */
2512 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002513 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002514}
2515
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002516void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2517{
2518 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2519
Harald Welted64c0bc2011-05-30 12:07:53 +02002520 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002521 if (!trx->bts || !trx->bts->oml_link)
2522 return;
2523
2524 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2525 trx->bts->bts_nr, trx->nr, 0xff,
2526 new_state);
2527}
2528
Harald Welte92b1fe42010-03-25 11:45:30 +08002529static const struct value_string ipacc_testres_names[] = {
2530 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2531 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2532 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2533 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2534 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2535 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002536};
2537
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002538const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002539{
Harald Welte92b1fe42010-03-25 11:45:30 +08002540 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002541}
2542
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002543void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002544{
2545 cid->mcc = (buf[0] & 0xf) * 100;
2546 cid->mcc += (buf[0] >> 4) * 10;
2547 cid->mcc += (buf[1] & 0xf) * 1;
2548
2549 if (buf[1] >> 4 == 0xf) {
2550 cid->mnc = (buf[2] & 0xf) * 10;
2551 cid->mnc += (buf[2] >> 4) * 1;
2552 } else {
2553 cid->mnc = (buf[2] & 0xf) * 100;
2554 cid->mnc += (buf[2] >> 4) * 10;
2555 cid->mnc += (buf[1] >> 4) * 1;
2556 }
2557
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002558 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2559 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002560}
2561
Harald Welte0f255852009-11-12 14:48:42 +01002562/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002563int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002564{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002565 uint8_t *cur = buf;
2566 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01002567
Harald Welteaf109b92010-07-22 18:14:36 +02002568 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002569
2570 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2571 return -EINVAL;
2572 cur++;
2573
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002574 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002575 cur += 2;
2576
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002577 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002578 cur += 2;
2579
2580 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2581 binf->freq_qual = *cur >> 2;
2582
Harald Welteaf109b92010-07-22 18:14:36 +02002583 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002584 binf->arfcn |= *cur++;
2585
2586 if (binf->info_type & IPAC_BINF_RXLEV)
2587 binf->rx_lev = *cur & 0x3f;
2588 cur++;
2589
2590 if (binf->info_type & IPAC_BINF_RXQUAL)
2591 binf->rx_qual = *cur & 0x7;
2592 cur++;
2593
2594 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002595 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002596 cur += 2;
2597
2598 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002599 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002600 cur += 2;
2601
2602 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002603 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002604 cur += 4;
2605
Harald Weltea780a3d2010-07-30 22:34:42 +02002606#if 0
2607 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002608 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002609#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002610 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002611 cur++;
2612
Harald Welteb40a38f2009-11-13 11:56:05 +01002613 ipac_parse_cgi(&binf->cgi, cur);
2614 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002615
2616 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2617 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2618 cur += sizeof(binf->ba_list_si2);
2619 }
2620
2621 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2622 memcpy(binf->ba_list_si2bis, cur,
2623 sizeof(binf->ba_list_si2bis));
2624 cur += sizeof(binf->ba_list_si2bis);
2625 }
2626
2627 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2628 memcpy(binf->ba_list_si2ter, cur,
2629 sizeof(binf->ba_list_si2ter));
2630 cur += sizeof(binf->ba_list_si2ter);
2631 }
2632
2633 return 0;
2634}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002635
2636void abis_nm_clear_queue(struct gsm_bts *bts)
2637{
2638 struct msgb *msg;
2639
2640 while (!llist_empty(&bts->abis_queue)) {
2641 msg = msgb_dequeue(&bts->abis_queue);
2642 msgb_free(msg);
2643 }
2644
2645 bts->abis_nm_pend = 0;
2646}