blob: 027a2638b116a8e9baca25e20979c03a672d0007 [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000043#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte52b1f982008-12-23 20:25:15 +000047
Harald Welte8470bf22008-12-25 23:28:35 +000048#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000051
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020052int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +000053{
Harald Welte39315c42010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000057}
Harald Weltee0590df2009-02-15 03:34:15 +000058
Harald Welte52b1f982008-12-23 20:25:15 +000059static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
Holger Freytherca362a62009-01-04 21:05:01 +000071#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000072/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
Holger Freytherca362a62009-01-04 21:05:01 +000077#endif
Harald Welte52b1f982008-12-23 20:25:15 +000078
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Welte15c61722011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +000099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
Harald Welte702d8702008-12-26 20:25:35 +0000103 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
109}
110
Harald Welte8470bf22008-12-25 23:28:35 +0000111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte966636f2009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000115}
116
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200117int _abis_nm_sendmsg(struct msgb *msg, int to_trx_oml)
118{
119 struct e1inp_sign_link *sign_link = msg->dst;
120
121 msg->l2h = msg->data;
122
123 if (!msg->dst) {
124 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
125 return -EINVAL;
126 }
127
128 /* Check for TRX-specific OML link first */
129 if (to_trx_oml) {
130 if (!sign_link->trx->oml_link)
131 return -ENODEV;
132 msg->dst = sign_link->trx->oml_link;
133 }
134 return abis_sendmsg(msg);
135}
136
Harald Welte52b1f982008-12-23 20:25:15 +0000137/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100138static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000139{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200140 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000141
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100142 /* queue OML messages */
143 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
144 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100145 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100146 } else {
147 msgb_enqueue(&bts->abis_queue, msg);
148 return 0;
149 }
150
151}
152
153int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
154{
155 OBSC_NM_W_ACK_CB(msg) = 1;
156 return abis_nm_queue_msg(bts, msg);
157}
158
159static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
160{
161 OBSC_NM_W_ACK_CB(msg) = 0;
162 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000163}
164
Harald Welte4724f992009-01-18 18:01:49 +0000165static int abis_nm_rcvmsg_sw(struct msgb *mb);
166
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100167int nm_is_running(struct gsm_nm_state *s) {
168 return (s->operational == NM_OPSTATE_ENABLED) && (
169 (s->availability == NM_AVSTATE_OK) ||
170 (s->availability == 0xff)
171 );
172}
173
Harald Weltee0590df2009-02-15 03:34:15 +0000174/* Update the administrative state of a given object in our in-memory data
175 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200176static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
177 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000178{
Harald Welteaeedeb42009-05-01 13:08:14 +0000179 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100180 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000181
Harald Welteaf9b8102011-03-06 21:20:38 +0100182 memset(&nsd, 0, sizeof(nsd));
183
Harald Welte978714d2011-06-06 18:31:20 +0200184 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100185 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100186 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200187 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000188 if (!nm_state)
189 return -1;
190
191 new_state = *nm_state;
192 new_state.administrative = adm_state;
193
Harald Weltef38ca9a2011-03-06 22:11:32 +0100194 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100195 nsd.obj_class = obj_class;
196 nsd.old_state = nm_state;
197 nsd.new_state = &new_state;
198 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200199 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000200
201 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000202
Harald Weltef338a032011-01-14 15:55:42 +0100203 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000204}
205
Harald Welte97ed1e72009-02-06 13:38:02 +0000206static int abis_nm_rx_statechg_rep(struct msgb *mb)
207{
Harald Weltee0590df2009-02-15 03:34:15 +0000208 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000209 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200210 struct e1inp_sign_link *sign_link = mb->dst;
211 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000212 struct tlv_parsed tp;
213 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000214
Harald Welte23897662009-05-01 14:52:51 +0000215 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000216
Harald Welte8b697c72009-06-05 19:18:45 +0000217 memset(&new_state, 0, sizeof(new_state));
218
Harald Welte978714d2011-06-06 18:31:20 +0200219 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000220 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100221 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000222 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000223 }
Harald Weltee0590df2009-02-15 03:34:15 +0000224
225 new_state = *nm_state;
226
Harald Welte39315c42010-01-10 18:01:52 +0100227 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000228 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
229 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "OP_STATE=%s ",
231 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000232 }
233 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000234 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
235 new_state.availability = 0xff;
236 else
237 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200238 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
239 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000240 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100241 } else
242 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000243 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
244 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200245 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200246 get_value_string(abis_nm_adm_state_names,
247 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000248 }
249 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000250
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100251 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
252 new_state.operational != nm_state->operational ||
253 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000254 /* Update the operational state of a given object in our in-memory data
255 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100256 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200257 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100258 nsd.obj_class = foh->obj_class;
259 nsd.old_state = nm_state;
260 nsd.new_state = &new_state;
261 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100262 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200263 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100264 nm_state->operational = new_state.operational;
265 nm_state->availability = new_state.availability;
266 if (nm_state->administrative == 0)
267 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000268 }
269#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000270 if (op_state == 1) {
271 /* try to enable objects that are disabled */
272 abis_nm_opstart(bts, foh->obj_class,
273 foh->obj_inst.bts_nr,
274 foh->obj_inst.trx_nr,
275 foh->obj_inst.ts_nr);
276 }
Harald Weltee0590df2009-02-15 03:34:15 +0000277#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000278 return 0;
279}
280
Harald Welte0db97b22009-05-01 17:22:47 +0000281static int rx_fail_evt_rep(struct msgb *mb)
282{
283 struct abis_om_hdr *oh = msgb_l2(mb);
284 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200285 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000286 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100287 const uint8_t *p_val;
288 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000289
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200290 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000291
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200292 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000293
294 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200295 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
296 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000297 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200298 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
299 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100300 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
301 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200302 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 +0100303 }
304 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
305 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
306 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
307 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200308 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100309 talloc_free(p_text);
310 }
311 }
Harald Welte0db97b22009-05-01 17:22:47 +0000312
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200313 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000314
315 return 0;
316}
317
Harald Welte97ed1e72009-02-06 13:38:02 +0000318static int abis_nm_rcvmsg_report(struct msgb *mb)
319{
320 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200321 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000322
Harald Welte15c61722011-05-22 22:45:37 +0200323 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000324
Harald Welte97ed1e72009-02-06 13:38:02 +0000325 //nmh->cfg->report_cb(mb, foh);
326
327 switch (mt) {
328 case NM_MT_STATECHG_EVENT_REP:
329 return abis_nm_rx_statechg_rep(mb);
330 break;
Harald Welte34a99682009-02-13 02:41:40 +0000331 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000332 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000334 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000335 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000336 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200337 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000338 break;
Harald Weltec7310382009-08-08 00:02:36 +0200339 case NM_MT_TEST_REP:
340 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200341 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200342 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000343 default:
Harald Welte23897662009-05-01 14:52:51 +0000344 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000345 break;
346
Harald Welte97ed1e72009-02-06 13:38:02 +0000347 };
348
Harald Welte97ed1e72009-02-06 13:38:02 +0000349 return 0;
350}
351
Harald Welte34a99682009-02-13 02:41:40 +0000352/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200353static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
354 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000355{
356 struct abis_om_hdr *oh;
357 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200358 uint8_t len = swdesc_len;
359 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000360
361 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
362 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
363
364 trailer = msgb_put(msg, swdesc_len);
365 memcpy(trailer, sw_desc, swdesc_len);
366
367 return abis_nm_sendmsg(bts, msg);
368}
369
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200370static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100371{
372 static const struct tlv_definition sw_descr_def = {
373 .def = {
374 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
375 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
376 },
377 };
378
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200379 uint8_t tag;
380 uint16_t tag_len;
381 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100382 int ofs = 0, len;
383
384 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
385 * nested nature and the fact you have to assume it contains only two sub
386 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
387
388 if (sw_descr[0] != NM_ATT_SW_DESCR) {
389 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
390 return -1;
391 }
392 ofs += 1;
393
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
396 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
397 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
398 return -2;
399 }
400 ofs += len;
401
402 len = tlv_parse_one(&tag, &tag_len, &val,
403 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
404 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
405 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
406 return -3;
407 }
408 ofs += len;
409
410 return ofs;
411}
412
Harald Welte34a99682009-02-13 02:41:40 +0000413static int abis_nm_rx_sw_act_req(struct msgb *mb)
414{
415 struct abis_om_hdr *oh = msgb_l2(mb);
416 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200417 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200418 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200419 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100420 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000421
Harald Welte15c61722011-05-22 22:45:37 +0200422 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200423
424 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000425
Harald Welte97a282b2010-03-14 15:37:43 +0800426 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000427
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200428 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000429 foh->obj_inst.bts_nr,
430 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800431 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000432 foh->data, oh->length-sizeof(*foh));
433
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200434 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200435 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
436 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
437 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
438 DEBUGP(DNM, "SW config not found! Can't continue.\n");
439 return -EINVAL;
440 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200441 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200442 }
443
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100444 /* Use the first SW_DESCR present in SW config */
445 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
446 if (sw_descr_len < 0)
447 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200448
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200449 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000450 foh->obj_inst.bts_nr,
451 foh->obj_inst.trx_nr,
452 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100453 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000454}
455
Harald Weltee0590df2009-02-15 03:34:15 +0000456/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
457static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
458{
459 struct abis_om_hdr *oh = msgb_l2(mb);
460 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200461 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000462 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200463 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000464
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200465 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000466 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
467 return -EINVAL;
468
469 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
470
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200471 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000472}
473
Harald Welteee670472009-02-22 21:58:49 +0000474static int abis_nm_rx_lmt_event(struct msgb *mb)
475{
476 struct abis_om_hdr *oh = msgb_l2(mb);
477 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200478 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000479 struct tlv_parsed tp;
480
481 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200482 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000483 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
484 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200485 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000486 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
487 }
488 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
489 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200490 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000491 DEBUGPC(DNM, "Level=%u ", level);
492 }
493 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
494 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
495 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
496 DEBUGPC(DNM, "Username=%s ", name);
497 }
498 DEBUGPC(DNM, "\n");
499 /* FIXME: parse LMT LOGON TIME */
500 return 0;
501}
502
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200503void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100504{
505 int wait = 0;
506 struct msgb *msg;
507 /* the queue is empty */
508 while (!llist_empty(&bts->abis_queue)) {
509 msg = msgb_dequeue(&bts->abis_queue);
510 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100511 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100512
513 if (wait)
514 break;
515 }
516
517 bts->abis_nm_pend = wait;
518}
519
Harald Welte52b1f982008-12-23 20:25:15 +0000520/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000521static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000522{
Harald Welte6c96ba52009-05-01 13:03:40 +0000523 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000524 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200525 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200526 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100527 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000528
529 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000530 if (is_report(mt))
531 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000532
Harald Welte15c61722011-05-22 22:45:37 +0200533 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000534 return abis_nm_rcvmsg_sw(mb);
535
Harald Welte15c61722011-05-22 22:45:37 +0200536 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800537 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000538 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200539
Harald Welte15c61722011-05-22 22:45:37 +0200540 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200541
Harald Welte15c61722011-05-22 22:45:37 +0200542 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000543
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200544 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000545 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200546 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200547 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000548 else
549 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200550
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800551 nack_data.msg = mb;
552 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200553 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200554 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200555 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000556 }
Harald Weltead384642008-12-26 10:20:07 +0000557#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000558 /* check if last message is to be acked */
559 if (is_ack_nack(nmh->last_msgtype)) {
560 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100561 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000562 /* we got our ACK, continue sending the next msg */
563 } else if (mt == MT_NACK(nmh->last_msgtype)) {
564 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100565 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000566 /* FIXME: somehow signal this to the caller */
567 } else {
568 /* really strange things happen */
569 return -EINVAL;
570 }
571 }
Harald Weltead384642008-12-26 10:20:07 +0000572#endif
573
Harald Welte97ed1e72009-02-06 13:38:02 +0000574 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000575 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100576 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000577 break;
Harald Welte34a99682009-02-13 02:41:40 +0000578 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100579 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000580 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000581 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100582 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000583 break;
Harald Welte1989c082009-08-06 17:58:31 +0200584 case NM_MT_CONN_MDROP_LINK_ACK:
585 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
586 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100587 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200588 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100589 break;
590 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200591 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100592 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100593 case NM_MT_SET_BTS_ATTR_ACK:
594 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200595 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
596 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Weltefd355a32011-03-04 13:41:31 +0100597 }
598 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000599 }
600
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200601 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100602 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000603}
604
Harald Welte677c21f2009-02-17 13:22:23 +0000605static int abis_nm_rx_ipacc(struct msgb *mb);
606
607static int abis_nm_rcvmsg_manuf(struct msgb *mb)
608{
609 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200610 struct e1inp_sign_link *sign_link = mb->dst;
611 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000612
613 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100614 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000615 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200616 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000617 break;
618 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100619 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
620 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000621 rc = 0;
622 break;
623 }
624
625 return rc;
626}
627
Harald Welte52b1f982008-12-23 20:25:15 +0000628/* High-Level API */
629/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000630int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000631{
Harald Welte52b1f982008-12-23 20:25:15 +0000632 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000633 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000634
635 /* Various consistency checks */
636 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100637 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000638 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200639 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
640 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000641 }
642 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100643 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000644 oh->sequence);
645 return -EINVAL;
646 }
Harald Welte702d8702008-12-26 20:25:35 +0000647#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200648 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000649 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000650 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100651 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000652 oh->length + sizeof(*oh), l2_len);
653 return -EINVAL;
654 }
Harald Welte702d8702008-12-26 20:25:35 +0000655 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100656 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 +0000657#endif
Harald Weltead384642008-12-26 10:20:07 +0000658 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000659
660 switch (oh->mdisc) {
661 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000662 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000663 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000664 case ABIS_OM_MDISC_MANUF:
665 rc = abis_nm_rcvmsg_manuf(msg);
666 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000667 case ABIS_OM_MDISC_MMI:
668 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100669 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000670 oh->mdisc);
671 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000672 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100673 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000674 oh->mdisc);
675 return -EINVAL;
676 }
677
Harald Weltead384642008-12-26 10:20:07 +0000678 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000679 return rc;
680}
681
682#if 0
683/* initialized all resources */
684struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
685{
686 struct abis_nm_h *nmh;
687
688 nmh = malloc(sizeof(*nmh));
689 if (!nmh)
690 return NULL;
691
692 nmh->cfg = cfg;
693
694 return nmh;
695}
696
697/* free all resources */
698void abis_nm_fini(struct abis_nm_h *nmh)
699{
700 free(nmh);
701}
702#endif
703
704/* Here we are trying to define a high-level API that can be used by
705 * the actual BSC implementation. However, the architecture is currently
706 * still under design. Ideally the calls to this API would be synchronous,
707 * while the underlying stack behind the APi runs in a traditional select
708 * based state machine.
709 */
710
Harald Welte4724f992009-01-18 18:01:49 +0000711/* 6.2 Software Load: */
712enum sw_state {
713 SW_STATE_NONE,
714 SW_STATE_WAIT_INITACK,
715 SW_STATE_WAIT_SEGACK,
716 SW_STATE_WAIT_ENDACK,
717 SW_STATE_WAIT_ACTACK,
718 SW_STATE_ERROR,
719};
Harald Welte52b1f982008-12-23 20:25:15 +0000720
Harald Welte52b1f982008-12-23 20:25:15 +0000721struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000722 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800723 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000724 gsm_cbfn *cbfn;
725 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000726 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000727
Harald Welte52b1f982008-12-23 20:25:15 +0000728 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200729 uint8_t obj_class;
730 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000731
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200732 uint8_t file_id[255];
733 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000734
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200735 uint8_t file_version[255];
736 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000737
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200738 uint8_t window_size;
739 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000740
741 int fd;
742 FILE *stream;
743 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000744 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000745};
746
Harald Welte4724f992009-01-18 18:01:49 +0000747static struct abis_nm_sw g_sw;
748
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100749static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
750{
751 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
752 msgb_v_put(msg, NM_ATT_SW_DESCR);
753 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
754 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
755 sw->file_version);
756 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
757 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
758 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
759 sw->file_version);
760 } else {
761 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
762 }
763}
764
Harald Welte4724f992009-01-18 18:01:49 +0000765/* 6.2.1 / 8.3.1: Load Data Initiate */
766static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000767{
Harald Welte4724f992009-01-18 18:01:49 +0000768 struct abis_om_hdr *oh;
769 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200770 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000771
772 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
773 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
774 sw->obj_instance[0], sw->obj_instance[1],
775 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100776
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100777 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000778 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
779
780 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000781}
782
Harald Welte1602ade2009-01-29 21:12:39 +0000783static int is_last_line(FILE *stream)
784{
785 char next_seg_buf[256];
786 long pos;
787
788 /* check if we're sending the last line */
789 pos = ftell(stream);
790 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
791 fseek(stream, pos, SEEK_SET);
792 return 1;
793 }
794
795 fseek(stream, pos, SEEK_SET);
796 return 0;
797}
798
Harald Welte4724f992009-01-18 18:01:49 +0000799/* 6.2.2 / 8.3.2 Load Data Segment */
800static int sw_load_segment(struct abis_nm_sw *sw)
801{
802 struct abis_om_hdr *oh;
803 struct msgb *msg = nm_msgb_alloc();
804 char seg_buf[256];
805 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000806 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200807 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000808
809 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000810
811 switch (sw->bts->type) {
812 case GSM_BTS_TYPE_BS11:
813 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
814 perror("fgets reading segment");
815 return -EINVAL;
816 }
817 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000818
819 /* check if we're sending the last line */
820 sw->last_seg = is_last_line(sw->stream);
821 if (sw->last_seg)
822 seg_buf[1] = 0;
823 else
824 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000825
826 len = strlen(line_buf) + 2;
827 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200828 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000829 /* BS11 wants CR + LF in excess of the TLV length !?! */
830 tlv[1] -= 2;
831
832 /* we only now know the exact length for the OM hdr */
833 len = strlen(line_buf)+2;
834 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100835 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200836 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100837 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
838 if (len < 0) {
839 perror("read failed");
840 return -EINVAL;
841 }
842
843 if (len != IPACC_SEGMENT_SIZE)
844 sw->last_seg = 1;
845
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100846 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200847 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100848 len += 3;
849 break;
850 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000851 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100852 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000853 /* FIXME: Other BTS types */
854 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000855 }
Harald Welte4724f992009-01-18 18:01:49 +0000856
Harald Welte4724f992009-01-18 18:01:49 +0000857 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
858 sw->obj_instance[0], sw->obj_instance[1],
859 sw->obj_instance[2]);
860
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100861 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000862}
863
864/* 6.2.4 / 8.3.4 Load Data End */
865static int sw_load_end(struct abis_nm_sw *sw)
866{
867 struct abis_om_hdr *oh;
868 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200869 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000870
871 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
872 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
873 sw->obj_instance[0], sw->obj_instance[1],
874 sw->obj_instance[2]);
875
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100876 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000877 return abis_nm_sendmsg(sw->bts, msg);
878}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000879
Harald Welte52b1f982008-12-23 20:25:15 +0000880/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000881static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000882{
Harald Welte4724f992009-01-18 18:01:49 +0000883 struct abis_om_hdr *oh;
884 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200885 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000886
Harald Welte4724f992009-01-18 18:01:49 +0000887 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
888 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
889 sw->obj_instance[0], sw->obj_instance[1],
890 sw->obj_instance[2]);
891
892 /* FIXME: this is BS11 specific format */
893 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
894 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
895 sw->file_version);
896
897 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000898}
Harald Welte4724f992009-01-18 18:01:49 +0000899
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100900struct sdp_firmware {
901 char magic[4];
902 char more_magic[4];
903 unsigned int header_length;
904 unsigned int file_length;
905} __attribute__ ((packed));
906
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100907static int parse_sdp_header(struct abis_nm_sw *sw)
908{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100909 struct sdp_firmware firmware_header;
910 int rc;
911 struct stat stat;
912
913 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
914 if (rc != sizeof(firmware_header)) {
915 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
916 return -1;
917 }
918
919 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
920 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
921 return -1;
922 }
923
924 if (firmware_header.more_magic[0] != 0x10 ||
925 firmware_header.more_magic[1] != 0x02 ||
926 firmware_header.more_magic[2] != 0x00 ||
927 firmware_header.more_magic[3] != 0x00) {
928 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
929 return -1;
930 }
931
932
933 if (fstat(sw->fd, &stat) == -1) {
934 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
935 return -1;
936 }
937
938 if (ntohl(firmware_header.file_length) != stat.st_size) {
939 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
940 return -1;
941 }
942
943 /* go back to the start as we checked the whole filesize.. */
944 lseek(sw->fd, 0l, SEEK_SET);
945 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
946 "There might be checksums in the file that are not\n"
947 "verified and incomplete firmware might be flashed.\n"
948 "There is absolutely no WARRANTY that flashing will\n"
949 "work.\n");
950 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100951}
952
Harald Welte4724f992009-01-18 18:01:49 +0000953static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
954{
955 char file_id[12+1];
956 char file_version[80+1];
957 int rc;
958
959 sw->fd = open(fname, O_RDONLY);
960 if (sw->fd < 0)
961 return sw->fd;
962
963 switch (sw->bts->type) {
964 case GSM_BTS_TYPE_BS11:
965 sw->stream = fdopen(sw->fd, "r");
966 if (!sw->stream) {
967 perror("fdopen");
968 return -1;
969 }
970 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200971 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +0000972 file_id, file_version);
973 if (rc != 2) {
974 perror("parsing header line of software file");
975 return -1;
976 }
977 strcpy((char *)sw->file_id, file_id);
978 sw->file_id_len = strlen(file_id);
979 strcpy((char *)sw->file_version, file_version);
980 sw->file_version_len = strlen(file_version);
981 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +0000982 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +0000983 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100984 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100985 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100986 rc = parse_sdp_header(sw);
987 if (rc < 0) {
988 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
989 return -1;
990 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100991
992 strcpy((char *)sw->file_id, "id");
993 sw->file_id_len = 3;
994 strcpy((char *)sw->file_version, "version");
995 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100996 break;
Harald Welte4724f992009-01-18 18:01:49 +0000997 default:
998 /* We don't know how to treat them yet */
999 close(sw->fd);
1000 return -EINVAL;
1001 }
1002
1003 return 0;
1004}
1005
1006static void sw_close_file(struct abis_nm_sw *sw)
1007{
1008 switch (sw->bts->type) {
1009 case GSM_BTS_TYPE_BS11:
1010 fclose(sw->stream);
1011 break;
1012 default:
1013 close(sw->fd);
1014 break;
1015 }
1016}
1017
1018/* Fill the window */
1019static int sw_fill_window(struct abis_nm_sw *sw)
1020{
1021 int rc;
1022
1023 while (sw->seg_in_window < sw->window_size) {
1024 rc = sw_load_segment(sw);
1025 if (rc < 0)
1026 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001027 if (sw->last_seg)
1028 break;
Harald Welte4724f992009-01-18 18:01:49 +00001029 }
1030 return 0;
1031}
1032
1033/* callback function from abis_nm_rcvmsg() handler */
1034static int abis_nm_rcvmsg_sw(struct msgb *mb)
1035{
1036 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001037 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001038 int rc = -1;
1039 struct abis_nm_sw *sw = &g_sw;
1040 enum sw_state old_state = sw->state;
1041
Harald Welte3ffd1372009-02-01 22:15:49 +00001042 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001043
1044 switch (sw->state) {
1045 case SW_STATE_WAIT_INITACK:
1046 switch (foh->msg_type) {
1047 case NM_MT_LOAD_INIT_ACK:
1048 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001049 if (sw->cbfn)
1050 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1051 NM_MT_LOAD_INIT_ACK, mb,
1052 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001053 rc = sw_fill_window(sw);
1054 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001055 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001056 break;
1057 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001058 if (sw->forced) {
1059 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1060 "Init NACK\n");
1061 if (sw->cbfn)
1062 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1063 NM_MT_LOAD_INIT_ACK, mb,
1064 sw->cb_data, NULL);
1065 rc = sw_fill_window(sw);
1066 sw->state = SW_STATE_WAIT_SEGACK;
1067 } else {
1068 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001069 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001070 if (sw->cbfn)
1071 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1072 NM_MT_LOAD_INIT_NACK, mb,
1073 sw->cb_data, NULL);
1074 sw->state = SW_STATE_ERROR;
1075 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001076 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001077 break;
1078 }
1079 break;
1080 case SW_STATE_WAIT_SEGACK:
1081 switch (foh->msg_type) {
1082 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001083 if (sw->cbfn)
1084 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1085 NM_MT_LOAD_SEG_ACK, mb,
1086 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001087 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001088 if (!sw->last_seg) {
1089 /* fill window with more segments */
1090 rc = sw_fill_window(sw);
1091 sw->state = SW_STATE_WAIT_SEGACK;
1092 } else {
1093 /* end the transfer */
1094 sw->state = SW_STATE_WAIT_ENDACK;
1095 rc = sw_load_end(sw);
1096 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001097 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001098 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001099 case NM_MT_LOAD_ABORT:
1100 if (sw->cbfn)
1101 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1102 NM_MT_LOAD_ABORT, mb,
1103 sw->cb_data, NULL);
1104 break;
Harald Welte4724f992009-01-18 18:01:49 +00001105 }
1106 break;
1107 case SW_STATE_WAIT_ENDACK:
1108 switch (foh->msg_type) {
1109 case NM_MT_LOAD_END_ACK:
1110 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001111 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1112 sw->bts->nr);
1113 sw->state = SW_STATE_NONE;
1114 if (sw->cbfn)
1115 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1116 NM_MT_LOAD_END_ACK, mb,
1117 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001118 rc = 0;
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 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001122 if (sw->forced) {
1123 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1124 "End NACK\n");
1125 sw->state = SW_STATE_NONE;
1126 if (sw->cbfn)
1127 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1128 NM_MT_LOAD_END_ACK, mb,
1129 sw->cb_data, NULL);
1130 } else {
1131 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001132 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001133 sw->state = SW_STATE_ERROR;
1134 if (sw->cbfn)
1135 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1136 NM_MT_LOAD_END_NACK, mb,
1137 sw->cb_data, NULL);
1138 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001139 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001140 break;
1141 }
1142 case SW_STATE_WAIT_ACTACK:
1143 switch (foh->msg_type) {
1144 case NM_MT_ACTIVATE_SW_ACK:
1145 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001146 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001147 sw->state = SW_STATE_NONE;
1148 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001149 if (sw->cbfn)
1150 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1151 NM_MT_ACTIVATE_SW_ACK, mb,
1152 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001153 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001154 break;
1155 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001156 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001157 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001158 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001159 if (sw->cbfn)
1160 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1161 NM_MT_ACTIVATE_SW_NACK, mb,
1162 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001163 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001164 break;
1165 }
1166 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001167 switch (foh->msg_type) {
1168 case NM_MT_ACTIVATE_SW_ACK:
1169 rc = 0;
1170 break;
1171 }
1172 break;
Harald Welte4724f992009-01-18 18:01:49 +00001173 case SW_STATE_ERROR:
1174 break;
1175 }
1176
1177 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001178 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001179 foh->msg_type, old_state, sw->state);
1180
1181 return rc;
1182}
1183
1184/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001185int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001186 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001187 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001188{
1189 struct abis_nm_sw *sw = &g_sw;
1190 int rc;
1191
Harald Welte5e4d1b32009-02-01 13:36:56 +00001192 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1193 bts->nr, fname);
1194
Harald Welte4724f992009-01-18 18:01:49 +00001195 if (sw->state != SW_STATE_NONE)
1196 return -EBUSY;
1197
1198 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001199 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001200
1201 switch (bts->type) {
1202 case GSM_BTS_TYPE_BS11:
1203 sw->obj_class = NM_OC_SITE_MANAGER;
1204 sw->obj_instance[0] = 0xff;
1205 sw->obj_instance[1] = 0xff;
1206 sw->obj_instance[2] = 0xff;
1207 break;
1208 case GSM_BTS_TYPE_NANOBTS:
1209 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001210 sw->obj_instance[0] = sw->bts->nr;
1211 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001212 sw->obj_instance[2] = 0xff;
1213 break;
1214 case GSM_BTS_TYPE_UNKNOWN:
1215 default:
1216 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1217 return -1;
1218 break;
1219 }
Harald Welte4724f992009-01-18 18:01:49 +00001220 sw->window_size = win_size;
1221 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001222 sw->cbfn = cbfn;
1223 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001224 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001225
1226 rc = sw_open_file(sw, fname);
1227 if (rc < 0) {
1228 sw->state = SW_STATE_NONE;
1229 return rc;
1230 }
1231
1232 return sw_load_init(sw);
1233}
Harald Welte52b1f982008-12-23 20:25:15 +00001234
Harald Welte1602ade2009-01-29 21:12:39 +00001235int abis_nm_software_load_status(struct gsm_bts *bts)
1236{
1237 struct abis_nm_sw *sw = &g_sw;
1238 struct stat st;
1239 int rc, percent;
1240
1241 rc = fstat(sw->fd, &st);
1242 if (rc < 0) {
1243 perror("ERROR during stat");
1244 return rc;
1245 }
1246
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001247 if (sw->stream)
1248 percent = (ftell(sw->stream) * 100) / st.st_size;
1249 else
1250 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001251 return percent;
1252}
1253
Harald Welte5e4d1b32009-02-01 13:36:56 +00001254/* Activate the specified software into the BTS */
1255int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1256 gsm_cbfn *cbfn, void *cb_data)
1257{
1258 struct abis_nm_sw *sw = &g_sw;
1259 int rc;
1260
1261 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1262 bts->nr, fname);
1263
1264 if (sw->state != SW_STATE_NONE)
1265 return -EBUSY;
1266
1267 sw->bts = bts;
1268 sw->obj_class = NM_OC_SITE_MANAGER;
1269 sw->obj_instance[0] = 0xff;
1270 sw->obj_instance[1] = 0xff;
1271 sw->obj_instance[2] = 0xff;
1272 sw->state = SW_STATE_WAIT_ACTACK;
1273 sw->cbfn = cbfn;
1274 sw->cb_data = cb_data;
1275
1276 /* Open the file in order to fill some sw struct members */
1277 rc = sw_open_file(sw, fname);
1278 if (rc < 0) {
1279 sw->state = SW_STATE_NONE;
1280 return rc;
1281 }
1282 sw_close_file(sw);
1283
1284 return sw_activate(sw);
1285}
1286
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001287static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1288 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001289{
Harald Welteadaf08b2009-01-18 11:08:10 +00001290 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001291 ch->bts_port = bts_port;
1292 ch->timeslot = ts_nr;
1293 ch->subslot = subslot_nr;
1294}
1295
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001296int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1297 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1298 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001299{
1300 struct abis_om_hdr *oh;
1301 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001302 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001303 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001304
1305 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1306 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1307 bts->bts_nr, trx_nr, 0xff);
1308
Harald Welte8470bf22008-12-25 23:28:35 +00001309 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001310
1311 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1312 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1313
1314 return abis_nm_sendmsg(bts, msg);
1315}
1316
1317/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1318int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001319 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001320{
Harald Welte8470bf22008-12-25 23:28:35 +00001321 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001322 struct abis_om_hdr *oh;
1323 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001324 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001325
1326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001327 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001328 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1329
1330 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1331 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1332
1333 return abis_nm_sendmsg(bts, msg);
1334}
1335
1336#if 0
1337int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1338 struct abis_nm_abis_channel *chan)
1339{
1340}
1341#endif
1342
1343int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001344 uint8_t e1_port, uint8_t e1_timeslot,
1345 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001346{
1347 struct gsm_bts *bts = ts->trx->bts;
1348 struct abis_om_hdr *oh;
1349 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001350 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001351
1352 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1353 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001354 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001355
1356 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1357 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1358
Harald Weltef325eb42009-02-19 17:07:39 +00001359 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1360 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001361 e1_port, e1_timeslot, e1_subslot);
1362
Harald Welte52b1f982008-12-23 20:25:15 +00001363 return abis_nm_sendmsg(bts, msg);
1364}
1365
1366#if 0
1367int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1368 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001369 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001370{
1371}
1372#endif
1373
Harald Welte22af0db2009-02-14 15:41:08 +00001374/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001375int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001376{
1377 struct abis_om_hdr *oh;
1378 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001379 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001380
1381 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1382
1383 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001384 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 +00001385 cur = msgb_put(msg, attr_len);
1386 memcpy(cur, attr, attr_len);
1387
1388 return abis_nm_sendmsg(bts, msg);
1389}
1390
1391/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001392int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001393{
1394 struct abis_om_hdr *oh;
1395 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001396 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001397
1398 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1399
1400 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1401 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001402 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001403 cur = msgb_put(msg, attr_len);
1404 memcpy(cur, attr, attr_len);
1405
1406 return abis_nm_sendmsg(trx->bts, msg);
1407}
1408
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001409static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001410{
1411 int i;
1412
1413 /* As it turns out, the BS-11 has some very peculiar restrictions
1414 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301415 switch (ts->trx->bts->type) {
1416 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001417 switch (chan_comb) {
1418 case NM_CHANC_TCHHalf:
1419 case NM_CHANC_TCHHalf2:
1420 /* not supported */
1421 return -EINVAL;
1422 case NM_CHANC_SDCCH:
1423 /* only one SDCCH/8 per TRX */
1424 for (i = 0; i < TRX_NR_TS; i++) {
1425 if (i == ts->nr)
1426 continue;
1427 if (ts->trx->ts[i].nm_chan_comb ==
1428 NM_CHANC_SDCCH)
1429 return -EINVAL;
1430 }
1431 /* not allowed for TS0 of BCCH-TRX */
1432 if (ts->trx == ts->trx->bts->c0 &&
1433 ts->nr == 0)
1434 return -EINVAL;
1435 /* not on the same TRX that has a BCCH+SDCCH4
1436 * combination */
1437 if (ts->trx == ts->trx->bts->c0 &&
1438 (ts->trx->ts[0].nm_chan_comb == 5 ||
1439 ts->trx->ts[0].nm_chan_comb == 8))
1440 return -EINVAL;
1441 break;
1442 case NM_CHANC_mainBCCH:
1443 case NM_CHANC_BCCHComb:
1444 /* allowed only for TS0 of C0 */
1445 if (ts->trx != ts->trx->bts->c0 ||
1446 ts->nr != 0)
1447 return -EINVAL;
1448 break;
1449 case NM_CHANC_BCCH:
1450 /* allowed only for TS 2/4/6 of C0 */
1451 if (ts->trx != ts->trx->bts->c0)
1452 return -EINVAL;
1453 if (ts->nr != 2 && ts->nr != 4 &&
1454 ts->nr != 6)
1455 return -EINVAL;
1456 break;
1457 case 8: /* this is not like 08.58, but in fact
1458 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1459 /* FIXME: only one CBCH allowed per cell */
1460 break;
1461 }
Harald Welted6575f92009-12-02 02:45:23 +05301462 break;
1463 case GSM_BTS_TYPE_NANOBTS:
1464 switch (ts->nr) {
1465 case 0:
1466 if (ts->trx->nr == 0) {
1467 /* only on TRX0 */
1468 switch (chan_comb) {
1469 case NM_CHANC_BCCH:
1470 case NM_CHANC_mainBCCH:
1471 case NM_CHANC_BCCHComb:
1472 return 0;
1473 break;
1474 default:
1475 return -EINVAL;
1476 }
1477 } else {
1478 switch (chan_comb) {
1479 case NM_CHANC_TCHFull:
1480 case NM_CHANC_TCHHalf:
1481 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1482 return 0;
1483 default:
1484 return -EINVAL;
1485 }
1486 }
1487 break;
1488 case 1:
1489 if (ts->trx->nr == 0) {
1490 switch (chan_comb) {
1491 case NM_CHANC_SDCCH_CBCH:
1492 if (ts->trx->ts[0].nm_chan_comb ==
1493 NM_CHANC_mainBCCH)
1494 return 0;
1495 return -EINVAL;
1496 case NM_CHANC_SDCCH:
1497 case NM_CHANC_TCHFull:
1498 case NM_CHANC_TCHHalf:
1499 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1500 case NM_CHANC_IPAC_TCHFull_PDCH:
1501 return 0;
1502 }
1503 } else {
1504 switch (chan_comb) {
1505 case NM_CHANC_SDCCH:
1506 case NM_CHANC_TCHFull:
1507 case NM_CHANC_TCHHalf:
1508 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1509 return 0;
1510 default:
1511 return -EINVAL;
1512 }
1513 }
1514 break;
1515 case 2:
1516 case 3:
1517 case 4:
1518 case 5:
1519 case 6:
1520 case 7:
1521 switch (chan_comb) {
1522 case NM_CHANC_TCHFull:
1523 case NM_CHANC_TCHHalf:
1524 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1525 return 0;
1526 case NM_CHANC_IPAC_PDCH:
1527 case NM_CHANC_IPAC_TCHFull_PDCH:
1528 if (ts->trx->nr == 0)
1529 return 0;
1530 else
1531 return -EINVAL;
1532 }
1533 break;
1534 }
1535 return -EINVAL;
1536 default:
1537 /* unknown BTS type */
1538 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001539 }
1540 return 0;
1541}
1542
Harald Welte22af0db2009-02-14 15:41:08 +00001543/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001544int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001545{
1546 struct gsm_bts *bts = ts->trx->bts;
1547 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001548 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001549 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001550 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00001551
1552 if (bts->type == GSM_BTS_TYPE_BS11)
1553 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001554
Harald Weltef325eb42009-02-19 17:07:39 +00001555 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001556 if (verify_chan_comb(ts, chan_comb) < 0) {
1557 msgb_free(msg);
1558 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1559 return -EINVAL;
1560 }
1561 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001562
Harald Welte52b1f982008-12-23 20:25:15 +00001563 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001564 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001565 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001566 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001567 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001568 if (ts->hopping.enabled) {
1569 unsigned int i;
1570 uint8_t *len;
1571
Harald Welte6e0cd042009-09-12 13:05:33 +02001572 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1573 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001574
1575 /* build the ARFCN list */
1576 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1577 len = msgb_put(msg, 1);
1578 *len = 0;
1579 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1580 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1581 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001582 /* At least BS-11 wants a TLV16 here */
1583 if (bts->type == GSM_BTS_TYPE_BS11)
1584 *len += 1;
1585 else
1586 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001587 }
1588 }
Harald Weltee0590df2009-02-15 03:34:15 +00001589 }
Harald Welte135a6482011-05-30 12:09:13 +02001590 if (ts->tsc == -1)
1591 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1592 else
1593 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001594 if (bts->type == GSM_BTS_TYPE_BS11)
1595 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001596
1597 return abis_nm_sendmsg(bts, msg);
1598}
1599
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001600int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1601 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001602{
1603 struct abis_om_hdr *oh;
1604 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001605 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1606 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001607
1608 if (nack) {
1609 len += 2;
1610 msgtype = NM_MT_SW_ACT_REQ_NACK;
1611 }
Harald Welte34a99682009-02-13 02:41:40 +00001612
1613 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001614 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1615
Harald Welte34a99682009-02-13 02:41:40 +00001616 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001617 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001618 memcpy(ptr, attr, att_len);
1619 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001620 if (nack)
1621 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001622
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001623 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001624}
1625
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001626int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001627{
Harald Welte8470bf22008-12-25 23:28:35 +00001628 struct msgb *msg = nm_msgb_alloc();
1629 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001630 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001631
1632 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1633 fill_om_hdr(oh, len);
1634 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001635 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001636
1637 return abis_nm_sendmsg(bts, msg);
1638}
1639
1640/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001641static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001642{
1643 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001644 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001645
1646 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001647 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001648 0xff, 0xff, 0xff);
1649
1650 return abis_nm_sendmsg(bts, msg);
1651}
1652
Harald Welte34a99682009-02-13 02:41:40 +00001653/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001654int 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 +00001655{
1656 struct abis_om_hdr *oh;
1657 struct msgb *msg = nm_msgb_alloc();
1658
1659 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1660 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1661
Harald Welte15c61722011-05-22 22:45:37 +02001662 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001663 DEBUGPC(DNM, "Sending OPSTART\n");
1664
Harald Welte34a99682009-02-13 02:41:40 +00001665 return abis_nm_sendmsg(bts, msg);
1666}
1667
1668/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001669int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1670 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001671{
1672 struct abis_om_hdr *oh;
1673 struct msgb *msg = nm_msgb_alloc();
1674
1675 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1676 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1677 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1678
1679 return abis_nm_sendmsg(bts, msg);
1680}
1681
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001682int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1683 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001684{
1685 struct abis_om_hdr *oh;
1686 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001687 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001688
1689 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1690 e1_port0, ts0, e1_port1, ts1);
1691
1692 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1693 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1694 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1695
1696 attr = msgb_put(msg, 3);
1697 attr[0] = NM_ATT_MDROP_LINK;
1698 attr[1] = e1_port0;
1699 attr[2] = ts0;
1700
1701 attr = msgb_put(msg, 3);
1702 attr[0] = NM_ATT_MDROP_NEXT;
1703 attr[1] = e1_port1;
1704 attr[2] = ts1;
1705
1706 return abis_nm_sendmsg(bts, msg);
1707}
Harald Welte34a99682009-02-13 02:41:40 +00001708
Harald Weltec7310382009-08-08 00:02:36 +02001709/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001710int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1711 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1712 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001713{
1714 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001715
Harald Welte15c61722011-05-22 22:45:37 +02001716 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001717
1718 if (!msg)
1719 msg = nm_msgb_alloc();
1720
1721 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1722 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1723 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1724 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001725 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001726
1727 return abis_nm_sendmsg(bts, msg);
1728}
1729
Harald Welte52b1f982008-12-23 20:25:15 +00001730int abis_nm_event_reports(struct gsm_bts *bts, int on)
1731{
1732 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001733 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001734 else
Harald Welte227d4072009-01-03 08:16:25 +00001735 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001736}
1737
Harald Welte47d88ae2009-01-04 12:02:08 +00001738/* Siemens (or BS-11) specific commands */
1739
Harald Welte3ffd1372009-02-01 22:15:49 +00001740int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1741{
1742 if (reconnect == 0)
1743 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1744 else
1745 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1746}
1747
Harald Welteb8427972009-02-05 19:27:17 +00001748int abis_nm_bs11_restart(struct gsm_bts *bts)
1749{
1750 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1751}
1752
1753
Harald Welte268bb402009-02-01 19:11:56 +00001754struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001755 uint16_t year;
1756 uint8_t month;
1757 uint8_t day;
1758 uint8_t hour;
1759 uint8_t min;
1760 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001761} __attribute__((packed));
1762
1763
1764void get_bs11_date_time(struct bs11_date_time *aet)
1765{
1766 time_t t;
1767 struct tm *tm;
1768
1769 t = time(NULL);
1770 tm = localtime(&t);
1771 aet->sec = tm->tm_sec;
1772 aet->min = tm->tm_min;
1773 aet->hour = tm->tm_hour;
1774 aet->day = tm->tm_mday;
1775 aet->month = tm->tm_mon;
1776 aet->year = htons(1900 + tm->tm_year);
1777}
1778
Harald Welte05188ee2009-01-18 11:39:08 +00001779int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001780{
Harald Welte4668fda2009-01-03 08:19:29 +00001781 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001782}
1783
Harald Welte05188ee2009-01-18 11:39:08 +00001784int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001785{
1786 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001787 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001788 else
Harald Welte4668fda2009-01-03 08:19:29 +00001789 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001790}
Harald Welte47d88ae2009-01-04 12:02:08 +00001791
Harald Welte05188ee2009-01-18 11:39:08 +00001792int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001793 enum abis_bs11_objtype type, uint8_t idx,
1794 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001795{
1796 struct abis_om_hdr *oh;
1797 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001798 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001799
1800 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001801 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001802 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001803 cur = msgb_put(msg, attr_len);
1804 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001805
1806 return abis_nm_sendmsg(bts, msg);
1807}
1808
Harald Welte78fc0d42009-02-19 02:50:57 +00001809int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001810 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001811{
1812 struct abis_om_hdr *oh;
1813 struct msgb *msg = nm_msgb_alloc();
1814
1815 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1816 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1817 NM_OC_BS11, type, 0, idx);
1818
1819 return abis_nm_sendmsg(bts, msg);
1820}
1821
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001822int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001823{
1824 struct abis_om_hdr *oh;
1825 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001826 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001827
1828 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001829 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001830 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1831 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001832
1833 return abis_nm_sendmsg(bts, msg);
1834}
1835
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001836int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001837{
1838 struct abis_om_hdr *oh;
1839 struct msgb *msg = nm_msgb_alloc();
1840
1841 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1842 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001843 idx, 0xff, 0xff);
1844
1845 return abis_nm_sendmsg(bts, msg);
1846}
1847
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001848int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001849{
1850 struct abis_om_hdr *oh;
1851 struct msgb *msg = nm_msgb_alloc();
1852
1853 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1854 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1855 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001856
1857 return abis_nm_sendmsg(bts, msg);
1858}
Harald Welte05188ee2009-01-18 11:39:08 +00001859
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001860static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001861int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1862{
1863 struct abis_om_hdr *oh;
1864 struct msgb *msg = nm_msgb_alloc();
1865
1866 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1867 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1868 0xff, 0xff, 0xff);
1869 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1870
1871 return abis_nm_sendmsg(bts, msg);
1872}
1873
Harald Welteb6c92ae2009-02-21 20:15:32 +00001874/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001875int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1876 uint8_t e1_timeslot, uint8_t e1_subslot,
1877 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001878{
1879 struct abis_om_hdr *oh;
1880 struct abis_nm_channel *ch;
1881 struct msgb *msg = nm_msgb_alloc();
1882
1883 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001884 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001885 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1886
1887 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1888 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001889 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001890
1891 return abis_nm_sendmsg(bts, msg);
1892}
1893
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001894int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001895{
1896 struct abis_om_hdr *oh;
1897 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001898
1899 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001900 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001901 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1902 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1903
1904 return abis_nm_sendmsg(trx->bts, msg);
1905}
1906
Harald Welte78fc0d42009-02-19 02:50:57 +00001907int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1908{
1909 struct abis_om_hdr *oh;
1910 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001911 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00001912
1913 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1914 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1915 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1916 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1917
1918 return abis_nm_sendmsg(trx->bts, msg);
1919}
1920
Harald Welteaaf02d92009-04-29 13:25:57 +00001921int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1922{
1923 struct abis_om_hdr *oh;
1924 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001925 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00001926
1927 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1928 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1929 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00001930 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00001931
1932 return abis_nm_sendmsg(bts, msg);
1933}
1934
Harald Welteef061952009-05-17 12:43:42 +00001935int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1936{
1937 struct abis_om_hdr *oh;
1938 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001939 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00001940 NM_ATT_BS11_CCLK_TYPE };
1941
1942 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1943 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1944 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1945 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1946
1947 return abis_nm_sendmsg(bts, msg);
1948
1949}
Harald Welteaaf02d92009-04-29 13:25:57 +00001950
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001951//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00001952
Harald Welte1bc09062009-01-18 14:17:52 +00001953int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00001954{
Daniel Willmann493db4e2010-01-07 00:43:11 +01001955 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1956}
1957
Daniel Willmann4b054c82010-01-07 00:46:26 +01001958int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1959{
1960 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1961}
1962
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001963int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001964{
Harald Welte05188ee2009-01-18 11:39:08 +00001965 struct abis_om_hdr *oh;
1966 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00001967 struct bs11_date_time bdt;
1968
1969 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00001970
1971 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00001972 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001973 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001974 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00001975 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001976 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00001977 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001978 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00001979 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01001980 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00001981 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001982 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00001983 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00001984 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001985 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00001986 }
Harald Welte05188ee2009-01-18 11:39:08 +00001987
1988 return abis_nm_sendmsg(bts, msg);
1989}
Harald Welte1bc09062009-01-18 14:17:52 +00001990
1991int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
1992{
1993 struct abis_om_hdr *oh;
1994 struct msgb *msg;
1995
1996 if (strlen(password) != 10)
1997 return -EINVAL;
1998
1999 msg = nm_msgb_alloc();
2000 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002001 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002002 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002003 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002004
2005 return abis_nm_sendmsg(bts, msg);
2006}
2007
Harald Weltee69f5fb2009-04-28 16:31:38 +00002008/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2009int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2010{
2011 struct abis_om_hdr *oh;
2012 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002013 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002014
2015 msg = nm_msgb_alloc();
2016 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2017 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2018 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002019
2020 if (locked)
2021 tlv_value = BS11_LI_PLL_LOCKED;
2022 else
2023 tlv_value = BS11_LI_PLL_STANDALONE;
2024
2025 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002026
2027 return abis_nm_sendmsg(bts, msg);
2028}
2029
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002030/* Set the calibration value of the PLL (work value/set value)
2031 * It depends on the login which one is changed */
2032int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2033{
2034 struct abis_om_hdr *oh;
2035 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002036 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002037
2038 msg = nm_msgb_alloc();
2039 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2040 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2041 BS11_OBJ_TRX1, 0x00, 0x00);
2042
2043 tlv_value[0] = value>>8;
2044 tlv_value[1] = value&0xff;
2045
2046 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2047
2048 return abis_nm_sendmsg(bts, msg);
2049}
2050
Harald Welte1bc09062009-01-18 14:17:52 +00002051int abis_nm_bs11_get_state(struct gsm_bts *bts)
2052{
2053 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2054}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002055
2056/* BS11 SWL */
2057
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002058void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002059
Harald Welte5e4d1b32009-02-01 13:36:56 +00002060struct abis_nm_bs11_sw {
2061 struct gsm_bts *bts;
2062 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002063 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002064 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002065 struct llist_head file_list;
2066 gsm_cbfn *user_cb; /* specified by the user */
2067};
2068static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2069
2070struct file_list_entry {
2071 struct llist_head list;
2072 char fname[PATH_MAX];
2073};
2074
2075struct file_list_entry *fl_dequeue(struct llist_head *queue)
2076{
2077 struct llist_head *lh;
2078
2079 if (llist_empty(queue))
2080 return NULL;
2081
2082 lh = queue->next;
2083 llist_del(lh);
2084
2085 return llist_entry(lh, struct file_list_entry, list);
2086}
2087
2088static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2089{
2090 char linebuf[255];
2091 struct llist_head *lh, *lh2;
2092 FILE *swl;
2093 int rc = 0;
2094
2095 swl = fopen(bs11_sw->swl_fname, "r");
2096 if (!swl)
2097 return -ENODEV;
2098
2099 /* zero the stale file list, if any */
2100 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2101 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002102 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002103 }
2104
2105 while (fgets(linebuf, sizeof(linebuf), swl)) {
2106 char file_id[12+1];
2107 char file_version[80+1];
2108 struct file_list_entry *fle;
2109 static char dir[PATH_MAX];
2110
2111 if (strlen(linebuf) < 4)
2112 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002113
Harald Welte5e4d1b32009-02-01 13:36:56 +00002114 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2115 if (rc < 0) {
2116 perror("ERR parsing SWL file");
2117 rc = -EINVAL;
2118 goto out;
2119 }
2120 if (rc < 2)
2121 continue;
2122
Harald Welte470ec292009-06-26 20:25:23 +02002123 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002124 if (!fle) {
2125 rc = -ENOMEM;
2126 goto out;
2127 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002128
2129 /* construct new filename */
2130 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2131 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2132 strcat(fle->fname, "/");
2133 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002134
2135 llist_add_tail(&fle->list, &bs11_sw->file_list);
2136 }
2137
2138out:
2139 fclose(swl);
2140 return rc;
2141}
2142
2143/* bs11 swload specific callback, passed to abis_nm core swload */
2144static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2145 struct msgb *msg, void *data, void *param)
2146{
2147 struct abis_nm_bs11_sw *bs11_sw = data;
2148 struct file_list_entry *fle;
2149 int rc = 0;
2150
Harald Welte5e4d1b32009-02-01 13:36:56 +00002151 switch (event) {
2152 case NM_MT_LOAD_END_ACK:
2153 fle = fl_dequeue(&bs11_sw->file_list);
2154 if (fle) {
2155 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002156 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002157 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002158 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002159 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002160 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002161 } else {
2162 /* activate the SWL */
2163 rc = abis_nm_software_activate(bs11_sw->bts,
2164 bs11_sw->swl_fname,
2165 bs11_swload_cbfn,
2166 bs11_sw);
2167 }
2168 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002169 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002170 case NM_MT_LOAD_END_NACK:
2171 case NM_MT_LOAD_INIT_ACK:
2172 case NM_MT_LOAD_INIT_NACK:
2173 case NM_MT_ACTIVATE_SW_NACK:
2174 case NM_MT_ACTIVATE_SW_ACK:
2175 default:
2176 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002177 if (bs11_sw->user_cb)
2178 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002179 break;
2180 }
2181
2182 return rc;
2183}
2184
2185/* Siemens provides a SWL file that is a mere listing of all the other
2186 * files that are part of a software release. We need to upload first
2187 * the list file, and then each file that is listed in the list file */
2188int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002189 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002190{
2191 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2192 struct file_list_entry *fle;
2193 int rc = 0;
2194
2195 INIT_LLIST_HEAD(&bs11_sw->file_list);
2196 bs11_sw->bts = bts;
2197 bs11_sw->win_size = win_size;
2198 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002199 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002200
2201 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2202 rc = bs11_read_swl_file(bs11_sw);
2203 if (rc < 0)
2204 return rc;
2205
2206 /* dequeue next item in file list */
2207 fle = fl_dequeue(&bs11_sw->file_list);
2208 if (!fle)
2209 return -EINVAL;
2210
2211 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002212 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002213 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002214 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002215 return rc;
2216}
2217
Harald Welte5083b0b2009-02-02 19:20:52 +00002218#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002219static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002220 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2221 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2222 NM_ATT_BS11_LMT_USER_NAME,
2223
2224 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2225
2226 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2227
2228 NM_ATT_BS11_SW_LOAD_STORED };
2229
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002230static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002231 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2232 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2233 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2234 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002235#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002236
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002237static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002238 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2239 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002240 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002241
2242int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2243{
2244 struct abis_om_hdr *oh;
2245 struct msgb *msg = nm_msgb_alloc();
2246
2247 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2248 /* SiemensHW CCTRL object */
2249 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2250 0x03, 0x00, 0x00);
2251 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2252
2253 return abis_nm_sendmsg(bts, msg);
2254}
Harald Welte268bb402009-02-01 19:11:56 +00002255
2256int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2257{
2258 struct abis_om_hdr *oh;
2259 struct msgb *msg = nm_msgb_alloc();
2260 struct bs11_date_time aet;
2261
2262 get_bs11_date_time(&aet);
2263 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2264 /* SiemensHW CCTRL object */
2265 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2266 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002267 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002268
2269 return abis_nm_sendmsg(bts, msg);
2270}
Harald Welte5c1e4582009-02-15 11:57:29 +00002271
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002272int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002273{
2274 struct abis_om_hdr *oh;
2275 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002276 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002277
2278 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2279 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2280 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2281 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2282
2283 return abis_nm_sendmsg(bts, msg);
2284}
2285
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002286int 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 +02002287{
2288 struct abis_om_hdr *oh;
2289 struct msgb *msg = nm_msgb_alloc();
2290 struct bs11_date_time aet;
2291
2292 get_bs11_date_time(&aet);
2293 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2294 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2295 bport, 0xff, 0x02);
2296 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2297
2298 return abis_nm_sendmsg(bts, msg);
2299}
2300
Harald Welte5c1e4582009-02-15 11:57:29 +00002301/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002302static const char ipaccess_magic[] = "com.ipaccess";
2303
Harald Welte677c21f2009-02-17 13:22:23 +00002304
2305static int abis_nm_rx_ipacc(struct msgb *msg)
2306{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002307 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002308 struct abis_om_hdr *oh = msgb_l2(msg);
2309 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002310 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002311 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002312 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002313 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002314
2315 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002316 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002317 return -EINVAL;
2318 }
2319
Harald Welte193fefc2009-04-30 15:16:27 +00002320 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002321 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002322
Harald Welte15c61722011-05-22 22:45:37 +02002323 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002324
Harald Welte746d6092009-10-19 22:11:11 +02002325 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002326
Harald Welte677c21f2009-02-17 13:22:23 +00002327 switch (foh->msg_type) {
2328 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002329 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002330 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2331 memcpy(&addr,
2332 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2333
2334 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2335 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002336 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002337 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002338 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002339 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002340 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2341 DEBUGPC(DNM, "STREAM=0x%02x ",
2342 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002343 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002344 break;
2345 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002346 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002347 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002348 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002349 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002350 else
2351 DEBUGPC(DNM, "\n");
2352 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002353 case NM_MT_IPACC_SET_NVATTR_ACK:
2354 DEBUGPC(DNM, "SET NVATTR ACK\n");
2355 /* FIXME: decode and show the actual attributes */
2356 break;
2357 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002358 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002359 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002360 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002361 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002362 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002363 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002364 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002365 case NM_MT_IPACC_GET_NVATTR_ACK:
2366 DEBUGPC(DNM, "GET NVATTR ACK\n");
2367 /* FIXME: decode and show the actual attributes */
2368 break;
2369 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002370 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002371 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002372 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002373 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002374 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002375 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002376 break;
Harald Welte15c44172009-10-08 20:15:24 +02002377 case NM_MT_IPACC_SET_ATTR_ACK:
2378 DEBUGPC(DNM, "SET ATTR ACK\n");
2379 break;
2380 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002381 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002382 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002383 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002384 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002385 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002386 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002387 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002388 default:
2389 DEBUGPC(DNM, "unknown\n");
2390 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002391 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002392
2393 /* signal handling */
2394 switch (foh->msg_type) {
2395 case NM_MT_IPACC_RSL_CONNECT_NACK:
2396 case NM_MT_IPACC_SET_NVATTR_NACK:
2397 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002398 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 +01002399 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002400 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002401 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002402 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002403 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 +01002404 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002405 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002406 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002407 default:
2408 break;
2409 }
2410
Harald Welte677c21f2009-02-17 13:22:23 +00002411 return 0;
2412}
2413
Harald Welte193fefc2009-04-30 15:16:27 +00002414/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002415int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2416 uint8_t obj_class, uint8_t bts_nr,
2417 uint8_t trx_nr, uint8_t ts_nr,
2418 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002419{
2420 struct msgb *msg = nm_msgb_alloc();
2421 struct abis_om_hdr *oh;
2422 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002423 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002424
2425 /* construct the 12.21 OM header, observe the erroneous length */
2426 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2427 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2428 oh->mdisc = ABIS_OM_MDISC_MANUF;
2429
2430 /* add the ip.access magic */
2431 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2432 *data++ = sizeof(ipaccess_magic);
2433 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2434
2435 /* fill the 12.21 FOM header */
2436 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2437 foh->msg_type = msg_type;
2438 foh->obj_class = obj_class;
2439 foh->obj_inst.bts_nr = bts_nr;
2440 foh->obj_inst.trx_nr = trx_nr;
2441 foh->obj_inst.ts_nr = ts_nr;
2442
2443 if (attr && attr_len) {
2444 data = msgb_put(msg, attr_len);
2445 memcpy(data, attr, attr_len);
2446 }
2447
2448 return abis_nm_sendmsg(bts, msg);
2449}
Harald Welte677c21f2009-02-17 13:22:23 +00002450
Harald Welte193fefc2009-04-30 15:16:27 +00002451/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002452int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002453 int attr_len)
2454{
Harald Welte2ef156d2010-01-07 20:39:42 +01002455 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2456 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002457 attr_len);
2458}
2459
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002460int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002461 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002462{
2463 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002464 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002465 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2466 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2467
2468 int attr_len = sizeof(attr);
2469
2470 ia.s_addr = htonl(ip);
2471 attr[1] = stream;
2472 attr[3] = port >> 8;
2473 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002474 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002475
2476 /* if ip == 0, we use the default IP */
2477 if (ip == 0)
2478 attr_len -= 5;
2479
2480 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002481 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002482
2483 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2484 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2485 trx->nr, 0xff, attr, attr_len);
2486}
2487
Harald Welte193fefc2009-04-30 15:16:27 +00002488/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002489int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002490{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002491 struct abis_om_hdr *oh;
2492 struct msgb *msg = nm_msgb_alloc();
2493
2494 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2495 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2496 trx->bts->nr, trx->nr, 0xff);
2497
2498 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002499}
Harald Weltedaef5212009-10-24 10:20:41 +02002500
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002501int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2502 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2503 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002504{
2505 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2506 obj_class, bts_nr, trx_nr, ts_nr,
2507 attr, attr_len);
2508}
Harald Welte0f255852009-11-12 14:48:42 +01002509
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002510void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002511{
2512 /* we simply reuse the GSM48 function and overwrite the RAC
2513 * with the Cell ID */
2514 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002515 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002516}
2517
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002518void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2519{
2520 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2521
Harald Welted64c0bc2011-05-30 12:07:53 +02002522 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002523 if (!trx->bts || !trx->bts->oml_link)
2524 return;
2525
2526 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2527 trx->bts->bts_nr, trx->nr, 0xff,
2528 new_state);
2529}
2530
Harald Welte92b1fe42010-03-25 11:45:30 +08002531static const struct value_string ipacc_testres_names[] = {
2532 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2533 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2534 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2535 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2536 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2537 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002538};
2539
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002540const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002541{
Harald Welte92b1fe42010-03-25 11:45:30 +08002542 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002543}
2544
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002545void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002546{
2547 cid->mcc = (buf[0] & 0xf) * 100;
2548 cid->mcc += (buf[0] >> 4) * 10;
2549 cid->mcc += (buf[1] & 0xf) * 1;
2550
2551 if (buf[1] >> 4 == 0xf) {
2552 cid->mnc = (buf[2] & 0xf) * 10;
2553 cid->mnc += (buf[2] >> 4) * 1;
2554 } else {
2555 cid->mnc = (buf[2] & 0xf) * 100;
2556 cid->mnc += (buf[2] >> 4) * 10;
2557 cid->mnc += (buf[1] >> 4) * 1;
2558 }
2559
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002560 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2561 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002562}
2563
Harald Welte0f255852009-11-12 14:48:42 +01002564/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002565int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002566{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002567 uint8_t *cur = buf;
2568 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01002569
Harald Welteaf109b92010-07-22 18:14:36 +02002570 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002571
2572 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2573 return -EINVAL;
2574 cur++;
2575
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002576 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002577 cur += 2;
2578
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002579 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002580 cur += 2;
2581
2582 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2583 binf->freq_qual = *cur >> 2;
2584
Harald Welteaf109b92010-07-22 18:14:36 +02002585 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002586 binf->arfcn |= *cur++;
2587
2588 if (binf->info_type & IPAC_BINF_RXLEV)
2589 binf->rx_lev = *cur & 0x3f;
2590 cur++;
2591
2592 if (binf->info_type & IPAC_BINF_RXQUAL)
2593 binf->rx_qual = *cur & 0x7;
2594 cur++;
2595
2596 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002597 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002598 cur += 2;
2599
2600 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002601 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002602 cur += 2;
2603
2604 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002605 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002606 cur += 4;
2607
Harald Weltea780a3d2010-07-30 22:34:42 +02002608#if 0
2609 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002610 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002611#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002612 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002613 cur++;
2614
Harald Welteb40a38f2009-11-13 11:56:05 +01002615 ipac_parse_cgi(&binf->cgi, cur);
2616 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002617
2618 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2619 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2620 cur += sizeof(binf->ba_list_si2);
2621 }
2622
2623 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2624 memcpy(binf->ba_list_si2bis, cur,
2625 sizeof(binf->ba_list_si2bis));
2626 cur += sizeof(binf->ba_list_si2bis);
2627 }
2628
2629 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2630 memcpy(binf->ba_list_si2ter, cur,
2631 sizeof(binf->ba_list_si2ter));
2632 cur += sizeof(binf->ba_list_si2ter);
2633 }
2634
2635 return 0;
2636}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002637
2638void abis_nm_clear_queue(struct gsm_bts *bts)
2639{
2640 struct msgb *msg;
2641
2642 while (!llist_empty(&bts->abis_queue)) {
2643 msg = msgb_dequeue(&bts->abis_queue);
2644 msgb_free(msg);
2645 }
2646
2647 bts->abis_nm_pend = 0;
2648}