blob: a41414a98ff57453bfae07f0d4ab855bb2ab423c [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 Ayuso7abecfc2011-08-17 22:43:54 +020046#include <openbsc/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 Welte52b1f982008-12-23 20:25:15 +0000117/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100118static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000119{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200120 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000121
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100122 /* queue OML messages */
123 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
124 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100125 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100126 } else {
127 msgb_enqueue(&bts->abis_queue, msg);
128 return 0;
129 }
130
131}
132
133int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
134{
135 OBSC_NM_W_ACK_CB(msg) = 1;
136 return abis_nm_queue_msg(bts, msg);
137}
138
139static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
140{
141 OBSC_NM_W_ACK_CB(msg) = 0;
142 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000143}
144
Harald Welte4724f992009-01-18 18:01:49 +0000145static int abis_nm_rcvmsg_sw(struct msgb *mb);
146
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100147int nm_is_running(struct gsm_nm_state *s) {
148 return (s->operational == NM_OPSTATE_ENABLED) && (
149 (s->availability == NM_AVSTATE_OK) ||
150 (s->availability == 0xff)
151 );
152}
153
Harald Weltee0590df2009-02-15 03:34:15 +0000154/* Update the administrative state of a given object in our in-memory data
155 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200156static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
157 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000158{
Harald Welteaeedeb42009-05-01 13:08:14 +0000159 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100160 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000161
Harald Welteaf9b8102011-03-06 21:20:38 +0100162 memset(&nsd, 0, sizeof(nsd));
163
Harald Welte978714d2011-06-06 18:31:20 +0200164 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100165 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100166 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200167 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000168 if (!nm_state)
169 return -1;
170
171 new_state = *nm_state;
172 new_state.administrative = adm_state;
173
Harald Weltef38ca9a2011-03-06 22:11:32 +0100174 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100175 nsd.obj_class = obj_class;
176 nsd.old_state = nm_state;
177 nsd.new_state = &new_state;
178 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200179 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000180
181 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000182
Harald Weltef338a032011-01-14 15:55:42 +0100183 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000184}
185
Harald Welte97ed1e72009-02-06 13:38:02 +0000186static int abis_nm_rx_statechg_rep(struct msgb *mb)
187{
Harald Weltee0590df2009-02-15 03:34:15 +0000188 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000189 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200190 struct e1inp_sign_link *sign_link = mb->dst;
191 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000192 struct tlv_parsed tp;
193 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000194
Harald Welte23897662009-05-01 14:52:51 +0000195 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000196
Harald Welte8b697c72009-06-05 19:18:45 +0000197 memset(&new_state, 0, sizeof(new_state));
198
Harald Welte978714d2011-06-06 18:31:20 +0200199 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000200 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100201 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000202 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000203 }
Harald Weltee0590df2009-02-15 03:34:15 +0000204
205 new_state = *nm_state;
206
Harald Welte39315c42010-01-10 18:01:52 +0100207 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000208 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
209 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200210 DEBUGPC(DNM, "OP_STATE=%s ",
211 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000212 }
213 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000214 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
215 new_state.availability = 0xff;
216 else
217 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200218 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
219 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000220 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100221 } else
222 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000223 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
224 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200225 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200226 get_value_string(abis_nm_adm_state_names,
227 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000228 }
229 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000230
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100231 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
232 new_state.operational != nm_state->operational ||
233 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000234 /* Update the operational state of a given object in our in-memory data
235 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100236 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200237 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100238 nsd.obj_class = foh->obj_class;
239 nsd.old_state = nm_state;
240 nsd.new_state = &new_state;
241 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100242 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200243 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100244 nm_state->operational = new_state.operational;
245 nm_state->availability = new_state.availability;
246 if (nm_state->administrative == 0)
247 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000248 }
249#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000250 if (op_state == 1) {
251 /* try to enable objects that are disabled */
252 abis_nm_opstart(bts, foh->obj_class,
253 foh->obj_inst.bts_nr,
254 foh->obj_inst.trx_nr,
255 foh->obj_inst.ts_nr);
256 }
Harald Weltee0590df2009-02-15 03:34:15 +0000257#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000258 return 0;
259}
260
Harald Welte0db97b22009-05-01 17:22:47 +0000261static int rx_fail_evt_rep(struct msgb *mb)
262{
263 struct abis_om_hdr *oh = msgb_l2(mb);
264 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200265 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000266 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100267 const uint8_t *p_val;
268 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000269
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200270 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000271
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200272 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000273
274 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200275 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
276 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000277 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200278 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
279 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100280 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
281 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200282 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 +0100283 }
284 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
285 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
286 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
287 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200288 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100289 talloc_free(p_text);
290 }
291 }
Harald Welte0db97b22009-05-01 17:22:47 +0000292
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200293 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000294
295 return 0;
296}
297
Harald Welte97ed1e72009-02-06 13:38:02 +0000298static int abis_nm_rcvmsg_report(struct msgb *mb)
299{
300 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200301 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000302
Harald Welte15c61722011-05-22 22:45:37 +0200303 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000304
Harald Welte97ed1e72009-02-06 13:38:02 +0000305 //nmh->cfg->report_cb(mb, foh);
306
307 switch (mt) {
308 case NM_MT_STATECHG_EVENT_REP:
309 return abis_nm_rx_statechg_rep(mb);
310 break;
Harald Welte34a99682009-02-13 02:41:40 +0000311 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000312 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200313 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000314 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000315 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000316 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200317 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000318 break;
Harald Weltec7310382009-08-08 00:02:36 +0200319 case NM_MT_TEST_REP:
320 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200321 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200322 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000323 default:
Harald Welte23897662009-05-01 14:52:51 +0000324 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000325 break;
326
Harald Welte97ed1e72009-02-06 13:38:02 +0000327 };
328
Harald Welte97ed1e72009-02-06 13:38:02 +0000329 return 0;
330}
331
Harald Welte34a99682009-02-13 02:41:40 +0000332/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200333static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
334 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000335{
336 struct abis_om_hdr *oh;
337 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200338 uint8_t len = swdesc_len;
339 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000340
341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
342 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
343
344 trailer = msgb_put(msg, swdesc_len);
345 memcpy(trailer, sw_desc, swdesc_len);
346
347 return abis_nm_sendmsg(bts, msg);
348}
349
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200350static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100351{
352 static const struct tlv_definition sw_descr_def = {
353 .def = {
354 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
355 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
356 },
357 };
358
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200359 uint8_t tag;
360 uint16_t tag_len;
361 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100362 int ofs = 0, len;
363
364 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
365 * nested nature and the fact you have to assume it contains only two sub
366 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
367
368 if (sw_descr[0] != NM_ATT_SW_DESCR) {
369 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
370 return -1;
371 }
372 ofs += 1;
373
374 len = tlv_parse_one(&tag, &tag_len, &val,
375 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
376 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
377 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
378 return -2;
379 }
380 ofs += len;
381
382 len = tlv_parse_one(&tag, &tag_len, &val,
383 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
384 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
385 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
386 return -3;
387 }
388 ofs += len;
389
390 return ofs;
391}
392
Harald Welte34a99682009-02-13 02:41:40 +0000393static int abis_nm_rx_sw_act_req(struct msgb *mb)
394{
395 struct abis_om_hdr *oh = msgb_l2(mb);
396 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200397 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200398 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200399 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100400 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000401
Harald Welte15c61722011-05-22 22:45:37 +0200402 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200403
404 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000405
Harald Welte97a282b2010-03-14 15:37:43 +0800406 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000407
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200408 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000409 foh->obj_inst.bts_nr,
410 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800411 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000412 foh->data, oh->length-sizeof(*foh));
413
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200414 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200415 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
416 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
417 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
418 DEBUGP(DNM, "SW config not found! Can't continue.\n");
419 return -EINVAL;
420 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200421 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200422 }
423
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100424 /* Use the first SW_DESCR present in SW config */
425 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
426 if (sw_descr_len < 0)
427 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200428
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200429 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000430 foh->obj_inst.bts_nr,
431 foh->obj_inst.trx_nr,
432 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100433 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000434}
435
Harald Weltee0590df2009-02-15 03:34:15 +0000436/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
437static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
438{
439 struct abis_om_hdr *oh = msgb_l2(mb);
440 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200441 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000442 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200443 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000444
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200445 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000446 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
447 return -EINVAL;
448
449 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
450
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200451 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000452}
453
Harald Welteee670472009-02-22 21:58:49 +0000454static int abis_nm_rx_lmt_event(struct msgb *mb)
455{
456 struct abis_om_hdr *oh = msgb_l2(mb);
457 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200458 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000459 struct tlv_parsed tp;
460
461 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200462 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000463 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
464 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200465 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000466 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
467 }
468 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
469 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200470 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000471 DEBUGPC(DNM, "Level=%u ", level);
472 }
473 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
474 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
475 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
476 DEBUGPC(DNM, "Username=%s ", name);
477 }
478 DEBUGPC(DNM, "\n");
479 /* FIXME: parse LMT LOGON TIME */
480 return 0;
481}
482
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100483static void abis_nm_queue_send_next(struct gsm_bts *bts)
484{
485 int wait = 0;
486 struct msgb *msg;
487 /* the queue is empty */
488 while (!llist_empty(&bts->abis_queue)) {
489 msg = msgb_dequeue(&bts->abis_queue);
490 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100491 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100492
493 if (wait)
494 break;
495 }
496
497 bts->abis_nm_pend = wait;
498}
499
Harald Welte52b1f982008-12-23 20:25:15 +0000500/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000501static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000502{
Harald Welte6c96ba52009-05-01 13:03:40 +0000503 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000504 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200505 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200506 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100507 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000508
509 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000510 if (is_report(mt))
511 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000512
Harald Welte15c61722011-05-22 22:45:37 +0200513 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000514 return abis_nm_rcvmsg_sw(mb);
515
Harald Welte15c61722011-05-22 22:45:37 +0200516 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800517 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000518 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200519
Harald Welte15c61722011-05-22 22:45:37 +0200520 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200521
Harald Welte15c61722011-05-22 22:45:37 +0200522 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000523
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200524 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000525 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200526 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200527 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000528 else
529 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200530
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800531 nack_data.msg = mb;
532 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200533 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200534 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200535 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000536 }
Harald Weltead384642008-12-26 10:20:07 +0000537#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000538 /* check if last message is to be acked */
539 if (is_ack_nack(nmh->last_msgtype)) {
540 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100541 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000542 /* we got our ACK, continue sending the next msg */
543 } else if (mt == MT_NACK(nmh->last_msgtype)) {
544 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100545 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000546 /* FIXME: somehow signal this to the caller */
547 } else {
548 /* really strange things happen */
549 return -EINVAL;
550 }
551 }
Harald Weltead384642008-12-26 10:20:07 +0000552#endif
553
Harald Welte97ed1e72009-02-06 13:38:02 +0000554 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000555 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100556 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000557 break;
Harald Welte34a99682009-02-13 02:41:40 +0000558 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100559 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000560 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000561 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100562 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000563 break;
Harald Welte1989c082009-08-06 17:58:31 +0200564 case NM_MT_CONN_MDROP_LINK_ACK:
565 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
566 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100567 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200568 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100569 break;
570 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200571 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100572 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100573 case NM_MT_SET_BTS_ATTR_ACK:
574 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200575 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
576 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Weltefd355a32011-03-04 13:41:31 +0100577 }
578 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000579 }
580
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200581 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100582 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000583}
584
Harald Welte677c21f2009-02-17 13:22:23 +0000585static int abis_nm_rx_ipacc(struct msgb *mb);
586
587static int abis_nm_rcvmsg_manuf(struct msgb *mb)
588{
589 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200590 struct e1inp_sign_link *sign_link = mb->dst;
591 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000592
593 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100594 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000595 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200596 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000597 break;
598 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100599 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
600 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000601 rc = 0;
602 break;
603 }
604
605 return rc;
606}
607
Harald Welte52b1f982008-12-23 20:25:15 +0000608/* High-Level API */
609/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000610int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000611{
Harald Welte52b1f982008-12-23 20:25:15 +0000612 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000613 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000614
615 /* Various consistency checks */
616 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100617 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000618 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200619 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
620 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000621 }
622 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100623 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000624 oh->sequence);
625 return -EINVAL;
626 }
Harald Welte702d8702008-12-26 20:25:35 +0000627#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200628 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000629 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000630 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100631 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000632 oh->length + sizeof(*oh), l2_len);
633 return -EINVAL;
634 }
Harald Welte702d8702008-12-26 20:25:35 +0000635 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100636 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 +0000637#endif
Harald Weltead384642008-12-26 10:20:07 +0000638 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000639
640 switch (oh->mdisc) {
641 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000642 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000643 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000644 case ABIS_OM_MDISC_MANUF:
645 rc = abis_nm_rcvmsg_manuf(msg);
646 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000647 case ABIS_OM_MDISC_MMI:
648 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100649 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000650 oh->mdisc);
651 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000652 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100653 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000654 oh->mdisc);
655 return -EINVAL;
656 }
657
Harald Weltead384642008-12-26 10:20:07 +0000658 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000659 return rc;
660}
661
662#if 0
663/* initialized all resources */
664struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
665{
666 struct abis_nm_h *nmh;
667
668 nmh = malloc(sizeof(*nmh));
669 if (!nmh)
670 return NULL;
671
672 nmh->cfg = cfg;
673
674 return nmh;
675}
676
677/* free all resources */
678void abis_nm_fini(struct abis_nm_h *nmh)
679{
680 free(nmh);
681}
682#endif
683
684/* Here we are trying to define a high-level API that can be used by
685 * the actual BSC implementation. However, the architecture is currently
686 * still under design. Ideally the calls to this API would be synchronous,
687 * while the underlying stack behind the APi runs in a traditional select
688 * based state machine.
689 */
690
Harald Welte4724f992009-01-18 18:01:49 +0000691/* 6.2 Software Load: */
692enum sw_state {
693 SW_STATE_NONE,
694 SW_STATE_WAIT_INITACK,
695 SW_STATE_WAIT_SEGACK,
696 SW_STATE_WAIT_ENDACK,
697 SW_STATE_WAIT_ACTACK,
698 SW_STATE_ERROR,
699};
Harald Welte52b1f982008-12-23 20:25:15 +0000700
Harald Welte52b1f982008-12-23 20:25:15 +0000701struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000702 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800703 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000704 gsm_cbfn *cbfn;
705 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000706 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000707
Harald Welte52b1f982008-12-23 20:25:15 +0000708 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200709 uint8_t obj_class;
710 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000711
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200712 uint8_t file_id[255];
713 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000714
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200715 uint8_t file_version[255];
716 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000717
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200718 uint8_t window_size;
719 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000720
721 int fd;
722 FILE *stream;
723 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000724 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000725};
726
Harald Welte4724f992009-01-18 18:01:49 +0000727static struct abis_nm_sw g_sw;
728
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100729static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
730{
731 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
732 msgb_v_put(msg, NM_ATT_SW_DESCR);
733 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
734 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
735 sw->file_version);
736 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
737 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
738 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
739 sw->file_version);
740 } else {
741 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
742 }
743}
744
Harald Welte4724f992009-01-18 18:01:49 +0000745/* 6.2.1 / 8.3.1: Load Data Initiate */
746static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000747{
Harald Welte4724f992009-01-18 18:01:49 +0000748 struct abis_om_hdr *oh;
749 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200750 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000751
752 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
753 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
754 sw->obj_instance[0], sw->obj_instance[1],
755 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100756
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100757 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000758 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
759
760 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000761}
762
Harald Welte1602ade2009-01-29 21:12:39 +0000763static int is_last_line(FILE *stream)
764{
765 char next_seg_buf[256];
766 long pos;
767
768 /* check if we're sending the last line */
769 pos = ftell(stream);
770 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
771 fseek(stream, pos, SEEK_SET);
772 return 1;
773 }
774
775 fseek(stream, pos, SEEK_SET);
776 return 0;
777}
778
Harald Welte4724f992009-01-18 18:01:49 +0000779/* 6.2.2 / 8.3.2 Load Data Segment */
780static int sw_load_segment(struct abis_nm_sw *sw)
781{
782 struct abis_om_hdr *oh;
783 struct msgb *msg = nm_msgb_alloc();
784 char seg_buf[256];
785 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000786 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200787 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000788
789 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000790
791 switch (sw->bts->type) {
792 case GSM_BTS_TYPE_BS11:
793 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
794 perror("fgets reading segment");
795 return -EINVAL;
796 }
797 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000798
799 /* check if we're sending the last line */
800 sw->last_seg = is_last_line(sw->stream);
801 if (sw->last_seg)
802 seg_buf[1] = 0;
803 else
804 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000805
806 len = strlen(line_buf) + 2;
807 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200808 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000809 /* BS11 wants CR + LF in excess of the TLV length !?! */
810 tlv[1] -= 2;
811
812 /* we only now know the exact length for the OM hdr */
813 len = strlen(line_buf)+2;
814 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100815 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200816 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100817 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
818 if (len < 0) {
819 perror("read failed");
820 return -EINVAL;
821 }
822
823 if (len != IPACC_SEGMENT_SIZE)
824 sw->last_seg = 1;
825
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100826 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200827 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100828 len += 3;
829 break;
830 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000831 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100832 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000833 /* FIXME: Other BTS types */
834 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000835 }
Harald Welte4724f992009-01-18 18:01:49 +0000836
Harald Welte4724f992009-01-18 18:01:49 +0000837 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
838 sw->obj_instance[0], sw->obj_instance[1],
839 sw->obj_instance[2]);
840
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100841 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000842}
843
844/* 6.2.4 / 8.3.4 Load Data End */
845static int sw_load_end(struct abis_nm_sw *sw)
846{
847 struct abis_om_hdr *oh;
848 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200849 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000850
851 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
852 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
853 sw->obj_instance[0], sw->obj_instance[1],
854 sw->obj_instance[2]);
855
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100856 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000857 return abis_nm_sendmsg(sw->bts, msg);
858}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000859
Harald Welte52b1f982008-12-23 20:25:15 +0000860/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000861static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000862{
Harald Welte4724f992009-01-18 18:01:49 +0000863 struct abis_om_hdr *oh;
864 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200865 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000866
Harald Welte4724f992009-01-18 18:01:49 +0000867 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
868 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
869 sw->obj_instance[0], sw->obj_instance[1],
870 sw->obj_instance[2]);
871
872 /* FIXME: this is BS11 specific format */
873 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
874 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
875 sw->file_version);
876
877 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000878}
Harald Welte4724f992009-01-18 18:01:49 +0000879
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100880struct sdp_firmware {
881 char magic[4];
882 char more_magic[4];
883 unsigned int header_length;
884 unsigned int file_length;
885} __attribute__ ((packed));
886
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100887static int parse_sdp_header(struct abis_nm_sw *sw)
888{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100889 struct sdp_firmware firmware_header;
890 int rc;
891 struct stat stat;
892
893 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
894 if (rc != sizeof(firmware_header)) {
895 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
896 return -1;
897 }
898
899 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
900 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
901 return -1;
902 }
903
904 if (firmware_header.more_magic[0] != 0x10 ||
905 firmware_header.more_magic[1] != 0x02 ||
906 firmware_header.more_magic[2] != 0x00 ||
907 firmware_header.more_magic[3] != 0x00) {
908 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
909 return -1;
910 }
911
912
913 if (fstat(sw->fd, &stat) == -1) {
914 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
915 return -1;
916 }
917
918 if (ntohl(firmware_header.file_length) != stat.st_size) {
919 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
920 return -1;
921 }
922
923 /* go back to the start as we checked the whole filesize.. */
924 lseek(sw->fd, 0l, SEEK_SET);
925 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
926 "There might be checksums in the file that are not\n"
927 "verified and incomplete firmware might be flashed.\n"
928 "There is absolutely no WARRANTY that flashing will\n"
929 "work.\n");
930 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100931}
932
Harald Welte4724f992009-01-18 18:01:49 +0000933static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
934{
935 char file_id[12+1];
936 char file_version[80+1];
937 int rc;
938
939 sw->fd = open(fname, O_RDONLY);
940 if (sw->fd < 0)
941 return sw->fd;
942
943 switch (sw->bts->type) {
944 case GSM_BTS_TYPE_BS11:
945 sw->stream = fdopen(sw->fd, "r");
946 if (!sw->stream) {
947 perror("fdopen");
948 return -1;
949 }
950 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200951 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +0000952 file_id, file_version);
953 if (rc != 2) {
954 perror("parsing header line of software file");
955 return -1;
956 }
957 strcpy((char *)sw->file_id, file_id);
958 sw->file_id_len = strlen(file_id);
959 strcpy((char *)sw->file_version, file_version);
960 sw->file_version_len = strlen(file_version);
961 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +0000962 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +0000963 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100964 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100965 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100966 rc = parse_sdp_header(sw);
967 if (rc < 0) {
968 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
969 return -1;
970 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100971
972 strcpy((char *)sw->file_id, "id");
973 sw->file_id_len = 3;
974 strcpy((char *)sw->file_version, "version");
975 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100976 break;
Harald Welte4724f992009-01-18 18:01:49 +0000977 default:
978 /* We don't know how to treat them yet */
979 close(sw->fd);
980 return -EINVAL;
981 }
982
983 return 0;
984}
985
986static void sw_close_file(struct abis_nm_sw *sw)
987{
988 switch (sw->bts->type) {
989 case GSM_BTS_TYPE_BS11:
990 fclose(sw->stream);
991 break;
992 default:
993 close(sw->fd);
994 break;
995 }
996}
997
998/* Fill the window */
999static int sw_fill_window(struct abis_nm_sw *sw)
1000{
1001 int rc;
1002
1003 while (sw->seg_in_window < sw->window_size) {
1004 rc = sw_load_segment(sw);
1005 if (rc < 0)
1006 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001007 if (sw->last_seg)
1008 break;
Harald Welte4724f992009-01-18 18:01:49 +00001009 }
1010 return 0;
1011}
1012
1013/* callback function from abis_nm_rcvmsg() handler */
1014static int abis_nm_rcvmsg_sw(struct msgb *mb)
1015{
1016 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001017 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001018 int rc = -1;
1019 struct abis_nm_sw *sw = &g_sw;
1020 enum sw_state old_state = sw->state;
1021
Harald Welte3ffd1372009-02-01 22:15:49 +00001022 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001023
1024 switch (sw->state) {
1025 case SW_STATE_WAIT_INITACK:
1026 switch (foh->msg_type) {
1027 case NM_MT_LOAD_INIT_ACK:
1028 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001029 if (sw->cbfn)
1030 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1031 NM_MT_LOAD_INIT_ACK, mb,
1032 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001033 rc = sw_fill_window(sw);
1034 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001035 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001036 break;
1037 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001038 if (sw->forced) {
1039 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1040 "Init NACK\n");
1041 if (sw->cbfn)
1042 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1043 NM_MT_LOAD_INIT_ACK, mb,
1044 sw->cb_data, NULL);
1045 rc = sw_fill_window(sw);
1046 sw->state = SW_STATE_WAIT_SEGACK;
1047 } else {
1048 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001049 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001050 if (sw->cbfn)
1051 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1052 NM_MT_LOAD_INIT_NACK, mb,
1053 sw->cb_data, NULL);
1054 sw->state = SW_STATE_ERROR;
1055 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001056 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001057 break;
1058 }
1059 break;
1060 case SW_STATE_WAIT_SEGACK:
1061 switch (foh->msg_type) {
1062 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001063 if (sw->cbfn)
1064 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1065 NM_MT_LOAD_SEG_ACK, mb,
1066 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001067 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001068 if (!sw->last_seg) {
1069 /* fill window with more segments */
1070 rc = sw_fill_window(sw);
1071 sw->state = SW_STATE_WAIT_SEGACK;
1072 } else {
1073 /* end the transfer */
1074 sw->state = SW_STATE_WAIT_ENDACK;
1075 rc = sw_load_end(sw);
1076 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001077 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001078 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001079 case NM_MT_LOAD_ABORT:
1080 if (sw->cbfn)
1081 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1082 NM_MT_LOAD_ABORT, mb,
1083 sw->cb_data, NULL);
1084 break;
Harald Welte4724f992009-01-18 18:01:49 +00001085 }
1086 break;
1087 case SW_STATE_WAIT_ENDACK:
1088 switch (foh->msg_type) {
1089 case NM_MT_LOAD_END_ACK:
1090 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001091 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1092 sw->bts->nr);
1093 sw->state = SW_STATE_NONE;
1094 if (sw->cbfn)
1095 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1096 NM_MT_LOAD_END_ACK, mb,
1097 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001098 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001099 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001100 break;
1101 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001102 if (sw->forced) {
1103 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1104 "End NACK\n");
1105 sw->state = SW_STATE_NONE;
1106 if (sw->cbfn)
1107 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1108 NM_MT_LOAD_END_ACK, mb,
1109 sw->cb_data, NULL);
1110 } else {
1111 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001112 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001113 sw->state = SW_STATE_ERROR;
1114 if (sw->cbfn)
1115 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1116 NM_MT_LOAD_END_NACK, mb,
1117 sw->cb_data, NULL);
1118 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001119 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001120 break;
1121 }
1122 case SW_STATE_WAIT_ACTACK:
1123 switch (foh->msg_type) {
1124 case NM_MT_ACTIVATE_SW_ACK:
1125 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001126 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001127 sw->state = SW_STATE_NONE;
1128 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001129 if (sw->cbfn)
1130 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1131 NM_MT_ACTIVATE_SW_ACK, mb,
1132 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001133 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001134 break;
1135 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001136 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001137 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001138 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001139 if (sw->cbfn)
1140 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1141 NM_MT_ACTIVATE_SW_NACK, mb,
1142 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001143 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001144 break;
1145 }
1146 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001147 switch (foh->msg_type) {
1148 case NM_MT_ACTIVATE_SW_ACK:
1149 rc = 0;
1150 break;
1151 }
1152 break;
Harald Welte4724f992009-01-18 18:01:49 +00001153 case SW_STATE_ERROR:
1154 break;
1155 }
1156
1157 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001158 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001159 foh->msg_type, old_state, sw->state);
1160
1161 return rc;
1162}
1163
1164/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001165int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001166 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001167 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001168{
1169 struct abis_nm_sw *sw = &g_sw;
1170 int rc;
1171
Harald Welte5e4d1b32009-02-01 13:36:56 +00001172 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1173 bts->nr, fname);
1174
Harald Welte4724f992009-01-18 18:01:49 +00001175 if (sw->state != SW_STATE_NONE)
1176 return -EBUSY;
1177
1178 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001179 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001180
1181 switch (bts->type) {
1182 case GSM_BTS_TYPE_BS11:
1183 sw->obj_class = NM_OC_SITE_MANAGER;
1184 sw->obj_instance[0] = 0xff;
1185 sw->obj_instance[1] = 0xff;
1186 sw->obj_instance[2] = 0xff;
1187 break;
1188 case GSM_BTS_TYPE_NANOBTS:
1189 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001190 sw->obj_instance[0] = sw->bts->nr;
1191 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001192 sw->obj_instance[2] = 0xff;
1193 break;
1194 case GSM_BTS_TYPE_UNKNOWN:
1195 default:
1196 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1197 return -1;
1198 break;
1199 }
Harald Welte4724f992009-01-18 18:01:49 +00001200 sw->window_size = win_size;
1201 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001202 sw->cbfn = cbfn;
1203 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001204 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001205
1206 rc = sw_open_file(sw, fname);
1207 if (rc < 0) {
1208 sw->state = SW_STATE_NONE;
1209 return rc;
1210 }
1211
1212 return sw_load_init(sw);
1213}
Harald Welte52b1f982008-12-23 20:25:15 +00001214
Harald Welte1602ade2009-01-29 21:12:39 +00001215int abis_nm_software_load_status(struct gsm_bts *bts)
1216{
1217 struct abis_nm_sw *sw = &g_sw;
1218 struct stat st;
1219 int rc, percent;
1220
1221 rc = fstat(sw->fd, &st);
1222 if (rc < 0) {
1223 perror("ERROR during stat");
1224 return rc;
1225 }
1226
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001227 if (sw->stream)
1228 percent = (ftell(sw->stream) * 100) / st.st_size;
1229 else
1230 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001231 return percent;
1232}
1233
Harald Welte5e4d1b32009-02-01 13:36:56 +00001234/* Activate the specified software into the BTS */
1235int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1236 gsm_cbfn *cbfn, void *cb_data)
1237{
1238 struct abis_nm_sw *sw = &g_sw;
1239 int rc;
1240
1241 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1242 bts->nr, fname);
1243
1244 if (sw->state != SW_STATE_NONE)
1245 return -EBUSY;
1246
1247 sw->bts = bts;
1248 sw->obj_class = NM_OC_SITE_MANAGER;
1249 sw->obj_instance[0] = 0xff;
1250 sw->obj_instance[1] = 0xff;
1251 sw->obj_instance[2] = 0xff;
1252 sw->state = SW_STATE_WAIT_ACTACK;
1253 sw->cbfn = cbfn;
1254 sw->cb_data = cb_data;
1255
1256 /* Open the file in order to fill some sw struct members */
1257 rc = sw_open_file(sw, fname);
1258 if (rc < 0) {
1259 sw->state = SW_STATE_NONE;
1260 return rc;
1261 }
1262 sw_close_file(sw);
1263
1264 return sw_activate(sw);
1265}
1266
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001267static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1268 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001269{
Harald Welteadaf08b2009-01-18 11:08:10 +00001270 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001271 ch->bts_port = bts_port;
1272 ch->timeslot = ts_nr;
1273 ch->subslot = subslot_nr;
1274}
1275
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001276int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1277 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1278 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001279{
1280 struct abis_om_hdr *oh;
1281 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001282 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001283 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001284
1285 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1286 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1287 bts->bts_nr, trx_nr, 0xff);
1288
Harald Welte8470bf22008-12-25 23:28:35 +00001289 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001290
1291 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1292 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1293
1294 return abis_nm_sendmsg(bts, msg);
1295}
1296
1297/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1298int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001299 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001300{
Harald Welte8470bf22008-12-25 23:28:35 +00001301 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001302 struct abis_om_hdr *oh;
1303 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001304 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001305
1306 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001307 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001308 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1309
1310 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1311 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1312
1313 return abis_nm_sendmsg(bts, msg);
1314}
1315
1316#if 0
1317int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1318 struct abis_nm_abis_channel *chan)
1319{
1320}
1321#endif
1322
1323int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001324 uint8_t e1_port, uint8_t e1_timeslot,
1325 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001326{
1327 struct gsm_bts *bts = ts->trx->bts;
1328 struct abis_om_hdr *oh;
1329 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001330 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001331
1332 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1333 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001334 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001335
1336 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1337 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1338
Harald Weltef325eb42009-02-19 17:07:39 +00001339 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1340 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001341 e1_port, e1_timeslot, e1_subslot);
1342
Harald Welte52b1f982008-12-23 20:25:15 +00001343 return abis_nm_sendmsg(bts, msg);
1344}
1345
1346#if 0
1347int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1348 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001349 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001350{
1351}
1352#endif
1353
Harald Welte22af0db2009-02-14 15:41:08 +00001354/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001355int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001356{
1357 struct abis_om_hdr *oh;
1358 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001359 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001360
1361 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1362
1363 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001364 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 +00001365 cur = msgb_put(msg, attr_len);
1366 memcpy(cur, attr, attr_len);
1367
1368 return abis_nm_sendmsg(bts, msg);
1369}
1370
1371/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001372int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001373{
1374 struct abis_om_hdr *oh;
1375 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001376 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001377
1378 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1379
1380 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1381 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001382 trx->bts->bts_nr, trx->nr, 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(trx->bts, msg);
1387}
1388
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001389static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001390{
1391 int i;
1392
1393 /* As it turns out, the BS-11 has some very peculiar restrictions
1394 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301395 switch (ts->trx->bts->type) {
1396 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001397 switch (chan_comb) {
1398 case NM_CHANC_TCHHalf:
1399 case NM_CHANC_TCHHalf2:
1400 /* not supported */
1401 return -EINVAL;
1402 case NM_CHANC_SDCCH:
1403 /* only one SDCCH/8 per TRX */
1404 for (i = 0; i < TRX_NR_TS; i++) {
1405 if (i == ts->nr)
1406 continue;
1407 if (ts->trx->ts[i].nm_chan_comb ==
1408 NM_CHANC_SDCCH)
1409 return -EINVAL;
1410 }
1411 /* not allowed for TS0 of BCCH-TRX */
1412 if (ts->trx == ts->trx->bts->c0 &&
1413 ts->nr == 0)
1414 return -EINVAL;
1415 /* not on the same TRX that has a BCCH+SDCCH4
1416 * combination */
1417 if (ts->trx == ts->trx->bts->c0 &&
1418 (ts->trx->ts[0].nm_chan_comb == 5 ||
1419 ts->trx->ts[0].nm_chan_comb == 8))
1420 return -EINVAL;
1421 break;
1422 case NM_CHANC_mainBCCH:
1423 case NM_CHANC_BCCHComb:
1424 /* allowed only for TS0 of C0 */
1425 if (ts->trx != ts->trx->bts->c0 ||
1426 ts->nr != 0)
1427 return -EINVAL;
1428 break;
1429 case NM_CHANC_BCCH:
1430 /* allowed only for TS 2/4/6 of C0 */
1431 if (ts->trx != ts->trx->bts->c0)
1432 return -EINVAL;
1433 if (ts->nr != 2 && ts->nr != 4 &&
1434 ts->nr != 6)
1435 return -EINVAL;
1436 break;
1437 case 8: /* this is not like 08.58, but in fact
1438 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1439 /* FIXME: only one CBCH allowed per cell */
1440 break;
1441 }
Harald Welted6575f92009-12-02 02:45:23 +05301442 break;
1443 case GSM_BTS_TYPE_NANOBTS:
1444 switch (ts->nr) {
1445 case 0:
1446 if (ts->trx->nr == 0) {
1447 /* only on TRX0 */
1448 switch (chan_comb) {
1449 case NM_CHANC_BCCH:
1450 case NM_CHANC_mainBCCH:
1451 case NM_CHANC_BCCHComb:
1452 return 0;
1453 break;
1454 default:
1455 return -EINVAL;
1456 }
1457 } else {
1458 switch (chan_comb) {
1459 case NM_CHANC_TCHFull:
1460 case NM_CHANC_TCHHalf:
1461 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1462 return 0;
1463 default:
1464 return -EINVAL;
1465 }
1466 }
1467 break;
1468 case 1:
1469 if (ts->trx->nr == 0) {
1470 switch (chan_comb) {
1471 case NM_CHANC_SDCCH_CBCH:
1472 if (ts->trx->ts[0].nm_chan_comb ==
1473 NM_CHANC_mainBCCH)
1474 return 0;
1475 return -EINVAL;
1476 case NM_CHANC_SDCCH:
1477 case NM_CHANC_TCHFull:
1478 case NM_CHANC_TCHHalf:
1479 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1480 case NM_CHANC_IPAC_TCHFull_PDCH:
1481 return 0;
1482 }
1483 } else {
1484 switch (chan_comb) {
1485 case NM_CHANC_SDCCH:
1486 case NM_CHANC_TCHFull:
1487 case NM_CHANC_TCHHalf:
1488 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1489 return 0;
1490 default:
1491 return -EINVAL;
1492 }
1493 }
1494 break;
1495 case 2:
1496 case 3:
1497 case 4:
1498 case 5:
1499 case 6:
1500 case 7:
1501 switch (chan_comb) {
1502 case NM_CHANC_TCHFull:
1503 case NM_CHANC_TCHHalf:
1504 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1505 return 0;
1506 case NM_CHANC_IPAC_PDCH:
1507 case NM_CHANC_IPAC_TCHFull_PDCH:
1508 if (ts->trx->nr == 0)
1509 return 0;
1510 else
1511 return -EINVAL;
1512 }
1513 break;
1514 }
1515 return -EINVAL;
1516 default:
1517 /* unknown BTS type */
1518 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001519 }
1520 return 0;
1521}
1522
Harald Welte22af0db2009-02-14 15:41:08 +00001523/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001524int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001525{
1526 struct gsm_bts *bts = ts->trx->bts;
1527 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001528 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001529 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001530 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00001531
1532 if (bts->type == GSM_BTS_TYPE_BS11)
1533 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001534
Harald Weltef325eb42009-02-19 17:07:39 +00001535 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001536 if (verify_chan_comb(ts, chan_comb) < 0) {
1537 msgb_free(msg);
1538 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1539 return -EINVAL;
1540 }
1541 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001542
Harald Welte52b1f982008-12-23 20:25:15 +00001543 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001544 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001545 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001546 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001547 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001548 if (ts->hopping.enabled) {
1549 unsigned int i;
1550 uint8_t *len;
1551
Harald Welte6e0cd042009-09-12 13:05:33 +02001552 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1553 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001554
1555 /* build the ARFCN list */
1556 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1557 len = msgb_put(msg, 1);
1558 *len = 0;
1559 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1560 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1561 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001562 /* At least BS-11 wants a TLV16 here */
1563 if (bts->type == GSM_BTS_TYPE_BS11)
1564 *len += 1;
1565 else
1566 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001567 }
1568 }
Harald Weltee0590df2009-02-15 03:34:15 +00001569 }
Harald Welte135a6482011-05-30 12:09:13 +02001570 if (ts->tsc == -1)
1571 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1572 else
1573 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001574 if (bts->type == GSM_BTS_TYPE_BS11)
1575 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001576
1577 return abis_nm_sendmsg(bts, msg);
1578}
1579
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001580int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1581 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001582{
1583 struct abis_om_hdr *oh;
1584 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001585 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1586 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001587
1588 if (nack) {
1589 len += 2;
1590 msgtype = NM_MT_SW_ACT_REQ_NACK;
1591 }
Harald Welte34a99682009-02-13 02:41:40 +00001592
1593 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001594 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1595
Harald Welte34a99682009-02-13 02:41:40 +00001596 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001597 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001598 memcpy(ptr, attr, att_len);
1599 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001600 if (nack)
1601 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001602
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001603 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001604}
1605
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001606int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001607{
Harald Welte8470bf22008-12-25 23:28:35 +00001608 struct msgb *msg = nm_msgb_alloc();
1609 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001610 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001611
1612 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1613 fill_om_hdr(oh, len);
1614 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001615 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001616
1617 return abis_nm_sendmsg(bts, msg);
1618}
1619
1620/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001621static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001622{
1623 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001624 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001625
1626 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001627 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001628 0xff, 0xff, 0xff);
1629
1630 return abis_nm_sendmsg(bts, msg);
1631}
1632
Harald Welte34a99682009-02-13 02:41:40 +00001633/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001634int 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 +00001635{
1636 struct abis_om_hdr *oh;
1637 struct msgb *msg = nm_msgb_alloc();
1638
1639 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1640 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1641
Harald Welte15c61722011-05-22 22:45:37 +02001642 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001643 DEBUGPC(DNM, "Sending OPSTART\n");
1644
Harald Welte34a99682009-02-13 02:41:40 +00001645 return abis_nm_sendmsg(bts, msg);
1646}
1647
1648/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001649int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1650 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001651{
1652 struct abis_om_hdr *oh;
1653 struct msgb *msg = nm_msgb_alloc();
1654
1655 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1656 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1657 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1658
1659 return abis_nm_sendmsg(bts, msg);
1660}
1661
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001662int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1663 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001664{
1665 struct abis_om_hdr *oh;
1666 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001667 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001668
1669 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1670 e1_port0, ts0, e1_port1, ts1);
1671
1672 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1673 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1674 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1675
1676 attr = msgb_put(msg, 3);
1677 attr[0] = NM_ATT_MDROP_LINK;
1678 attr[1] = e1_port0;
1679 attr[2] = ts0;
1680
1681 attr = msgb_put(msg, 3);
1682 attr[0] = NM_ATT_MDROP_NEXT;
1683 attr[1] = e1_port1;
1684 attr[2] = ts1;
1685
1686 return abis_nm_sendmsg(bts, msg);
1687}
Harald Welte34a99682009-02-13 02:41:40 +00001688
Harald Weltec7310382009-08-08 00:02:36 +02001689/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001690int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1691 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1692 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001693{
1694 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001695
Harald Welte15c61722011-05-22 22:45:37 +02001696 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001697
1698 if (!msg)
1699 msg = nm_msgb_alloc();
1700
1701 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1702 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1703 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1704 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001705 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001706
1707 return abis_nm_sendmsg(bts, msg);
1708}
1709
Harald Welte52b1f982008-12-23 20:25:15 +00001710int abis_nm_event_reports(struct gsm_bts *bts, int on)
1711{
1712 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001713 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001714 else
Harald Welte227d4072009-01-03 08:16:25 +00001715 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001716}
1717
Harald Welte47d88ae2009-01-04 12:02:08 +00001718/* Siemens (or BS-11) specific commands */
1719
Harald Welte3ffd1372009-02-01 22:15:49 +00001720int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1721{
1722 if (reconnect == 0)
1723 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1724 else
1725 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1726}
1727
Harald Welteb8427972009-02-05 19:27:17 +00001728int abis_nm_bs11_restart(struct gsm_bts *bts)
1729{
1730 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1731}
1732
1733
Harald Welte268bb402009-02-01 19:11:56 +00001734struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001735 uint16_t year;
1736 uint8_t month;
1737 uint8_t day;
1738 uint8_t hour;
1739 uint8_t min;
1740 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001741} __attribute__((packed));
1742
1743
1744void get_bs11_date_time(struct bs11_date_time *aet)
1745{
1746 time_t t;
1747 struct tm *tm;
1748
1749 t = time(NULL);
1750 tm = localtime(&t);
1751 aet->sec = tm->tm_sec;
1752 aet->min = tm->tm_min;
1753 aet->hour = tm->tm_hour;
1754 aet->day = tm->tm_mday;
1755 aet->month = tm->tm_mon;
1756 aet->year = htons(1900 + tm->tm_year);
1757}
1758
Harald Welte05188ee2009-01-18 11:39:08 +00001759int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001760{
Harald Welte4668fda2009-01-03 08:19:29 +00001761 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001762}
1763
Harald Welte05188ee2009-01-18 11:39:08 +00001764int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001765{
1766 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001767 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001768 else
Harald Welte4668fda2009-01-03 08:19:29 +00001769 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001770}
Harald Welte47d88ae2009-01-04 12:02:08 +00001771
Harald Welte05188ee2009-01-18 11:39:08 +00001772int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001773 enum abis_bs11_objtype type, uint8_t idx,
1774 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001775{
1776 struct abis_om_hdr *oh;
1777 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001778 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001779
1780 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001781 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001782 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001783 cur = msgb_put(msg, attr_len);
1784 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001785
1786 return abis_nm_sendmsg(bts, msg);
1787}
1788
Harald Welte78fc0d42009-02-19 02:50:57 +00001789int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001790 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001791{
1792 struct abis_om_hdr *oh;
1793 struct msgb *msg = nm_msgb_alloc();
1794
1795 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1796 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1797 NM_OC_BS11, type, 0, idx);
1798
1799 return abis_nm_sendmsg(bts, msg);
1800}
1801
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001802int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001803{
1804 struct abis_om_hdr *oh;
1805 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001806 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001807
1808 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001809 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001810 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1811 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001812
1813 return abis_nm_sendmsg(bts, msg);
1814}
1815
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001816int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001817{
1818 struct abis_om_hdr *oh;
1819 struct msgb *msg = nm_msgb_alloc();
1820
1821 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1822 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001823 idx, 0xff, 0xff);
1824
1825 return abis_nm_sendmsg(bts, msg);
1826}
1827
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001828int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001829{
1830 struct abis_om_hdr *oh;
1831 struct msgb *msg = nm_msgb_alloc();
1832
1833 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1834 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1835 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001836
1837 return abis_nm_sendmsg(bts, msg);
1838}
Harald Welte05188ee2009-01-18 11:39:08 +00001839
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001840static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001841int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1842{
1843 struct abis_om_hdr *oh;
1844 struct msgb *msg = nm_msgb_alloc();
1845
1846 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1847 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1848 0xff, 0xff, 0xff);
1849 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1850
1851 return abis_nm_sendmsg(bts, msg);
1852}
1853
Harald Welteb6c92ae2009-02-21 20:15:32 +00001854/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001855int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1856 uint8_t e1_timeslot, uint8_t e1_subslot,
1857 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001858{
1859 struct abis_om_hdr *oh;
1860 struct abis_nm_channel *ch;
1861 struct msgb *msg = nm_msgb_alloc();
1862
1863 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001864 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001865 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1866
1867 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1868 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001869 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001870
1871 return abis_nm_sendmsg(bts, msg);
1872}
1873
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001874int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001875{
1876 struct abis_om_hdr *oh;
1877 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001878
1879 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001880 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001881 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1882 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1883
1884 return abis_nm_sendmsg(trx->bts, msg);
1885}
1886
Harald Welte78fc0d42009-02-19 02:50:57 +00001887int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1888{
1889 struct abis_om_hdr *oh;
1890 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001891 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00001892
1893 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1894 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1895 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1896 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1897
1898 return abis_nm_sendmsg(trx->bts, msg);
1899}
1900
Harald Welteaaf02d92009-04-29 13:25:57 +00001901int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1902{
1903 struct abis_om_hdr *oh;
1904 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001905 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00001906
1907 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1908 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1909 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00001910 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00001911
1912 return abis_nm_sendmsg(bts, msg);
1913}
1914
Harald Welteef061952009-05-17 12:43:42 +00001915int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1916{
1917 struct abis_om_hdr *oh;
1918 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001919 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00001920 NM_ATT_BS11_CCLK_TYPE };
1921
1922 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1923 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1924 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1925 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1926
1927 return abis_nm_sendmsg(bts, msg);
1928
1929}
Harald Welteaaf02d92009-04-29 13:25:57 +00001930
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001931//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00001932
Harald Welte1bc09062009-01-18 14:17:52 +00001933int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00001934{
Daniel Willmann493db4e2010-01-07 00:43:11 +01001935 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1936}
1937
Daniel Willmann4b054c82010-01-07 00:46:26 +01001938int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1939{
1940 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1941}
1942
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001943int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001944{
Harald Welte05188ee2009-01-18 11:39:08 +00001945 struct abis_om_hdr *oh;
1946 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00001947 struct bs11_date_time bdt;
1948
1949 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00001950
1951 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00001952 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001953 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001954 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00001955 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001956 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00001957 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001958 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00001959 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01001960 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00001961 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001962 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00001963 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00001964 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001965 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00001966 }
Harald Welte05188ee2009-01-18 11:39:08 +00001967
1968 return abis_nm_sendmsg(bts, msg);
1969}
Harald Welte1bc09062009-01-18 14:17:52 +00001970
1971int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
1972{
1973 struct abis_om_hdr *oh;
1974 struct msgb *msg;
1975
1976 if (strlen(password) != 10)
1977 return -EINVAL;
1978
1979 msg = nm_msgb_alloc();
1980 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001981 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00001982 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001983 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00001984
1985 return abis_nm_sendmsg(bts, msg);
1986}
1987
Harald Weltee69f5fb2009-04-28 16:31:38 +00001988/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
1989int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
1990{
1991 struct abis_om_hdr *oh;
1992 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001993 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00001994
1995 msg = nm_msgb_alloc();
1996 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1997 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
1998 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00001999
2000 if (locked)
2001 tlv_value = BS11_LI_PLL_LOCKED;
2002 else
2003 tlv_value = BS11_LI_PLL_STANDALONE;
2004
2005 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002006
2007 return abis_nm_sendmsg(bts, msg);
2008}
2009
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002010/* Set the calibration value of the PLL (work value/set value)
2011 * It depends on the login which one is changed */
2012int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2013{
2014 struct abis_om_hdr *oh;
2015 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002016 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002017
2018 msg = nm_msgb_alloc();
2019 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2020 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2021 BS11_OBJ_TRX1, 0x00, 0x00);
2022
2023 tlv_value[0] = value>>8;
2024 tlv_value[1] = value&0xff;
2025
2026 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2027
2028 return abis_nm_sendmsg(bts, msg);
2029}
2030
Harald Welte1bc09062009-01-18 14:17:52 +00002031int abis_nm_bs11_get_state(struct gsm_bts *bts)
2032{
2033 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2034}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002035
2036/* BS11 SWL */
2037
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002038void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002039
Harald Welte5e4d1b32009-02-01 13:36:56 +00002040struct abis_nm_bs11_sw {
2041 struct gsm_bts *bts;
2042 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002043 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002044 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002045 struct llist_head file_list;
2046 gsm_cbfn *user_cb; /* specified by the user */
2047};
2048static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2049
2050struct file_list_entry {
2051 struct llist_head list;
2052 char fname[PATH_MAX];
2053};
2054
2055struct file_list_entry *fl_dequeue(struct llist_head *queue)
2056{
2057 struct llist_head *lh;
2058
2059 if (llist_empty(queue))
2060 return NULL;
2061
2062 lh = queue->next;
2063 llist_del(lh);
2064
2065 return llist_entry(lh, struct file_list_entry, list);
2066}
2067
2068static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2069{
2070 char linebuf[255];
2071 struct llist_head *lh, *lh2;
2072 FILE *swl;
2073 int rc = 0;
2074
2075 swl = fopen(bs11_sw->swl_fname, "r");
2076 if (!swl)
2077 return -ENODEV;
2078
2079 /* zero the stale file list, if any */
2080 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2081 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002082 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002083 }
2084
2085 while (fgets(linebuf, sizeof(linebuf), swl)) {
2086 char file_id[12+1];
2087 char file_version[80+1];
2088 struct file_list_entry *fle;
2089 static char dir[PATH_MAX];
2090
2091 if (strlen(linebuf) < 4)
2092 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002093
Harald Welte5e4d1b32009-02-01 13:36:56 +00002094 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2095 if (rc < 0) {
2096 perror("ERR parsing SWL file");
2097 rc = -EINVAL;
2098 goto out;
2099 }
2100 if (rc < 2)
2101 continue;
2102
Harald Welte470ec292009-06-26 20:25:23 +02002103 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002104 if (!fle) {
2105 rc = -ENOMEM;
2106 goto out;
2107 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002108
2109 /* construct new filename */
2110 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2111 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2112 strcat(fle->fname, "/");
2113 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002114
2115 llist_add_tail(&fle->list, &bs11_sw->file_list);
2116 }
2117
2118out:
2119 fclose(swl);
2120 return rc;
2121}
2122
2123/* bs11 swload specific callback, passed to abis_nm core swload */
2124static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2125 struct msgb *msg, void *data, void *param)
2126{
2127 struct abis_nm_bs11_sw *bs11_sw = data;
2128 struct file_list_entry *fle;
2129 int rc = 0;
2130
Harald Welte5e4d1b32009-02-01 13:36:56 +00002131 switch (event) {
2132 case NM_MT_LOAD_END_ACK:
2133 fle = fl_dequeue(&bs11_sw->file_list);
2134 if (fle) {
2135 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002136 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002137 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002138 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002139 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002140 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002141 } else {
2142 /* activate the SWL */
2143 rc = abis_nm_software_activate(bs11_sw->bts,
2144 bs11_sw->swl_fname,
2145 bs11_swload_cbfn,
2146 bs11_sw);
2147 }
2148 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002149 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002150 case NM_MT_LOAD_END_NACK:
2151 case NM_MT_LOAD_INIT_ACK:
2152 case NM_MT_LOAD_INIT_NACK:
2153 case NM_MT_ACTIVATE_SW_NACK:
2154 case NM_MT_ACTIVATE_SW_ACK:
2155 default:
2156 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002157 if (bs11_sw->user_cb)
2158 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002159 break;
2160 }
2161
2162 return rc;
2163}
2164
2165/* Siemens provides a SWL file that is a mere listing of all the other
2166 * files that are part of a software release. We need to upload first
2167 * the list file, and then each file that is listed in the list file */
2168int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002169 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002170{
2171 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2172 struct file_list_entry *fle;
2173 int rc = 0;
2174
2175 INIT_LLIST_HEAD(&bs11_sw->file_list);
2176 bs11_sw->bts = bts;
2177 bs11_sw->win_size = win_size;
2178 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002179 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002180
2181 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2182 rc = bs11_read_swl_file(bs11_sw);
2183 if (rc < 0)
2184 return rc;
2185
2186 /* dequeue next item in file list */
2187 fle = fl_dequeue(&bs11_sw->file_list);
2188 if (!fle)
2189 return -EINVAL;
2190
2191 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002192 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002193 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002194 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002195 return rc;
2196}
2197
Harald Welte5083b0b2009-02-02 19:20:52 +00002198#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002199static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002200 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2201 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2202 NM_ATT_BS11_LMT_USER_NAME,
2203
2204 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2205
2206 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2207
2208 NM_ATT_BS11_SW_LOAD_STORED };
2209
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002210static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002211 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2212 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2213 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2214 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002215#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002216
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002217static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002218 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2219 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002220 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002221
2222int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2223{
2224 struct abis_om_hdr *oh;
2225 struct msgb *msg = nm_msgb_alloc();
2226
2227 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2228 /* SiemensHW CCTRL object */
2229 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2230 0x03, 0x00, 0x00);
2231 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2232
2233 return abis_nm_sendmsg(bts, msg);
2234}
Harald Welte268bb402009-02-01 19:11:56 +00002235
2236int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2237{
2238 struct abis_om_hdr *oh;
2239 struct msgb *msg = nm_msgb_alloc();
2240 struct bs11_date_time aet;
2241
2242 get_bs11_date_time(&aet);
2243 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2244 /* SiemensHW CCTRL object */
2245 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2246 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002247 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002248
2249 return abis_nm_sendmsg(bts, msg);
2250}
Harald Welte5c1e4582009-02-15 11:57:29 +00002251
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002252int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002253{
2254 struct abis_om_hdr *oh;
2255 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002256 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002257
2258 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2259 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2260 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2261 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2262
2263 return abis_nm_sendmsg(bts, msg);
2264}
2265
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002266int 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 +02002267{
2268 struct abis_om_hdr *oh;
2269 struct msgb *msg = nm_msgb_alloc();
2270 struct bs11_date_time aet;
2271
2272 get_bs11_date_time(&aet);
2273 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2274 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2275 bport, 0xff, 0x02);
2276 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2277
2278 return abis_nm_sendmsg(bts, msg);
2279}
2280
Harald Welte5c1e4582009-02-15 11:57:29 +00002281/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002282static const char ipaccess_magic[] = "com.ipaccess";
2283
Harald Welte677c21f2009-02-17 13:22:23 +00002284
2285static int abis_nm_rx_ipacc(struct msgb *msg)
2286{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002287 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002288 struct abis_om_hdr *oh = msgb_l2(msg);
2289 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002290 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002291 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002292 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002293 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002294
2295 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002296 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002297 return -EINVAL;
2298 }
2299
Harald Welte193fefc2009-04-30 15:16:27 +00002300 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002301 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002302
Harald Welte15c61722011-05-22 22:45:37 +02002303 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002304
Harald Welte746d6092009-10-19 22:11:11 +02002305 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002306
Harald Welte677c21f2009-02-17 13:22:23 +00002307 switch (foh->msg_type) {
2308 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002309 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002310 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2311 memcpy(&addr,
2312 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2313
2314 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2315 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002316 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002317 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002318 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002319 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002320 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2321 DEBUGPC(DNM, "STREAM=0x%02x ",
2322 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002323 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002324 break;
2325 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002326 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002327 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002328 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002329 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002330 else
2331 DEBUGPC(DNM, "\n");
2332 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002333 case NM_MT_IPACC_SET_NVATTR_ACK:
2334 DEBUGPC(DNM, "SET NVATTR ACK\n");
2335 /* FIXME: decode and show the actual attributes */
2336 break;
2337 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002338 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002339 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002340 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002341 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002342 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002343 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002344 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002345 case NM_MT_IPACC_GET_NVATTR_ACK:
2346 DEBUGPC(DNM, "GET NVATTR ACK\n");
2347 /* FIXME: decode and show the actual attributes */
2348 break;
2349 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002350 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002351 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002352 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002353 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002354 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002355 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002356 break;
Harald Welte15c44172009-10-08 20:15:24 +02002357 case NM_MT_IPACC_SET_ATTR_ACK:
2358 DEBUGPC(DNM, "SET ATTR ACK\n");
2359 break;
2360 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002361 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002362 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002363 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002364 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002365 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002366 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002367 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002368 default:
2369 DEBUGPC(DNM, "unknown\n");
2370 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002371 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002372
2373 /* signal handling */
2374 switch (foh->msg_type) {
2375 case NM_MT_IPACC_RSL_CONNECT_NACK:
2376 case NM_MT_IPACC_SET_NVATTR_NACK:
2377 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002378 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 +01002379 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002380 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002381 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002382 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002383 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 +01002384 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002385 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002386 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002387 default:
2388 break;
2389 }
2390
Harald Welte677c21f2009-02-17 13:22:23 +00002391 return 0;
2392}
2393
Harald Welte193fefc2009-04-30 15:16:27 +00002394/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002395int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2396 uint8_t obj_class, uint8_t bts_nr,
2397 uint8_t trx_nr, uint8_t ts_nr,
2398 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002399{
2400 struct msgb *msg = nm_msgb_alloc();
2401 struct abis_om_hdr *oh;
2402 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002403 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002404
2405 /* construct the 12.21 OM header, observe the erroneous length */
2406 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2407 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2408 oh->mdisc = ABIS_OM_MDISC_MANUF;
2409
2410 /* add the ip.access magic */
2411 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2412 *data++ = sizeof(ipaccess_magic);
2413 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2414
2415 /* fill the 12.21 FOM header */
2416 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2417 foh->msg_type = msg_type;
2418 foh->obj_class = obj_class;
2419 foh->obj_inst.bts_nr = bts_nr;
2420 foh->obj_inst.trx_nr = trx_nr;
2421 foh->obj_inst.ts_nr = ts_nr;
2422
2423 if (attr && attr_len) {
2424 data = msgb_put(msg, attr_len);
2425 memcpy(data, attr, attr_len);
2426 }
2427
2428 return abis_nm_sendmsg(bts, msg);
2429}
Harald Welte677c21f2009-02-17 13:22:23 +00002430
Harald Welte193fefc2009-04-30 15:16:27 +00002431/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002432int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002433 int attr_len)
2434{
Harald Welte2ef156d2010-01-07 20:39:42 +01002435 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2436 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002437 attr_len);
2438}
2439
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002440int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002441 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002442{
2443 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002444 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002445 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2446 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2447
2448 int attr_len = sizeof(attr);
2449
2450 ia.s_addr = htonl(ip);
2451 attr[1] = stream;
2452 attr[3] = port >> 8;
2453 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002454 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002455
2456 /* if ip == 0, we use the default IP */
2457 if (ip == 0)
2458 attr_len -= 5;
2459
2460 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002461 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002462
2463 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2464 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2465 trx->nr, 0xff, attr, attr_len);
2466}
2467
Harald Welte193fefc2009-04-30 15:16:27 +00002468/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002469int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002470{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002471 struct abis_om_hdr *oh;
2472 struct msgb *msg = nm_msgb_alloc();
2473
2474 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2475 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2476 trx->bts->nr, trx->nr, 0xff);
2477
2478 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002479}
Harald Weltedaef5212009-10-24 10:20:41 +02002480
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002481int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2482 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2483 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002484{
2485 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2486 obj_class, bts_nr, trx_nr, ts_nr,
2487 attr, attr_len);
2488}
Harald Welte0f255852009-11-12 14:48:42 +01002489
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002490void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002491{
2492 /* we simply reuse the GSM48 function and overwrite the RAC
2493 * with the Cell ID */
2494 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002495 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002496}
2497
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002498void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2499{
2500 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2501
Harald Welted64c0bc2011-05-30 12:07:53 +02002502 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002503 if (!trx->bts || !trx->bts->oml_link)
2504 return;
2505
2506 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2507 trx->bts->bts_nr, trx->nr, 0xff,
2508 new_state);
2509}
2510
Harald Welte92b1fe42010-03-25 11:45:30 +08002511static const struct value_string ipacc_testres_names[] = {
2512 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2513 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2514 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2515 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2516 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2517 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002518};
2519
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002520const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002521{
Harald Welte92b1fe42010-03-25 11:45:30 +08002522 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002523}
2524
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002525void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002526{
2527 cid->mcc = (buf[0] & 0xf) * 100;
2528 cid->mcc += (buf[0] >> 4) * 10;
2529 cid->mcc += (buf[1] & 0xf) * 1;
2530
2531 if (buf[1] >> 4 == 0xf) {
2532 cid->mnc = (buf[2] & 0xf) * 10;
2533 cid->mnc += (buf[2] >> 4) * 1;
2534 } else {
2535 cid->mnc = (buf[2] & 0xf) * 100;
2536 cid->mnc += (buf[2] >> 4) * 10;
2537 cid->mnc += (buf[1] >> 4) * 1;
2538 }
2539
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002540 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2541 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002542}
2543
Harald Welte0f255852009-11-12 14:48:42 +01002544/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002545int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002546{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002547 uint8_t *cur = buf;
2548 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01002549
Harald Welteaf109b92010-07-22 18:14:36 +02002550 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002551
2552 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2553 return -EINVAL;
2554 cur++;
2555
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002556 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002557 cur += 2;
2558
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002559 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002560 cur += 2;
2561
2562 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2563 binf->freq_qual = *cur >> 2;
2564
Harald Welteaf109b92010-07-22 18:14:36 +02002565 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002566 binf->arfcn |= *cur++;
2567
2568 if (binf->info_type & IPAC_BINF_RXLEV)
2569 binf->rx_lev = *cur & 0x3f;
2570 cur++;
2571
2572 if (binf->info_type & IPAC_BINF_RXQUAL)
2573 binf->rx_qual = *cur & 0x7;
2574 cur++;
2575
2576 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002577 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002578 cur += 2;
2579
2580 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002581 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002582 cur += 2;
2583
2584 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002585 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002586 cur += 4;
2587
Harald Weltea780a3d2010-07-30 22:34:42 +02002588#if 0
2589 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002590 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002591#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002592 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002593 cur++;
2594
Harald Welteb40a38f2009-11-13 11:56:05 +01002595 ipac_parse_cgi(&binf->cgi, cur);
2596 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002597
2598 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2599 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2600 cur += sizeof(binf->ba_list_si2);
2601 }
2602
2603 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2604 memcpy(binf->ba_list_si2bis, cur,
2605 sizeof(binf->ba_list_si2bis));
2606 cur += sizeof(binf->ba_list_si2bis);
2607 }
2608
2609 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2610 memcpy(binf->ba_list_si2ter, cur,
2611 sizeof(binf->ba_list_si2ter));
2612 cur += sizeof(binf->ba_list_si2ter);
2613 }
2614
2615 return 0;
2616}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002617
2618void abis_nm_clear_queue(struct gsm_bts *bts)
2619{
2620 struct msgb *msg;
2621
2622 while (!llist_empty(&bts->abis_queue)) {
2623 msg = msgb_dequeue(&bts->abis_queue);
2624 msgb_free(msg);
2625 }
2626
2627 bts->abis_nm_pend = 0;
2628}