blob: 4fd11c703b59e1497e665ae761e1ea39ff357376 [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000043#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte52b1f982008-12-23 20:25:15 +000047
Harald Welte8470bf22008-12-25 23:28:35 +000048#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000051
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020052int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +000053{
Harald Welte39315c42010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000057}
Harald Weltee0590df2009-02-15 03:34:15 +000058
Harald Welte52b1f982008-12-23 20:25:15 +000059static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
Holger Freytherca362a62009-01-04 21:05:01 +000071#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000072/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
Holger Freytherca362a62009-01-04 21:05:01 +000077#endif
Harald Welte52b1f982008-12-23 20:25:15 +000078
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Welte15c61722011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +000099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
Harald Welte702d8702008-12-26 20:25:35 +0000103 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
109}
110
Harald Welte8470bf22008-12-25 23:28:35 +0000111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte966636f2009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000115}
116
Harald Welte15eae8d2011-09-26 23:43:23 +0200117int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200118{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200119 msg->l2h = msg->data;
120
121 if (!msg->dst) {
122 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
123 return -EINVAL;
124 }
125
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200126 return abis_sendmsg(msg);
127}
128
Harald Welte52b1f982008-12-23 20:25:15 +0000129/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100130static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000131{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200132 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000133
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100134 /* queue OML messages */
135 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
136 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200137 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100138 } else {
139 msgb_enqueue(&bts->abis_queue, msg);
140 return 0;
141 }
142
143}
144
145int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
146{
147 OBSC_NM_W_ACK_CB(msg) = 1;
148 return abis_nm_queue_msg(bts, msg);
149}
150
151static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
152{
153 OBSC_NM_W_ACK_CB(msg) = 0;
154 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000155}
156
Harald Welte4724f992009-01-18 18:01:49 +0000157static int abis_nm_rcvmsg_sw(struct msgb *mb);
158
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100159int nm_is_running(struct gsm_nm_state *s) {
160 return (s->operational == NM_OPSTATE_ENABLED) && (
161 (s->availability == NM_AVSTATE_OK) ||
162 (s->availability == 0xff)
163 );
164}
165
Harald Weltee0590df2009-02-15 03:34:15 +0000166/* Update the administrative state of a given object in our in-memory data
167 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200168static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
169 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000170{
Harald Welteaeedeb42009-05-01 13:08:14 +0000171 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100172 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000173
Harald Welteaf9b8102011-03-06 21:20:38 +0100174 memset(&nsd, 0, sizeof(nsd));
175
Harald Welte978714d2011-06-06 18:31:20 +0200176 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100177 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100178 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200179 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000180 if (!nm_state)
181 return -1;
182
183 new_state = *nm_state;
184 new_state.administrative = adm_state;
185
Harald Weltef38ca9a2011-03-06 22:11:32 +0100186 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100187 nsd.obj_class = obj_class;
188 nsd.old_state = nm_state;
189 nsd.new_state = &new_state;
190 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200191 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000192
193 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000194
Harald Weltef338a032011-01-14 15:55:42 +0100195 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000196}
197
Harald Welte97ed1e72009-02-06 13:38:02 +0000198static int abis_nm_rx_statechg_rep(struct msgb *mb)
199{
Harald Weltee0590df2009-02-15 03:34:15 +0000200 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000201 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200202 struct e1inp_sign_link *sign_link = mb->dst;
203 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000204 struct tlv_parsed tp;
205 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000206
Harald Welte23897662009-05-01 14:52:51 +0000207 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000208
Harald Welte8b697c72009-06-05 19:18:45 +0000209 memset(&new_state, 0, sizeof(new_state));
210
Harald Welte978714d2011-06-06 18:31:20 +0200211 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000212 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100213 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000214 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000215 }
Harald Weltee0590df2009-02-15 03:34:15 +0000216
217 new_state = *nm_state;
218
Harald Welte39315c42010-01-10 18:01:52 +0100219 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000220 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
221 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200222 DEBUGPC(DNM, "OP_STATE=%s ",
223 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000224 }
225 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000226 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
227 new_state.availability = 0xff;
228 else
229 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
231 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000232 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100233 } else
234 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000235 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
236 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200237 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200238 get_value_string(abis_nm_adm_state_names,
239 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000240 }
241 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000242
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100243 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
244 new_state.operational != nm_state->operational ||
245 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000246 /* Update the operational state of a given object in our in-memory data
247 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100248 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200249 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100250 nsd.obj_class = foh->obj_class;
251 nsd.old_state = nm_state;
252 nsd.new_state = &new_state;
253 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100254 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200255 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100256 nm_state->operational = new_state.operational;
257 nm_state->availability = new_state.availability;
258 if (nm_state->administrative == 0)
259 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000260 }
261#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000262 if (op_state == 1) {
263 /* try to enable objects that are disabled */
264 abis_nm_opstart(bts, foh->obj_class,
265 foh->obj_inst.bts_nr,
266 foh->obj_inst.trx_nr,
267 foh->obj_inst.ts_nr);
268 }
Harald Weltee0590df2009-02-15 03:34:15 +0000269#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000270 return 0;
271}
272
Harald Welte0db97b22009-05-01 17:22:47 +0000273static int rx_fail_evt_rep(struct msgb *mb)
274{
275 struct abis_om_hdr *oh = msgb_l2(mb);
276 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200277 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000278 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100279 const uint8_t *p_val;
280 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000281
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200282 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000283
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200284 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000285
286 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200287 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
288 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000289 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200290 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
291 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100292 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
293 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200294 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100295 }
296 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
297 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
298 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
299 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200300 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100301 talloc_free(p_text);
302 }
303 }
Harald Welte0db97b22009-05-01 17:22:47 +0000304
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200305 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000306
307 return 0;
308}
309
Harald Welte97ed1e72009-02-06 13:38:02 +0000310static int abis_nm_rcvmsg_report(struct msgb *mb)
311{
312 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200313 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000314
Harald Welte15c61722011-05-22 22:45:37 +0200315 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000316
Harald Welte97ed1e72009-02-06 13:38:02 +0000317 //nmh->cfg->report_cb(mb, foh);
318
319 switch (mt) {
320 case NM_MT_STATECHG_EVENT_REP:
321 return abis_nm_rx_statechg_rep(mb);
322 break;
Harald Welte34a99682009-02-13 02:41:40 +0000323 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000324 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200325 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000326 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000327 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000328 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200329 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000330 break;
Harald Weltec7310382009-08-08 00:02:36 +0200331 case NM_MT_TEST_REP:
332 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200334 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000335 default:
Harald Welte23897662009-05-01 14:52:51 +0000336 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000337 break;
338
Harald Welte97ed1e72009-02-06 13:38:02 +0000339 };
340
Harald Welte97ed1e72009-02-06 13:38:02 +0000341 return 0;
342}
343
Harald Welte34a99682009-02-13 02:41:40 +0000344/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200345static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
346 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000347{
348 struct abis_om_hdr *oh;
349 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200350 uint8_t len = swdesc_len;
351 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000352
353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
354 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
355
356 trailer = msgb_put(msg, swdesc_len);
357 memcpy(trailer, sw_desc, swdesc_len);
358
359 return abis_nm_sendmsg(bts, msg);
360}
361
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200362static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100363{
364 static const struct tlv_definition sw_descr_def = {
365 .def = {
366 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
367 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
368 },
369 };
370
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200371 uint8_t tag;
372 uint16_t tag_len;
373 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100374 int ofs = 0, len;
375
376 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
377 * nested nature and the fact you have to assume it contains only two sub
378 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
379
380 if (sw_descr[0] != NM_ATT_SW_DESCR) {
381 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
382 return -1;
383 }
384 ofs += 1;
385
386 len = tlv_parse_one(&tag, &tag_len, &val,
387 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
388 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
389 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
390 return -2;
391 }
392 ofs += len;
393
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
396 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
397 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
398 return -3;
399 }
400 ofs += len;
401
402 return ofs;
403}
404
Harald Welte34a99682009-02-13 02:41:40 +0000405static int abis_nm_rx_sw_act_req(struct msgb *mb)
406{
407 struct abis_om_hdr *oh = msgb_l2(mb);
408 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200409 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200410 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200411 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100412 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000413
Harald Welte15c61722011-05-22 22:45:37 +0200414 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200415
416 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000417
Harald Welte97a282b2010-03-14 15:37:43 +0800418 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000419
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200420 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000421 foh->obj_inst.bts_nr,
422 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800423 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000424 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100425 if (ret != 0) {
426 LOGP(DNM, LOGL_ERROR,
427 "Sending SW ActReq ACK failed: %d\n", ret);
428 return ret;
429 }
Harald Welte34a99682009-02-13 02:41:40 +0000430
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200431 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200432 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
433 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
434 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100435 LOGP(DNM, LOGL_ERROR,
436 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200437 return -EINVAL;
438 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200439 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200440 }
441
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100442 /* Use the first SW_DESCR present in SW config */
443 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
444 if (sw_descr_len < 0)
445 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200446
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200447 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000448 foh->obj_inst.bts_nr,
449 foh->obj_inst.trx_nr,
450 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100451 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000452}
453
Harald Weltee0590df2009-02-15 03:34:15 +0000454/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
455static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
456{
457 struct abis_om_hdr *oh = msgb_l2(mb);
458 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200459 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000460 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200461 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000462
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200463 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000464 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
465 return -EINVAL;
466
467 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
468
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200469 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000470}
471
Harald Welteee670472009-02-22 21:58:49 +0000472static int abis_nm_rx_lmt_event(struct msgb *mb)
473{
474 struct abis_om_hdr *oh = msgb_l2(mb);
475 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200476 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000477 struct tlv_parsed tp;
478
479 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200480 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000481 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
482 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200483 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000484 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
485 }
486 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
487 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200488 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000489 DEBUGPC(DNM, "Level=%u ", level);
490 }
491 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
492 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
493 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
494 DEBUGPC(DNM, "Username=%s ", name);
495 }
496 DEBUGPC(DNM, "\n");
497 /* FIXME: parse LMT LOGON TIME */
498 return 0;
499}
500
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200501void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100502{
503 int wait = 0;
504 struct msgb *msg;
505 /* the queue is empty */
506 while (!llist_empty(&bts->abis_queue)) {
507 msg = msgb_dequeue(&bts->abis_queue);
508 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200509 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100510
511 if (wait)
512 break;
513 }
514
515 bts->abis_nm_pend = wait;
516}
517
Harald Welte52b1f982008-12-23 20:25:15 +0000518/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000519static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000520{
Harald Welte6c96ba52009-05-01 13:03:40 +0000521 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000522 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200523 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200524 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100525 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000526
527 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000528 if (is_report(mt))
529 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000530
Harald Welte15c61722011-05-22 22:45:37 +0200531 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000532 return abis_nm_rcvmsg_sw(mb);
533
Harald Welte15c61722011-05-22 22:45:37 +0200534 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800535 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000536 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200537
Harald Welte15c61722011-05-22 22:45:37 +0200538 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200539
Harald Welte15c61722011-05-22 22:45:37 +0200540 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000541
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200542 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000543 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200544 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200545 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000546 else
547 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200548
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800549 nack_data.msg = mb;
550 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200551 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200552 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200553 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000554 }
Harald Weltead384642008-12-26 10:20:07 +0000555#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000556 /* check if last message is to be acked */
557 if (is_ack_nack(nmh->last_msgtype)) {
558 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100559 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000560 /* we got our ACK, continue sending the next msg */
561 } else if (mt == MT_NACK(nmh->last_msgtype)) {
562 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100563 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000564 /* FIXME: somehow signal this to the caller */
565 } else {
566 /* really strange things happen */
567 return -EINVAL;
568 }
569 }
Harald Weltead384642008-12-26 10:20:07 +0000570#endif
571
Harald Welte97ed1e72009-02-06 13:38:02 +0000572 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000573 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100574 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000575 break;
Harald Welte34a99682009-02-13 02:41:40 +0000576 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100577 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000578 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000579 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100580 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000581 break;
Harald Welte1989c082009-08-06 17:58:31 +0200582 case NM_MT_CONN_MDROP_LINK_ACK:
583 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
584 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100585 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200586 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100587 break;
588 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200589 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100590 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100591 case NM_MT_SET_BTS_ATTR_ACK:
592 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200593 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
594 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Weltefd355a32011-03-04 13:41:31 +0100595 }
596 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000597 }
598
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200599 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100600 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000601}
602
Harald Welte677c21f2009-02-17 13:22:23 +0000603static int abis_nm_rx_ipacc(struct msgb *mb);
604
605static int abis_nm_rcvmsg_manuf(struct msgb *mb)
606{
607 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200608 struct e1inp_sign_link *sign_link = mb->dst;
609 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000610
611 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100612 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200613 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000614 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200615 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000616 break;
617 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100618 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
619 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000620 rc = 0;
621 break;
622 }
623
624 return rc;
625}
626
Harald Welte52b1f982008-12-23 20:25:15 +0000627/* High-Level API */
628/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000629int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000630{
Harald Welte52b1f982008-12-23 20:25:15 +0000631 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000632 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000633
634 /* Various consistency checks */
635 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100636 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000637 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200638 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
639 rc = -EINVAL;
640 goto err;
641 }
Harald Welte52b1f982008-12-23 20:25:15 +0000642 }
643 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100644 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000645 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200646 rc = -EINVAL;
647 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000648 }
Harald Welte702d8702008-12-26 20:25:35 +0000649#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200650 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000651 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000652 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100653 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000654 oh->length + sizeof(*oh), l2_len);
655 return -EINVAL;
656 }
Harald Welte702d8702008-12-26 20:25:35 +0000657 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100658 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 +0000659#endif
Harald Weltead384642008-12-26 10:20:07 +0000660 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000661
662 switch (oh->mdisc) {
663 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000664 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000665 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000666 case ABIS_OM_MDISC_MANUF:
667 rc = abis_nm_rcvmsg_manuf(msg);
668 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000669 case ABIS_OM_MDISC_MMI:
670 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100671 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000672 oh->mdisc);
673 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000674 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100675 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000676 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200677 rc = -EINVAL;
678 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000679 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200680err:
Harald Weltead384642008-12-26 10:20:07 +0000681 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000682 return rc;
683}
684
685#if 0
686/* initialized all resources */
687struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
688{
689 struct abis_nm_h *nmh;
690
691 nmh = malloc(sizeof(*nmh));
692 if (!nmh)
693 return NULL;
694
695 nmh->cfg = cfg;
696
697 return nmh;
698}
699
700/* free all resources */
701void abis_nm_fini(struct abis_nm_h *nmh)
702{
703 free(nmh);
704}
705#endif
706
707/* Here we are trying to define a high-level API that can be used by
708 * the actual BSC implementation. However, the architecture is currently
709 * still under design. Ideally the calls to this API would be synchronous,
710 * while the underlying stack behind the APi runs in a traditional select
711 * based state machine.
712 */
713
Harald Welte4724f992009-01-18 18:01:49 +0000714/* 6.2 Software Load: */
715enum sw_state {
716 SW_STATE_NONE,
717 SW_STATE_WAIT_INITACK,
718 SW_STATE_WAIT_SEGACK,
719 SW_STATE_WAIT_ENDACK,
720 SW_STATE_WAIT_ACTACK,
721 SW_STATE_ERROR,
722};
Harald Welte52b1f982008-12-23 20:25:15 +0000723
Harald Welte52b1f982008-12-23 20:25:15 +0000724struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000725 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800726 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000727 gsm_cbfn *cbfn;
728 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000729 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000730
Harald Welte52b1f982008-12-23 20:25:15 +0000731 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200732 uint8_t obj_class;
733 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000734
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200735 uint8_t file_id[255];
736 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000737
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200738 uint8_t file_version[255];
739 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000740
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200741 uint8_t window_size;
742 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000743
744 int fd;
745 FILE *stream;
746 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000747 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000748};
749
Harald Welte4724f992009-01-18 18:01:49 +0000750static struct abis_nm_sw g_sw;
751
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100752static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
753{
754 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
755 msgb_v_put(msg, NM_ATT_SW_DESCR);
756 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
757 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
758 sw->file_version);
759 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
760 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
761 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
762 sw->file_version);
763 } else {
764 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
765 }
766}
767
Harald Welte4724f992009-01-18 18:01:49 +0000768/* 6.2.1 / 8.3.1: Load Data Initiate */
769static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000770{
Harald Welte4724f992009-01-18 18:01:49 +0000771 struct abis_om_hdr *oh;
772 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200773 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000774
775 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
776 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
777 sw->obj_instance[0], sw->obj_instance[1],
778 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100779
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100780 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000781 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
782
783 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000784}
785
Harald Welte1602ade2009-01-29 21:12:39 +0000786static int is_last_line(FILE *stream)
787{
788 char next_seg_buf[256];
789 long pos;
790
791 /* check if we're sending the last line */
792 pos = ftell(stream);
793 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
794 fseek(stream, pos, SEEK_SET);
795 return 1;
796 }
797
798 fseek(stream, pos, SEEK_SET);
799 return 0;
800}
801
Harald Welte4724f992009-01-18 18:01:49 +0000802/* 6.2.2 / 8.3.2 Load Data Segment */
803static int sw_load_segment(struct abis_nm_sw *sw)
804{
805 struct abis_om_hdr *oh;
806 struct msgb *msg = nm_msgb_alloc();
807 char seg_buf[256];
808 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000809 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200810 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000811
812 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000813
814 switch (sw->bts->type) {
815 case GSM_BTS_TYPE_BS11:
816 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
817 perror("fgets reading segment");
818 return -EINVAL;
819 }
820 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000821
822 /* check if we're sending the last line */
823 sw->last_seg = is_last_line(sw->stream);
824 if (sw->last_seg)
825 seg_buf[1] = 0;
826 else
827 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000828
829 len = strlen(line_buf) + 2;
830 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200831 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000832 /* BS11 wants CR + LF in excess of the TLV length !?! */
833 tlv[1] -= 2;
834
835 /* we only now know the exact length for the OM hdr */
836 len = strlen(line_buf)+2;
837 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100838 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200839 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100840 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
841 if (len < 0) {
842 perror("read failed");
843 return -EINVAL;
844 }
845
846 if (len != IPACC_SEGMENT_SIZE)
847 sw->last_seg = 1;
848
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100849 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200850 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100851 len += 3;
852 break;
853 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000854 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100855 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000856 /* FIXME: Other BTS types */
857 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000858 }
Harald Welte4724f992009-01-18 18:01:49 +0000859
Harald Welte4724f992009-01-18 18:01:49 +0000860 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
861 sw->obj_instance[0], sw->obj_instance[1],
862 sw->obj_instance[2]);
863
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100864 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000865}
866
867/* 6.2.4 / 8.3.4 Load Data End */
868static int sw_load_end(struct abis_nm_sw *sw)
869{
870 struct abis_om_hdr *oh;
871 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200872 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000873
874 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
875 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
876 sw->obj_instance[0], sw->obj_instance[1],
877 sw->obj_instance[2]);
878
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100879 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000880 return abis_nm_sendmsg(sw->bts, msg);
881}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000882
Harald Welte52b1f982008-12-23 20:25:15 +0000883/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000884static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000885{
Harald Welte4724f992009-01-18 18:01:49 +0000886 struct abis_om_hdr *oh;
887 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200888 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000889
Harald Welte4724f992009-01-18 18:01:49 +0000890 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
891 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
892 sw->obj_instance[0], sw->obj_instance[1],
893 sw->obj_instance[2]);
894
895 /* FIXME: this is BS11 specific format */
896 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
897 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
898 sw->file_version);
899
900 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000901}
Harald Welte4724f992009-01-18 18:01:49 +0000902
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100903struct sdp_firmware {
904 char magic[4];
905 char more_magic[4];
906 unsigned int header_length;
907 unsigned int file_length;
908} __attribute__ ((packed));
909
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100910static int parse_sdp_header(struct abis_nm_sw *sw)
911{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100912 struct sdp_firmware firmware_header;
913 int rc;
914 struct stat stat;
915
916 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
917 if (rc != sizeof(firmware_header)) {
918 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
919 return -1;
920 }
921
922 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
923 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
924 return -1;
925 }
926
927 if (firmware_header.more_magic[0] != 0x10 ||
928 firmware_header.more_magic[1] != 0x02 ||
929 firmware_header.more_magic[2] != 0x00 ||
930 firmware_header.more_magic[3] != 0x00) {
931 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
932 return -1;
933 }
934
935
936 if (fstat(sw->fd, &stat) == -1) {
937 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
938 return -1;
939 }
940
941 if (ntohl(firmware_header.file_length) != stat.st_size) {
942 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
943 return -1;
944 }
945
946 /* go back to the start as we checked the whole filesize.. */
947 lseek(sw->fd, 0l, SEEK_SET);
948 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
949 "There might be checksums in the file that are not\n"
950 "verified and incomplete firmware might be flashed.\n"
951 "There is absolutely no WARRANTY that flashing will\n"
952 "work.\n");
953 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100954}
955
Harald Welte4724f992009-01-18 18:01:49 +0000956static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
957{
958 char file_id[12+1];
959 char file_version[80+1];
960 int rc;
961
962 sw->fd = open(fname, O_RDONLY);
963 if (sw->fd < 0)
964 return sw->fd;
965
966 switch (sw->bts->type) {
967 case GSM_BTS_TYPE_BS11:
968 sw->stream = fdopen(sw->fd, "r");
969 if (!sw->stream) {
970 perror("fdopen");
971 return -1;
972 }
973 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200974 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +0000975 file_id, file_version);
976 if (rc != 2) {
977 perror("parsing header line of software file");
978 return -1;
979 }
980 strcpy((char *)sw->file_id, file_id);
981 sw->file_id_len = strlen(file_id);
982 strcpy((char *)sw->file_version, file_version);
983 sw->file_version_len = strlen(file_version);
984 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +0000985 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +0000986 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100987 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100988 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100989 rc = parse_sdp_header(sw);
990 if (rc < 0) {
991 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
992 return -1;
993 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100994
995 strcpy((char *)sw->file_id, "id");
996 sw->file_id_len = 3;
997 strcpy((char *)sw->file_version, "version");
998 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100999 break;
Harald Welte4724f992009-01-18 18:01:49 +00001000 default:
1001 /* We don't know how to treat them yet */
1002 close(sw->fd);
1003 return -EINVAL;
1004 }
1005
1006 return 0;
1007}
1008
1009static void sw_close_file(struct abis_nm_sw *sw)
1010{
1011 switch (sw->bts->type) {
1012 case GSM_BTS_TYPE_BS11:
1013 fclose(sw->stream);
1014 break;
1015 default:
1016 close(sw->fd);
1017 break;
1018 }
1019}
1020
1021/* Fill the window */
1022static int sw_fill_window(struct abis_nm_sw *sw)
1023{
1024 int rc;
1025
1026 while (sw->seg_in_window < sw->window_size) {
1027 rc = sw_load_segment(sw);
1028 if (rc < 0)
1029 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001030 if (sw->last_seg)
1031 break;
Harald Welte4724f992009-01-18 18:01:49 +00001032 }
1033 return 0;
1034}
1035
1036/* callback function from abis_nm_rcvmsg() handler */
1037static int abis_nm_rcvmsg_sw(struct msgb *mb)
1038{
1039 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001040 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001041 int rc = -1;
1042 struct abis_nm_sw *sw = &g_sw;
1043 enum sw_state old_state = sw->state;
1044
Harald Welte3ffd1372009-02-01 22:15:49 +00001045 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001046
1047 switch (sw->state) {
1048 case SW_STATE_WAIT_INITACK:
1049 switch (foh->msg_type) {
1050 case NM_MT_LOAD_INIT_ACK:
1051 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001052 if (sw->cbfn)
1053 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1054 NM_MT_LOAD_INIT_ACK, mb,
1055 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001056 rc = sw_fill_window(sw);
1057 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001058 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001059 break;
1060 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001061 if (sw->forced) {
1062 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1063 "Init NACK\n");
1064 if (sw->cbfn)
1065 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1066 NM_MT_LOAD_INIT_ACK, mb,
1067 sw->cb_data, NULL);
1068 rc = sw_fill_window(sw);
1069 sw->state = SW_STATE_WAIT_SEGACK;
1070 } else {
1071 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001072 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001073 if (sw->cbfn)
1074 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1075 NM_MT_LOAD_INIT_NACK, mb,
1076 sw->cb_data, NULL);
1077 sw->state = SW_STATE_ERROR;
1078 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001079 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001080 break;
1081 }
1082 break;
1083 case SW_STATE_WAIT_SEGACK:
1084 switch (foh->msg_type) {
1085 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001086 if (sw->cbfn)
1087 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1088 NM_MT_LOAD_SEG_ACK, mb,
1089 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001090 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001091 if (!sw->last_seg) {
1092 /* fill window with more segments */
1093 rc = sw_fill_window(sw);
1094 sw->state = SW_STATE_WAIT_SEGACK;
1095 } else {
1096 /* end the transfer */
1097 sw->state = SW_STATE_WAIT_ENDACK;
1098 rc = sw_load_end(sw);
1099 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001100 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001101 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001102 case NM_MT_LOAD_ABORT:
1103 if (sw->cbfn)
1104 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1105 NM_MT_LOAD_ABORT, mb,
1106 sw->cb_data, NULL);
1107 break;
Harald Welte4724f992009-01-18 18:01:49 +00001108 }
1109 break;
1110 case SW_STATE_WAIT_ENDACK:
1111 switch (foh->msg_type) {
1112 case NM_MT_LOAD_END_ACK:
1113 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001114 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1115 sw->bts->nr);
1116 sw->state = SW_STATE_NONE;
1117 if (sw->cbfn)
1118 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1119 NM_MT_LOAD_END_ACK, mb,
1120 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001121 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001122 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001123 break;
1124 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001125 if (sw->forced) {
1126 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1127 "End NACK\n");
1128 sw->state = SW_STATE_NONE;
1129 if (sw->cbfn)
1130 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1131 NM_MT_LOAD_END_ACK, mb,
1132 sw->cb_data, NULL);
1133 } else {
1134 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001135 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001136 sw->state = SW_STATE_ERROR;
1137 if (sw->cbfn)
1138 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1139 NM_MT_LOAD_END_NACK, mb,
1140 sw->cb_data, NULL);
1141 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001142 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001143 break;
1144 }
1145 case SW_STATE_WAIT_ACTACK:
1146 switch (foh->msg_type) {
1147 case NM_MT_ACTIVATE_SW_ACK:
1148 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001149 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001150 sw->state = SW_STATE_NONE;
1151 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001152 if (sw->cbfn)
1153 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1154 NM_MT_ACTIVATE_SW_ACK, mb,
1155 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001156 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001157 break;
1158 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001159 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001160 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001161 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001162 if (sw->cbfn)
1163 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1164 NM_MT_ACTIVATE_SW_NACK, mb,
1165 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001166 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001167 break;
1168 }
1169 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001170 switch (foh->msg_type) {
1171 case NM_MT_ACTIVATE_SW_ACK:
1172 rc = 0;
1173 break;
1174 }
1175 break;
Harald Welte4724f992009-01-18 18:01:49 +00001176 case SW_STATE_ERROR:
1177 break;
1178 }
1179
1180 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001181 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001182 foh->msg_type, old_state, sw->state);
1183
1184 return rc;
1185}
1186
1187/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001188int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001189 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001190 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001191{
1192 struct abis_nm_sw *sw = &g_sw;
1193 int rc;
1194
Harald Welte5e4d1b32009-02-01 13:36:56 +00001195 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1196 bts->nr, fname);
1197
Harald Welte4724f992009-01-18 18:01:49 +00001198 if (sw->state != SW_STATE_NONE)
1199 return -EBUSY;
1200
1201 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001202 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001203
1204 switch (bts->type) {
1205 case GSM_BTS_TYPE_BS11:
1206 sw->obj_class = NM_OC_SITE_MANAGER;
1207 sw->obj_instance[0] = 0xff;
1208 sw->obj_instance[1] = 0xff;
1209 sw->obj_instance[2] = 0xff;
1210 break;
1211 case GSM_BTS_TYPE_NANOBTS:
1212 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001213 sw->obj_instance[0] = sw->bts->nr;
1214 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001215 sw->obj_instance[2] = 0xff;
1216 break;
1217 case GSM_BTS_TYPE_UNKNOWN:
1218 default:
1219 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1220 return -1;
1221 break;
1222 }
Harald Welte4724f992009-01-18 18:01:49 +00001223 sw->window_size = win_size;
1224 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001225 sw->cbfn = cbfn;
1226 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001227 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001228
1229 rc = sw_open_file(sw, fname);
1230 if (rc < 0) {
1231 sw->state = SW_STATE_NONE;
1232 return rc;
1233 }
1234
1235 return sw_load_init(sw);
1236}
Harald Welte52b1f982008-12-23 20:25:15 +00001237
Harald Welte1602ade2009-01-29 21:12:39 +00001238int abis_nm_software_load_status(struct gsm_bts *bts)
1239{
1240 struct abis_nm_sw *sw = &g_sw;
1241 struct stat st;
1242 int rc, percent;
1243
1244 rc = fstat(sw->fd, &st);
1245 if (rc < 0) {
1246 perror("ERROR during stat");
1247 return rc;
1248 }
1249
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001250 if (sw->stream)
1251 percent = (ftell(sw->stream) * 100) / st.st_size;
1252 else
1253 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001254 return percent;
1255}
1256
Harald Welte5e4d1b32009-02-01 13:36:56 +00001257/* Activate the specified software into the BTS */
1258int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1259 gsm_cbfn *cbfn, void *cb_data)
1260{
1261 struct abis_nm_sw *sw = &g_sw;
1262 int rc;
1263
1264 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1265 bts->nr, fname);
1266
1267 if (sw->state != SW_STATE_NONE)
1268 return -EBUSY;
1269
1270 sw->bts = bts;
1271 sw->obj_class = NM_OC_SITE_MANAGER;
1272 sw->obj_instance[0] = 0xff;
1273 sw->obj_instance[1] = 0xff;
1274 sw->obj_instance[2] = 0xff;
1275 sw->state = SW_STATE_WAIT_ACTACK;
1276 sw->cbfn = cbfn;
1277 sw->cb_data = cb_data;
1278
1279 /* Open the file in order to fill some sw struct members */
1280 rc = sw_open_file(sw, fname);
1281 if (rc < 0) {
1282 sw->state = SW_STATE_NONE;
1283 return rc;
1284 }
1285 sw_close_file(sw);
1286
1287 return sw_activate(sw);
1288}
1289
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001290static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1291 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001292{
Harald Welteadaf08b2009-01-18 11:08:10 +00001293 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001294 ch->bts_port = bts_port;
1295 ch->timeslot = ts_nr;
1296 ch->subslot = subslot_nr;
1297}
1298
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001299int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1300 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1301 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001302{
1303 struct abis_om_hdr *oh;
1304 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001305 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001306 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001307
1308 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1309 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1310 bts->bts_nr, trx_nr, 0xff);
1311
Harald Welte8470bf22008-12-25 23:28:35 +00001312 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001313
1314 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1315 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1316
1317 return abis_nm_sendmsg(bts, msg);
1318}
1319
1320/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1321int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001322 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001323{
Harald Welte8470bf22008-12-25 23:28:35 +00001324 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001325 struct abis_om_hdr *oh;
1326 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001327 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001328
1329 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001330 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001331 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1332
1333 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1334 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1335
1336 return abis_nm_sendmsg(bts, msg);
1337}
1338
1339#if 0
1340int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1341 struct abis_nm_abis_channel *chan)
1342{
1343}
1344#endif
1345
1346int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001347 uint8_t e1_port, uint8_t e1_timeslot,
1348 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001349{
1350 struct gsm_bts *bts = ts->trx->bts;
1351 struct abis_om_hdr *oh;
1352 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001353 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001354
1355 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1356 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001357 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001358
1359 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1360 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1361
Harald Weltef325eb42009-02-19 17:07:39 +00001362 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1363 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001364 e1_port, e1_timeslot, e1_subslot);
1365
Harald Welte52b1f982008-12-23 20:25:15 +00001366 return abis_nm_sendmsg(bts, msg);
1367}
1368
1369#if 0
1370int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1371 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001372 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001373{
1374}
1375#endif
1376
Harald Weltefe568f22012-08-14 19:15:57 +02001377/* Chapter 8.11.1 */
1378int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1379 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1380 uint8_t *attr, uint8_t attr_len)
1381{
1382 struct abis_om_hdr *oh;
1383 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001384
1385 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1386
1387 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1388 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1389 bts_nr, trx_nr, ts_nr);
1390 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1391
1392 return abis_nm_sendmsg(bts, msg);
1393}
1394
Harald Welte22af0db2009-02-14 15:41:08 +00001395/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001396int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001397{
1398 struct abis_om_hdr *oh;
1399 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001400 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001401
1402 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1403
1404 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001405 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 +00001406 cur = msgb_put(msg, attr_len);
1407 memcpy(cur, attr, attr_len);
1408
1409 return abis_nm_sendmsg(bts, msg);
1410}
1411
1412/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001413int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001414{
1415 struct abis_om_hdr *oh;
1416 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001417 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001418
1419 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1420
1421 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1422 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001423 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001424 cur = msgb_put(msg, attr_len);
1425 memcpy(cur, attr, attr_len);
1426
1427 return abis_nm_sendmsg(trx->bts, msg);
1428}
1429
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001430static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1431 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001432{
1433 int i;
1434
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001435 *reason = "Reason unknown";
1436
Harald Welte39c7deb2009-08-09 21:49:48 +02001437 /* As it turns out, the BS-11 has some very peculiar restrictions
1438 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301439 switch (ts->trx->bts->type) {
1440 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001441 switch (chan_comb) {
1442 case NM_CHANC_TCHHalf:
1443 case NM_CHANC_TCHHalf2:
1444 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001445 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001446 return -EINVAL;
1447 case NM_CHANC_SDCCH:
1448 /* only one SDCCH/8 per TRX */
1449 for (i = 0; i < TRX_NR_TS; i++) {
1450 if (i == ts->nr)
1451 continue;
1452 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001453 NM_CHANC_SDCCH) {
1454 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001455 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001456 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001457 }
1458 /* not allowed for TS0 of BCCH-TRX */
1459 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001460 ts->nr == 0) {
1461 *reason = "SDCCH/8 must be on TS0.";
1462 return -EINVAL;
1463 }
1464
Harald Welte39c7deb2009-08-09 21:49:48 +02001465 /* not on the same TRX that has a BCCH+SDCCH4
1466 * combination */
1467 if (ts->trx == ts->trx->bts->c0 &&
1468 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001469 ts->trx->ts[0].nm_chan_comb == 8)) {
1470 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1471 return -EINVAL;
1472 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001473 break;
1474 case NM_CHANC_mainBCCH:
1475 case NM_CHANC_BCCHComb:
1476 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001477 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1478 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001479 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001480 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001481 break;
1482 case NM_CHANC_BCCH:
1483 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001484 if (ts->trx != ts->trx->bts->c0) {
1485 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001486 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001487 }
1488 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1489 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001490 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001491 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001492 break;
1493 case 8: /* this is not like 08.58, but in fact
1494 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1495 /* FIXME: only one CBCH allowed per cell */
1496 break;
1497 }
Harald Welted6575f92009-12-02 02:45:23 +05301498 break;
1499 case GSM_BTS_TYPE_NANOBTS:
1500 switch (ts->nr) {
1501 case 0:
1502 if (ts->trx->nr == 0) {
1503 /* only on TRX0 */
1504 switch (chan_comb) {
1505 case NM_CHANC_BCCH:
1506 case NM_CHANC_mainBCCH:
1507 case NM_CHANC_BCCHComb:
1508 return 0;
1509 break;
1510 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001511 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301512 return -EINVAL;
1513 }
1514 } else {
1515 switch (chan_comb) {
1516 case NM_CHANC_TCHFull:
1517 case NM_CHANC_TCHHalf:
1518 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1519 return 0;
1520 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001521 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301522 return -EINVAL;
1523 }
1524 }
1525 break;
1526 case 1:
1527 if (ts->trx->nr == 0) {
1528 switch (chan_comb) {
1529 case NM_CHANC_SDCCH_CBCH:
1530 if (ts->trx->ts[0].nm_chan_comb ==
1531 NM_CHANC_mainBCCH)
1532 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001533 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301534 return -EINVAL;
1535 case NM_CHANC_SDCCH:
1536 case NM_CHANC_TCHFull:
1537 case NM_CHANC_TCHHalf:
1538 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1539 case NM_CHANC_IPAC_TCHFull_PDCH:
1540 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001541 default:
1542 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1543 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301544 }
1545 } else {
1546 switch (chan_comb) {
1547 case NM_CHANC_SDCCH:
1548 case NM_CHANC_TCHFull:
1549 case NM_CHANC_TCHHalf:
1550 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1551 return 0;
1552 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001553 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301554 return -EINVAL;
1555 }
1556 }
1557 break;
1558 case 2:
1559 case 3:
1560 case 4:
1561 case 5:
1562 case 6:
1563 case 7:
1564 switch (chan_comb) {
1565 case NM_CHANC_TCHFull:
1566 case NM_CHANC_TCHHalf:
1567 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1568 return 0;
1569 case NM_CHANC_IPAC_PDCH:
1570 case NM_CHANC_IPAC_TCHFull_PDCH:
1571 if (ts->trx->nr == 0)
1572 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001573 else {
1574 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301575 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001576 }
Harald Welted6575f92009-12-02 02:45:23 +05301577 }
1578 break;
1579 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001580 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301581 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001582 case GSM_BTS_TYPE_OSMO_SYSMO:
1583 /* no known restrictions */
1584 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301585 default:
1586 /* unknown BTS type */
1587 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001588 }
1589 return 0;
1590}
1591
Harald Welte22af0db2009-02-14 15:41:08 +00001592/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001593int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001594{
1595 struct gsm_bts *bts = ts->trx->bts;
1596 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001597 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001598 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001599 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001600 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001601
1602 if (bts->type == GSM_BTS_TYPE_BS11)
1603 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001604
Harald Weltef325eb42009-02-19 17:07:39 +00001605 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001606 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001607 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001608 LOGP(DNM, LOGL_ERROR,
1609 "Invalid Channel Combination %d on %s. Reason: %s\n",
1610 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001611 return -EINVAL;
1612 }
1613 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001614
Harald Welte52b1f982008-12-23 20:25:15 +00001615 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001616 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001617 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001618 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001619 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001620 if (ts->hopping.enabled) {
1621 unsigned int i;
1622 uint8_t *len;
1623
Harald Welte6e0cd042009-09-12 13:05:33 +02001624 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1625 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001626
1627 /* build the ARFCN list */
1628 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1629 len = msgb_put(msg, 1);
1630 *len = 0;
1631 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1632 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1633 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001634 /* At least BS-11 wants a TLV16 here */
1635 if (bts->type == GSM_BTS_TYPE_BS11)
1636 *len += 1;
1637 else
1638 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001639 }
1640 }
Harald Weltee0590df2009-02-15 03:34:15 +00001641 }
Harald Welte135a6482011-05-30 12:09:13 +02001642 if (ts->tsc == -1)
1643 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1644 else
1645 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001646 if (bts->type == GSM_BTS_TYPE_BS11)
1647 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001648
1649 return abis_nm_sendmsg(bts, msg);
1650}
1651
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001652int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1653 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001654{
1655 struct abis_om_hdr *oh;
1656 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001657 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1658 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001659
1660 if (nack) {
1661 len += 2;
1662 msgtype = NM_MT_SW_ACT_REQ_NACK;
1663 }
Harald Welte34a99682009-02-13 02:41:40 +00001664
1665 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001666 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1667
Harald Welte34a99682009-02-13 02:41:40 +00001668 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001669 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001670 memcpy(ptr, attr, att_len);
1671 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001672 if (nack)
1673 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001674
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001675 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001676}
1677
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001678int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001679{
Harald Welte8470bf22008-12-25 23:28:35 +00001680 struct msgb *msg = nm_msgb_alloc();
1681 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001682 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001683
1684 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1685 fill_om_hdr(oh, len);
1686 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001687 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001688
1689 return abis_nm_sendmsg(bts, msg);
1690}
1691
1692/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001693static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001694{
1695 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001696 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001697
1698 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001699 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001700 0xff, 0xff, 0xff);
1701
1702 return abis_nm_sendmsg(bts, msg);
1703}
1704
Harald Welte34a99682009-02-13 02:41:40 +00001705/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001706int 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 +00001707{
1708 struct abis_om_hdr *oh;
1709 struct msgb *msg = nm_msgb_alloc();
1710
1711 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1712 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1713
Harald Welte15c61722011-05-22 22:45:37 +02001714 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001715 DEBUGPC(DNM, "Sending OPSTART\n");
1716
Harald Welte34a99682009-02-13 02:41:40 +00001717 return abis_nm_sendmsg(bts, msg);
1718}
1719
1720/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001721int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1722 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001723{
1724 struct abis_om_hdr *oh;
1725 struct msgb *msg = nm_msgb_alloc();
1726
1727 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1728 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1729 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1730
1731 return abis_nm_sendmsg(bts, msg);
1732}
1733
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001734int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1735 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001736{
1737 struct abis_om_hdr *oh;
1738 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001739 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001740
1741 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1742 e1_port0, ts0, e1_port1, ts1);
1743
1744 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1745 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1746 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1747
1748 attr = msgb_put(msg, 3);
1749 attr[0] = NM_ATT_MDROP_LINK;
1750 attr[1] = e1_port0;
1751 attr[2] = ts0;
1752
1753 attr = msgb_put(msg, 3);
1754 attr[0] = NM_ATT_MDROP_NEXT;
1755 attr[1] = e1_port1;
1756 attr[2] = ts1;
1757
1758 return abis_nm_sendmsg(bts, msg);
1759}
Harald Welte34a99682009-02-13 02:41:40 +00001760
Harald Weltec7310382009-08-08 00:02:36 +02001761/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001762int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1763 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1764 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001765{
1766 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001767
Harald Welte15c61722011-05-22 22:45:37 +02001768 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001769
1770 if (!msg)
1771 msg = nm_msgb_alloc();
1772
1773 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1774 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1775 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1776 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001777 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001778
1779 return abis_nm_sendmsg(bts, msg);
1780}
1781
Harald Welte52b1f982008-12-23 20:25:15 +00001782int abis_nm_event_reports(struct gsm_bts *bts, int on)
1783{
1784 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001785 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001786 else
Harald Welte227d4072009-01-03 08:16:25 +00001787 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001788}
1789
Harald Welte47d88ae2009-01-04 12:02:08 +00001790/* Siemens (or BS-11) specific commands */
1791
Harald Welte3ffd1372009-02-01 22:15:49 +00001792int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1793{
1794 if (reconnect == 0)
1795 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1796 else
1797 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1798}
1799
Harald Welteb8427972009-02-05 19:27:17 +00001800int abis_nm_bs11_restart(struct gsm_bts *bts)
1801{
1802 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1803}
1804
1805
Harald Welte268bb402009-02-01 19:11:56 +00001806struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001807 uint16_t year;
1808 uint8_t month;
1809 uint8_t day;
1810 uint8_t hour;
1811 uint8_t min;
1812 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001813} __attribute__((packed));
1814
1815
1816void get_bs11_date_time(struct bs11_date_time *aet)
1817{
1818 time_t t;
1819 struct tm *tm;
1820
1821 t = time(NULL);
1822 tm = localtime(&t);
1823 aet->sec = tm->tm_sec;
1824 aet->min = tm->tm_min;
1825 aet->hour = tm->tm_hour;
1826 aet->day = tm->tm_mday;
1827 aet->month = tm->tm_mon;
1828 aet->year = htons(1900 + tm->tm_year);
1829}
1830
Harald Welte05188ee2009-01-18 11:39:08 +00001831int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001832{
Harald Welte4668fda2009-01-03 08:19:29 +00001833 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001834}
1835
Harald Welte05188ee2009-01-18 11:39:08 +00001836int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001837{
1838 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001839 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001840 else
Harald Welte4668fda2009-01-03 08:19:29 +00001841 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001842}
Harald Welte47d88ae2009-01-04 12:02:08 +00001843
Harald Welte05188ee2009-01-18 11:39:08 +00001844int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001845 enum abis_bs11_objtype type, uint8_t idx,
1846 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001847{
1848 struct abis_om_hdr *oh;
1849 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001850 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001851
1852 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001853 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001854 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001855 cur = msgb_put(msg, attr_len);
1856 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001857
1858 return abis_nm_sendmsg(bts, msg);
1859}
1860
Harald Welte78fc0d42009-02-19 02:50:57 +00001861int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001862 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001863{
1864 struct abis_om_hdr *oh;
1865 struct msgb *msg = nm_msgb_alloc();
1866
1867 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1868 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1869 NM_OC_BS11, type, 0, idx);
1870
1871 return abis_nm_sendmsg(bts, msg);
1872}
1873
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001874int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001875{
1876 struct abis_om_hdr *oh;
1877 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001878 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001879
1880 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001881 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001882 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1883 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001884
1885 return abis_nm_sendmsg(bts, msg);
1886}
1887
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001888int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001889{
1890 struct abis_om_hdr *oh;
1891 struct msgb *msg = nm_msgb_alloc();
1892
1893 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1894 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001895 idx, 0xff, 0xff);
1896
1897 return abis_nm_sendmsg(bts, msg);
1898}
1899
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001900int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001901{
1902 struct abis_om_hdr *oh;
1903 struct msgb *msg = nm_msgb_alloc();
1904
1905 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1906 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1907 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001908
1909 return abis_nm_sendmsg(bts, msg);
1910}
Harald Welte05188ee2009-01-18 11:39:08 +00001911
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001912static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001913int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1914{
1915 struct abis_om_hdr *oh;
1916 struct msgb *msg = nm_msgb_alloc();
1917
1918 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1919 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1920 0xff, 0xff, 0xff);
1921 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1922
1923 return abis_nm_sendmsg(bts, msg);
1924}
1925
Harald Welteb6c92ae2009-02-21 20:15:32 +00001926/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001927int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1928 uint8_t e1_timeslot, uint8_t e1_subslot,
1929 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001930{
1931 struct abis_om_hdr *oh;
1932 struct abis_nm_channel *ch;
1933 struct msgb *msg = nm_msgb_alloc();
1934
1935 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001936 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001937 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1938
1939 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1940 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001941 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001942
1943 return abis_nm_sendmsg(bts, msg);
1944}
1945
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001946int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001947{
1948 struct abis_om_hdr *oh;
1949 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001950
1951 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001952 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001953 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1954 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1955
1956 return abis_nm_sendmsg(trx->bts, msg);
1957}
1958
Harald Welte78fc0d42009-02-19 02:50:57 +00001959int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1960{
1961 struct abis_om_hdr *oh;
1962 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001963 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00001964
1965 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1966 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1967 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1968 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1969
1970 return abis_nm_sendmsg(trx->bts, msg);
1971}
1972
Harald Welteaaf02d92009-04-29 13:25:57 +00001973int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1974{
1975 struct abis_om_hdr *oh;
1976 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001977 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00001978
1979 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1980 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1981 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00001982 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00001983
1984 return abis_nm_sendmsg(bts, msg);
1985}
1986
Harald Welteef061952009-05-17 12:43:42 +00001987int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1988{
1989 struct abis_om_hdr *oh;
1990 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001991 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00001992 NM_ATT_BS11_CCLK_TYPE };
1993
1994 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1995 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1996 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1997 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1998
1999 return abis_nm_sendmsg(bts, msg);
2000
2001}
Harald Welteaaf02d92009-04-29 13:25:57 +00002002
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002003//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002004
Harald Welte1bc09062009-01-18 14:17:52 +00002005int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002006{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002007 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2008}
2009
Daniel Willmann4b054c82010-01-07 00:46:26 +01002010int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2011{
2012 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2013}
2014
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002015int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002016{
Harald Welte05188ee2009-01-18 11:39:08 +00002017 struct abis_om_hdr *oh;
2018 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002019 struct bs11_date_time bdt;
2020
2021 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002022
2023 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002024 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002025 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002026 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002027 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002028 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002029 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002030 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002031 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002032 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002033 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002034 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002035 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002036 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002037 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002038 }
Harald Welte05188ee2009-01-18 11:39:08 +00002039
2040 return abis_nm_sendmsg(bts, msg);
2041}
Harald Welte1bc09062009-01-18 14:17:52 +00002042
2043int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2044{
2045 struct abis_om_hdr *oh;
2046 struct msgb *msg;
2047
2048 if (strlen(password) != 10)
2049 return -EINVAL;
2050
2051 msg = nm_msgb_alloc();
2052 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002053 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002054 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002055 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002056
2057 return abis_nm_sendmsg(bts, msg);
2058}
2059
Harald Weltee69f5fb2009-04-28 16:31:38 +00002060/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2061int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2062{
2063 struct abis_om_hdr *oh;
2064 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002065 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002066
2067 msg = nm_msgb_alloc();
2068 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2069 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2070 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002071
2072 if (locked)
2073 tlv_value = BS11_LI_PLL_LOCKED;
2074 else
2075 tlv_value = BS11_LI_PLL_STANDALONE;
2076
2077 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002078
2079 return abis_nm_sendmsg(bts, msg);
2080}
2081
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002082/* Set the calibration value of the PLL (work value/set value)
2083 * It depends on the login which one is changed */
2084int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2085{
2086 struct abis_om_hdr *oh;
2087 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002088 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002089
2090 msg = nm_msgb_alloc();
2091 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2092 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2093 BS11_OBJ_TRX1, 0x00, 0x00);
2094
2095 tlv_value[0] = value>>8;
2096 tlv_value[1] = value&0xff;
2097
2098 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2099
2100 return abis_nm_sendmsg(bts, msg);
2101}
2102
Harald Welte1bc09062009-01-18 14:17:52 +00002103int abis_nm_bs11_get_state(struct gsm_bts *bts)
2104{
2105 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2106}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002107
2108/* BS11 SWL */
2109
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002110void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002111
Harald Welte5e4d1b32009-02-01 13:36:56 +00002112struct abis_nm_bs11_sw {
2113 struct gsm_bts *bts;
2114 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002115 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002116 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002117 struct llist_head file_list;
2118 gsm_cbfn *user_cb; /* specified by the user */
2119};
2120static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2121
2122struct file_list_entry {
2123 struct llist_head list;
2124 char fname[PATH_MAX];
2125};
2126
2127struct file_list_entry *fl_dequeue(struct llist_head *queue)
2128{
2129 struct llist_head *lh;
2130
2131 if (llist_empty(queue))
2132 return NULL;
2133
2134 lh = queue->next;
2135 llist_del(lh);
2136
2137 return llist_entry(lh, struct file_list_entry, list);
2138}
2139
2140static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2141{
2142 char linebuf[255];
2143 struct llist_head *lh, *lh2;
2144 FILE *swl;
2145 int rc = 0;
2146
2147 swl = fopen(bs11_sw->swl_fname, "r");
2148 if (!swl)
2149 return -ENODEV;
2150
2151 /* zero the stale file list, if any */
2152 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2153 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002154 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002155 }
2156
2157 while (fgets(linebuf, sizeof(linebuf), swl)) {
2158 char file_id[12+1];
2159 char file_version[80+1];
2160 struct file_list_entry *fle;
2161 static char dir[PATH_MAX];
2162
2163 if (strlen(linebuf) < 4)
2164 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002165
Harald Welte5e4d1b32009-02-01 13:36:56 +00002166 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2167 if (rc < 0) {
2168 perror("ERR parsing SWL file");
2169 rc = -EINVAL;
2170 goto out;
2171 }
2172 if (rc < 2)
2173 continue;
2174
Harald Welte470ec292009-06-26 20:25:23 +02002175 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002176 if (!fle) {
2177 rc = -ENOMEM;
2178 goto out;
2179 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002180
2181 /* construct new filename */
2182 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2183 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2184 strcat(fle->fname, "/");
2185 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002186
2187 llist_add_tail(&fle->list, &bs11_sw->file_list);
2188 }
2189
2190out:
2191 fclose(swl);
2192 return rc;
2193}
2194
2195/* bs11 swload specific callback, passed to abis_nm core swload */
2196static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2197 struct msgb *msg, void *data, void *param)
2198{
2199 struct abis_nm_bs11_sw *bs11_sw = data;
2200 struct file_list_entry *fle;
2201 int rc = 0;
2202
Harald Welte5e4d1b32009-02-01 13:36:56 +00002203 switch (event) {
2204 case NM_MT_LOAD_END_ACK:
2205 fle = fl_dequeue(&bs11_sw->file_list);
2206 if (fle) {
2207 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002208 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002209 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002210 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002211 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002212 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002213 } else {
2214 /* activate the SWL */
2215 rc = abis_nm_software_activate(bs11_sw->bts,
2216 bs11_sw->swl_fname,
2217 bs11_swload_cbfn,
2218 bs11_sw);
2219 }
2220 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002221 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002222 case NM_MT_LOAD_END_NACK:
2223 case NM_MT_LOAD_INIT_ACK:
2224 case NM_MT_LOAD_INIT_NACK:
2225 case NM_MT_ACTIVATE_SW_NACK:
2226 case NM_MT_ACTIVATE_SW_ACK:
2227 default:
2228 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002229 if (bs11_sw->user_cb)
2230 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002231 break;
2232 }
2233
2234 return rc;
2235}
2236
2237/* Siemens provides a SWL file that is a mere listing of all the other
2238 * files that are part of a software release. We need to upload first
2239 * the list file, and then each file that is listed in the list file */
2240int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002241 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002242{
2243 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2244 struct file_list_entry *fle;
2245 int rc = 0;
2246
2247 INIT_LLIST_HEAD(&bs11_sw->file_list);
2248 bs11_sw->bts = bts;
2249 bs11_sw->win_size = win_size;
2250 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002251 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002252
2253 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2254 rc = bs11_read_swl_file(bs11_sw);
2255 if (rc < 0)
2256 return rc;
2257
2258 /* dequeue next item in file list */
2259 fle = fl_dequeue(&bs11_sw->file_list);
2260 if (!fle)
2261 return -EINVAL;
2262
2263 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002264 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002265 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002266 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002267 return rc;
2268}
2269
Harald Welte5083b0b2009-02-02 19:20:52 +00002270#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002271static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002272 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2273 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2274 NM_ATT_BS11_LMT_USER_NAME,
2275
2276 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2277
2278 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2279
2280 NM_ATT_BS11_SW_LOAD_STORED };
2281
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002282static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002283 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2284 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2285 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2286 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002287#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002288
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002289static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002290 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2291 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002292 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002293
2294int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2295{
2296 struct abis_om_hdr *oh;
2297 struct msgb *msg = nm_msgb_alloc();
2298
2299 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2300 /* SiemensHW CCTRL object */
2301 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2302 0x03, 0x00, 0x00);
2303 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2304
2305 return abis_nm_sendmsg(bts, msg);
2306}
Harald Welte268bb402009-02-01 19:11:56 +00002307
2308int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2309{
2310 struct abis_om_hdr *oh;
2311 struct msgb *msg = nm_msgb_alloc();
2312 struct bs11_date_time aet;
2313
2314 get_bs11_date_time(&aet);
2315 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2316 /* SiemensHW CCTRL object */
2317 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2318 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002319 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002320
2321 return abis_nm_sendmsg(bts, msg);
2322}
Harald Welte5c1e4582009-02-15 11:57:29 +00002323
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002324int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002325{
2326 struct abis_om_hdr *oh;
2327 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002328 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002329
2330 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2331 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2332 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2333 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2334
2335 return abis_nm_sendmsg(bts, msg);
2336}
2337
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002338int 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 +02002339{
2340 struct abis_om_hdr *oh;
2341 struct msgb *msg = nm_msgb_alloc();
2342 struct bs11_date_time aet;
2343
2344 get_bs11_date_time(&aet);
2345 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2346 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2347 bport, 0xff, 0x02);
2348 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2349
2350 return abis_nm_sendmsg(bts, msg);
2351}
2352
Harald Welte5c1e4582009-02-15 11:57:29 +00002353/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002354static const char ipaccess_magic[] = "com.ipaccess";
2355
Harald Welte677c21f2009-02-17 13:22:23 +00002356
2357static int abis_nm_rx_ipacc(struct msgb *msg)
2358{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002359 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002360 struct abis_om_hdr *oh = msgb_l2(msg);
2361 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002362 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002363 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002364 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002365 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002366
2367 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002368 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002369 return -EINVAL;
2370 }
2371
Harald Welte193fefc2009-04-30 15:16:27 +00002372 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002373 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002374
Harald Welte15c61722011-05-22 22:45:37 +02002375 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002376
Harald Welte746d6092009-10-19 22:11:11 +02002377 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002378
Harald Welte677c21f2009-02-17 13:22:23 +00002379 switch (foh->msg_type) {
2380 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002381 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002382 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2383 memcpy(&addr,
2384 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2385
2386 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2387 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002388 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002389 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002390 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002391 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002392 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2393 DEBUGPC(DNM, "STREAM=0x%02x ",
2394 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002395 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002396 break;
2397 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002398 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002399 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002400 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002401 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002402 else
2403 DEBUGPC(DNM, "\n");
2404 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002405 case NM_MT_IPACC_SET_NVATTR_ACK:
2406 DEBUGPC(DNM, "SET NVATTR ACK\n");
2407 /* FIXME: decode and show the actual attributes */
2408 break;
2409 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002410 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002411 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002412 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002413 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002414 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002415 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002416 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002417 case NM_MT_IPACC_GET_NVATTR_ACK:
2418 DEBUGPC(DNM, "GET NVATTR ACK\n");
2419 /* FIXME: decode and show the actual attributes */
2420 break;
2421 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002422 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002423 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002424 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002425 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002426 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002427 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002428 break;
Harald Welte15c44172009-10-08 20:15:24 +02002429 case NM_MT_IPACC_SET_ATTR_ACK:
2430 DEBUGPC(DNM, "SET ATTR ACK\n");
2431 break;
2432 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002433 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002434 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002435 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002436 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002437 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002438 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002439 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002440 default:
2441 DEBUGPC(DNM, "unknown\n");
2442 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002443 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002444
2445 /* signal handling */
2446 switch (foh->msg_type) {
2447 case NM_MT_IPACC_RSL_CONNECT_NACK:
2448 case NM_MT_IPACC_SET_NVATTR_NACK:
2449 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002450 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 +01002451 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002452 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002453 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002454 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002455 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 +01002456 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002457 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002458 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002459 default:
2460 break;
2461 }
2462
Harald Welte677c21f2009-02-17 13:22:23 +00002463 return 0;
2464}
2465
Harald Welte193fefc2009-04-30 15:16:27 +00002466/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002467int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2468 uint8_t obj_class, uint8_t bts_nr,
2469 uint8_t trx_nr, uint8_t ts_nr,
2470 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002471{
2472 struct msgb *msg = nm_msgb_alloc();
2473 struct abis_om_hdr *oh;
2474 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002475 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002476
2477 /* construct the 12.21 OM header, observe the erroneous length */
2478 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2479 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2480 oh->mdisc = ABIS_OM_MDISC_MANUF;
2481
2482 /* add the ip.access magic */
2483 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2484 *data++ = sizeof(ipaccess_magic);
2485 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2486
2487 /* fill the 12.21 FOM header */
2488 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2489 foh->msg_type = msg_type;
2490 foh->obj_class = obj_class;
2491 foh->obj_inst.bts_nr = bts_nr;
2492 foh->obj_inst.trx_nr = trx_nr;
2493 foh->obj_inst.ts_nr = ts_nr;
2494
2495 if (attr && attr_len) {
2496 data = msgb_put(msg, attr_len);
2497 memcpy(data, attr, attr_len);
2498 }
2499
2500 return abis_nm_sendmsg(bts, msg);
2501}
Harald Welte677c21f2009-02-17 13:22:23 +00002502
Harald Welte193fefc2009-04-30 15:16:27 +00002503/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002504int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002505 int attr_len)
2506{
Harald Welte2ef156d2010-01-07 20:39:42 +01002507 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2508 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002509 attr_len);
2510}
2511
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002512int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002513 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002514{
2515 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002516 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002517 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2518 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2519
2520 int attr_len = sizeof(attr);
2521
2522 ia.s_addr = htonl(ip);
2523 attr[1] = stream;
2524 attr[3] = port >> 8;
2525 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002526 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002527
2528 /* if ip == 0, we use the default IP */
2529 if (ip == 0)
2530 attr_len -= 5;
2531
2532 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002533 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002534
2535 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2536 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2537 trx->nr, 0xff, attr, attr_len);
2538}
2539
Harald Welte193fefc2009-04-30 15:16:27 +00002540/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002541int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002542{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002543 struct abis_om_hdr *oh;
2544 struct msgb *msg = nm_msgb_alloc();
2545
2546 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2547 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2548 trx->bts->nr, trx->nr, 0xff);
2549
2550 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002551}
Harald Weltedaef5212009-10-24 10:20:41 +02002552
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002553int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2554 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2555 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002556{
2557 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2558 obj_class, bts_nr, trx_nr, ts_nr,
2559 attr, attr_len);
2560}
Harald Welte0f255852009-11-12 14:48:42 +01002561
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002562void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002563{
2564 /* we simply reuse the GSM48 function and overwrite the RAC
2565 * with the Cell ID */
2566 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002567 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002568}
2569
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002570void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2571{
2572 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2573
Harald Welted64c0bc2011-05-30 12:07:53 +02002574 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002575 if (!trx->bts || !trx->bts->oml_link)
2576 return;
2577
2578 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2579 trx->bts->bts_nr, trx->nr, 0xff,
2580 new_state);
2581}
2582
Harald Welte92b1fe42010-03-25 11:45:30 +08002583static const struct value_string ipacc_testres_names[] = {
2584 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2585 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2586 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2587 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2588 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2589 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002590};
2591
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002592const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002593{
Harald Welte92b1fe42010-03-25 11:45:30 +08002594 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002595}
2596
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002597void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002598{
2599 cid->mcc = (buf[0] & 0xf) * 100;
2600 cid->mcc += (buf[0] >> 4) * 10;
2601 cid->mcc += (buf[1] & 0xf) * 1;
2602
2603 if (buf[1] >> 4 == 0xf) {
2604 cid->mnc = (buf[2] & 0xf) * 10;
2605 cid->mnc += (buf[2] >> 4) * 1;
2606 } else {
2607 cid->mnc = (buf[2] & 0xf) * 100;
2608 cid->mnc += (buf[2] >> 4) * 10;
2609 cid->mnc += (buf[1] >> 4) * 1;
2610 }
2611
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002612 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2613 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002614}
2615
Harald Welte0f255852009-11-12 14:48:42 +01002616/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002617int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002618{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002619 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002620 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002621
Harald Welteaf109b92010-07-22 18:14:36 +02002622 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002623
2624 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2625 return -EINVAL;
2626 cur++;
2627
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002628 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002629 cur += 2;
2630
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002631 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002632 cur += 2;
2633
2634 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2635 binf->freq_qual = *cur >> 2;
2636
Harald Welteaf109b92010-07-22 18:14:36 +02002637 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002638 binf->arfcn |= *cur++;
2639
2640 if (binf->info_type & IPAC_BINF_RXLEV)
2641 binf->rx_lev = *cur & 0x3f;
2642 cur++;
2643
2644 if (binf->info_type & IPAC_BINF_RXQUAL)
2645 binf->rx_qual = *cur & 0x7;
2646 cur++;
2647
2648 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002649 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002650 cur += 2;
2651
2652 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002653 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002654 cur += 2;
2655
2656 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002657 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002658 cur += 4;
2659
Harald Weltea780a3d2010-07-30 22:34:42 +02002660#if 0
2661 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002662 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002663#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002664 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002665 cur++;
2666
Harald Welteb40a38f2009-11-13 11:56:05 +01002667 ipac_parse_cgi(&binf->cgi, cur);
2668 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002669
2670 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2671 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2672 cur += sizeof(binf->ba_list_si2);
2673 }
2674
2675 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2676 memcpy(binf->ba_list_si2bis, cur,
2677 sizeof(binf->ba_list_si2bis));
2678 cur += sizeof(binf->ba_list_si2bis);
2679 }
2680
2681 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2682 memcpy(binf->ba_list_si2ter, cur,
2683 sizeof(binf->ba_list_si2ter));
2684 cur += sizeof(binf->ba_list_si2ter);
2685 }
2686
2687 return 0;
2688}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002689
2690void abis_nm_clear_queue(struct gsm_bts *bts)
2691{
2692 struct msgb *msg;
2693
2694 while (!llist_empty(&bts->abis_queue)) {
2695 msg = msgb_dequeue(&bts->abis_queue);
2696 msgb_free(msg);
2697 }
2698
2699 bts->abis_nm_pend = 0;
2700}