blob: adc2362fab86f2cbb2bb3c61978f9abea362bc32 [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 Freytherbce56752012-11-22 14:59:46 +0100362int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
363 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100364{
365 static const struct tlv_definition sw_descr_def = {
366 .def = {
367 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
368 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
369 },
370 };
371
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100372 size_t pos = 0;
373 int desc_pos = 0;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100374
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100375 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
376 uint8_t tag;
377 uint16_t tag_len;
378 const uint8_t *val;
379 int len;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100380
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100381 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
382 desc[desc_pos].start = &sw_descr[pos];
383
384 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
385 * nested nature and the fact you have to assume it contains only two sub
386 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
387 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
388 LOGP(DNM, LOGL_ERROR,
389 "SW_DESCR attribute identifier not found!\n");
390 return -1;
391 }
392
393 pos += 1;
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
396 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
397 LOGP(DNM, LOGL_ERROR,
398 "FILE_ID attribute identifier not found!\n");
399 return -2;
400 }
401 desc[desc_pos].file_id = val;
402 desc[desc_pos].file_id_len = tag_len;
403 pos += len;
404
405
406 len = tlv_parse_one(&tag, &tag_len, &val,
407 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
408 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
409 LOGP(DNM, LOGL_ERROR,
410 "FILE_VERSION attribute identifier not found!\n");
411 return -3;
412 }
413 desc[desc_pos].file_ver = val;
414 desc[desc_pos].file_ver_len = tag_len;
415 pos += len;
416
417 /* final size */
418 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100419 }
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100420
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100421 return desc_pos;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100422}
423
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100424int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
425 const size_t size)
426{
427 int res = 0;
428 int i;
429
430 for (i = 1; i < size; ++i) {
431 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
432 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
433 res = i;
434 }
435 }
436
437 return res;
438}
439
Harald Welte34a99682009-02-13 02:41:40 +0000440static int abis_nm_rx_sw_act_req(struct msgb *mb)
441{
442 struct abis_om_hdr *oh = msgb_l2(mb);
443 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200444 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200445 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200446 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100447 int ret, sw_config_len, len;
448 struct abis_nm_sw_descr sw_descr[5];
Harald Welte34a99682009-02-13 02:41:40 +0000449
Harald Welte15c61722011-05-22 22:45:37 +0200450 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200451
452 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000453
Harald Welte97a282b2010-03-14 15:37:43 +0800454 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000455
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200456 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000457 foh->obj_inst.bts_nr,
458 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800459 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000460 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100461 if (ret != 0) {
462 LOGP(DNM, LOGL_ERROR,
463 "Sending SW ActReq ACK failed: %d\n", ret);
464 return ret;
465 }
Harald Welte34a99682009-02-13 02:41:40 +0000466
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200467 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200468 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
469 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
470 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100471 LOGP(DNM, LOGL_ERROR,
472 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200473 return -EINVAL;
474 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200475 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200476 }
477
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100478 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100479 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100480 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100481 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100482 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100483 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100484 }
Mike Habena03f9772009-10-01 14:56:13 +0200485
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100486 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
487 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
488
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200489 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000490 foh->obj_inst.bts_nr,
491 foh->obj_inst.trx_nr,
492 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100493 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte34a99682009-02-13 02:41:40 +0000494}
495
Harald Weltee0590df2009-02-15 03:34:15 +0000496/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
497static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
498{
499 struct abis_om_hdr *oh = msgb_l2(mb);
500 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200501 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000502 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200503 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000504
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200505 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000506 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
507 return -EINVAL;
508
509 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
510
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200511 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000512}
513
Harald Welteee670472009-02-22 21:58:49 +0000514static int abis_nm_rx_lmt_event(struct msgb *mb)
515{
516 struct abis_om_hdr *oh = msgb_l2(mb);
517 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200518 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000519 struct tlv_parsed tp;
520
521 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200522 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000523 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
524 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200525 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000526 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
527 }
528 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
529 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200530 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000531 DEBUGPC(DNM, "Level=%u ", level);
532 }
533 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
534 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
535 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
536 DEBUGPC(DNM, "Username=%s ", name);
537 }
538 DEBUGPC(DNM, "\n");
539 /* FIXME: parse LMT LOGON TIME */
540 return 0;
541}
542
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200543void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100544{
545 int wait = 0;
546 struct msgb *msg;
547 /* the queue is empty */
548 while (!llist_empty(&bts->abis_queue)) {
549 msg = msgb_dequeue(&bts->abis_queue);
550 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200551 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100552
553 if (wait)
554 break;
555 }
556
557 bts->abis_nm_pend = wait;
558}
559
Harald Welte52b1f982008-12-23 20:25:15 +0000560/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000561static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000562{
Harald Welte6c96ba52009-05-01 13:03:40 +0000563 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000564 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200565 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200566 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100567 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000568
569 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000570 if (is_report(mt))
571 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000572
Harald Welte15c61722011-05-22 22:45:37 +0200573 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000574 return abis_nm_rcvmsg_sw(mb);
575
Harald Welte15c61722011-05-22 22:45:37 +0200576 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800577 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000578 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200579
Harald Welte15c61722011-05-22 22:45:37 +0200580 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200581
Harald Welte15c61722011-05-22 22:45:37 +0200582 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000583
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200584 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000585 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200586 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200587 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000588 else
589 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200590
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800591 nack_data.msg = mb;
592 nack_data.mt = mt;
Holger Hans Peter Freytherde1674a2012-11-11 18:26:23 +0100593 nack_data.bts = sign_link->trx->bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200594 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200595 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200596 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000597 }
Harald Weltead384642008-12-26 10:20:07 +0000598#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000599 /* check if last message is to be acked */
600 if (is_ack_nack(nmh->last_msgtype)) {
601 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100602 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000603 /* we got our ACK, continue sending the next msg */
604 } else if (mt == MT_NACK(nmh->last_msgtype)) {
605 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100606 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000607 /* FIXME: somehow signal this to the caller */
608 } else {
609 /* really strange things happen */
610 return -EINVAL;
611 }
612 }
Harald Weltead384642008-12-26 10:20:07 +0000613#endif
614
Harald Welte97ed1e72009-02-06 13:38:02 +0000615 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000616 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100617 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000618 break;
Harald Welte34a99682009-02-13 02:41:40 +0000619 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100620 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000621 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000622 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100623 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000624 break;
Harald Welte1989c082009-08-06 17:58:31 +0200625 case NM_MT_CONN_MDROP_LINK_ACK:
626 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
627 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100628 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200629 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100630 break;
631 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200632 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100633 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100634 case NM_MT_SET_BTS_ATTR_ACK:
635 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200636 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
637 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Weltefd355a32011-03-04 13:41:31 +0100638 }
639 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000640 }
641
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200642 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100643 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000644}
645
Harald Welte677c21f2009-02-17 13:22:23 +0000646static int abis_nm_rx_ipacc(struct msgb *mb);
647
648static int abis_nm_rcvmsg_manuf(struct msgb *mb)
649{
650 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200651 struct e1inp_sign_link *sign_link = mb->dst;
652 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000653
654 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100655 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200656 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000657 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200658 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000659 break;
660 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100661 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
662 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000663 rc = 0;
664 break;
665 }
666
667 return rc;
668}
669
Harald Welte52b1f982008-12-23 20:25:15 +0000670/* High-Level API */
671/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000672int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000673{
Harald Welte52b1f982008-12-23 20:25:15 +0000674 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000675 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000676
677 /* Various consistency checks */
678 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100679 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000680 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200681 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
682 rc = -EINVAL;
683 goto err;
684 }
Harald Welte52b1f982008-12-23 20:25:15 +0000685 }
686 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100687 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000688 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200689 rc = -EINVAL;
690 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000691 }
Harald Welte702d8702008-12-26 20:25:35 +0000692#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200693 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000694 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000695 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100696 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000697 oh->length + sizeof(*oh), l2_len);
698 return -EINVAL;
699 }
Harald Welte702d8702008-12-26 20:25:35 +0000700 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100701 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 +0000702#endif
Harald Weltead384642008-12-26 10:20:07 +0000703 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000704
705 switch (oh->mdisc) {
706 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000707 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000708 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000709 case ABIS_OM_MDISC_MANUF:
710 rc = abis_nm_rcvmsg_manuf(msg);
711 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000712 case ABIS_OM_MDISC_MMI:
713 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100714 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000715 oh->mdisc);
716 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000717 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100718 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000719 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200720 rc = -EINVAL;
721 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000722 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200723err:
Harald Weltead384642008-12-26 10:20:07 +0000724 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000725 return rc;
726}
727
728#if 0
729/* initialized all resources */
730struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
731{
732 struct abis_nm_h *nmh;
733
734 nmh = malloc(sizeof(*nmh));
735 if (!nmh)
736 return NULL;
737
738 nmh->cfg = cfg;
739
740 return nmh;
741}
742
743/* free all resources */
744void abis_nm_fini(struct abis_nm_h *nmh)
745{
746 free(nmh);
747}
748#endif
749
750/* Here we are trying to define a high-level API that can be used by
751 * the actual BSC implementation. However, the architecture is currently
752 * still under design. Ideally the calls to this API would be synchronous,
753 * while the underlying stack behind the APi runs in a traditional select
754 * based state machine.
755 */
756
Harald Welte4724f992009-01-18 18:01:49 +0000757/* 6.2 Software Load: */
758enum sw_state {
759 SW_STATE_NONE,
760 SW_STATE_WAIT_INITACK,
761 SW_STATE_WAIT_SEGACK,
762 SW_STATE_WAIT_ENDACK,
763 SW_STATE_WAIT_ACTACK,
764 SW_STATE_ERROR,
765};
Harald Welte52b1f982008-12-23 20:25:15 +0000766
Harald Welte52b1f982008-12-23 20:25:15 +0000767struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000768 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800769 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000770 gsm_cbfn *cbfn;
771 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000772 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000773
Harald Welte52b1f982008-12-23 20:25:15 +0000774 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200775 uint8_t obj_class;
776 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000777
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200778 uint8_t file_id[255];
779 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000780
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200781 uint8_t file_version[255];
782 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000783
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200784 uint8_t window_size;
785 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000786
787 int fd;
788 FILE *stream;
789 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000790 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000791};
792
Harald Welte4724f992009-01-18 18:01:49 +0000793static struct abis_nm_sw g_sw;
794
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100795static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
796{
797 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
798 msgb_v_put(msg, NM_ATT_SW_DESCR);
799 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
800 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
801 sw->file_version);
802 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
803 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
804 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
805 sw->file_version);
806 } else {
807 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
808 }
809}
810
Harald Welte4724f992009-01-18 18:01:49 +0000811/* 6.2.1 / 8.3.1: Load Data Initiate */
812static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000813{
Harald Welte4724f992009-01-18 18:01:49 +0000814 struct abis_om_hdr *oh;
815 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200816 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000817
818 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
819 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
820 sw->obj_instance[0], sw->obj_instance[1],
821 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100822
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100823 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000824 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
825
826 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000827}
828
Harald Welte1602ade2009-01-29 21:12:39 +0000829static int is_last_line(FILE *stream)
830{
831 char next_seg_buf[256];
832 long pos;
833
834 /* check if we're sending the last line */
835 pos = ftell(stream);
836 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
837 fseek(stream, pos, SEEK_SET);
838 return 1;
839 }
840
841 fseek(stream, pos, SEEK_SET);
842 return 0;
843}
844
Harald Welte4724f992009-01-18 18:01:49 +0000845/* 6.2.2 / 8.3.2 Load Data Segment */
846static int sw_load_segment(struct abis_nm_sw *sw)
847{
848 struct abis_om_hdr *oh;
849 struct msgb *msg = nm_msgb_alloc();
850 char seg_buf[256];
851 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000852 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200853 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000854
855 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000856
857 switch (sw->bts->type) {
858 case GSM_BTS_TYPE_BS11:
859 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
860 perror("fgets reading segment");
861 return -EINVAL;
862 }
863 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000864
865 /* check if we're sending the last line */
866 sw->last_seg = is_last_line(sw->stream);
867 if (sw->last_seg)
868 seg_buf[1] = 0;
869 else
870 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000871
872 len = strlen(line_buf) + 2;
873 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200874 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000875 /* BS11 wants CR + LF in excess of the TLV length !?! */
876 tlv[1] -= 2;
877
878 /* we only now know the exact length for the OM hdr */
879 len = strlen(line_buf)+2;
880 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100881 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200882 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100883 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
884 if (len < 0) {
885 perror("read failed");
886 return -EINVAL;
887 }
888
889 if (len != IPACC_SEGMENT_SIZE)
890 sw->last_seg = 1;
891
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100892 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200893 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100894 len += 3;
895 break;
896 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000897 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100898 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000899 /* FIXME: Other BTS types */
900 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000901 }
Harald Welte4724f992009-01-18 18:01:49 +0000902
Harald Welte4724f992009-01-18 18:01:49 +0000903 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
904 sw->obj_instance[0], sw->obj_instance[1],
905 sw->obj_instance[2]);
906
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100907 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000908}
909
910/* 6.2.4 / 8.3.4 Load Data End */
911static int sw_load_end(struct abis_nm_sw *sw)
912{
913 struct abis_om_hdr *oh;
914 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200915 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000916
917 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
918 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
919 sw->obj_instance[0], sw->obj_instance[1],
920 sw->obj_instance[2]);
921
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100922 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000923 return abis_nm_sendmsg(sw->bts, msg);
924}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000925
Harald Welte52b1f982008-12-23 20:25:15 +0000926/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000927static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000928{
Harald Welte4724f992009-01-18 18:01:49 +0000929 struct abis_om_hdr *oh;
930 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200931 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000932
Harald Welte4724f992009-01-18 18:01:49 +0000933 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
934 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
935 sw->obj_instance[0], sw->obj_instance[1],
936 sw->obj_instance[2]);
937
938 /* FIXME: this is BS11 specific format */
939 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
940 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
941 sw->file_version);
942
943 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000944}
Harald Welte4724f992009-01-18 18:01:49 +0000945
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100946struct sdp_firmware {
947 char magic[4];
948 char more_magic[4];
949 unsigned int header_length;
950 unsigned int file_length;
951} __attribute__ ((packed));
952
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100953static int parse_sdp_header(struct abis_nm_sw *sw)
954{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100955 struct sdp_firmware firmware_header;
956 int rc;
957 struct stat stat;
958
959 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
960 if (rc != sizeof(firmware_header)) {
961 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
962 return -1;
963 }
964
965 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
966 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
967 return -1;
968 }
969
970 if (firmware_header.more_magic[0] != 0x10 ||
971 firmware_header.more_magic[1] != 0x02 ||
972 firmware_header.more_magic[2] != 0x00 ||
973 firmware_header.more_magic[3] != 0x00) {
974 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
975 return -1;
976 }
977
978
979 if (fstat(sw->fd, &stat) == -1) {
980 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
981 return -1;
982 }
983
984 if (ntohl(firmware_header.file_length) != stat.st_size) {
985 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
986 return -1;
987 }
988
989 /* go back to the start as we checked the whole filesize.. */
990 lseek(sw->fd, 0l, SEEK_SET);
991 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
992 "There might be checksums in the file that are not\n"
993 "verified and incomplete firmware might be flashed.\n"
994 "There is absolutely no WARRANTY that flashing will\n"
995 "work.\n");
996 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100997}
998
Harald Welte4724f992009-01-18 18:01:49 +0000999static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1000{
1001 char file_id[12+1];
1002 char file_version[80+1];
1003 int rc;
1004
1005 sw->fd = open(fname, O_RDONLY);
1006 if (sw->fd < 0)
1007 return sw->fd;
1008
1009 switch (sw->bts->type) {
1010 case GSM_BTS_TYPE_BS11:
1011 sw->stream = fdopen(sw->fd, "r");
1012 if (!sw->stream) {
1013 perror("fdopen");
1014 return -1;
1015 }
1016 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001017 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001018 file_id, file_version);
1019 if (rc != 2) {
1020 perror("parsing header line of software file");
1021 return -1;
1022 }
1023 strcpy((char *)sw->file_id, file_id);
1024 sw->file_id_len = strlen(file_id);
1025 strcpy((char *)sw->file_version, file_version);
1026 sw->file_version_len = strlen(file_version);
1027 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001028 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001029 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001030 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001031 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001032 rc = parse_sdp_header(sw);
1033 if (rc < 0) {
1034 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1035 return -1;
1036 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001037
1038 strcpy((char *)sw->file_id, "id");
1039 sw->file_id_len = 3;
1040 strcpy((char *)sw->file_version, "version");
1041 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001042 break;
Harald Welte4724f992009-01-18 18:01:49 +00001043 default:
1044 /* We don't know how to treat them yet */
1045 close(sw->fd);
1046 return -EINVAL;
1047 }
1048
1049 return 0;
1050}
1051
1052static void sw_close_file(struct abis_nm_sw *sw)
1053{
1054 switch (sw->bts->type) {
1055 case GSM_BTS_TYPE_BS11:
1056 fclose(sw->stream);
1057 break;
1058 default:
1059 close(sw->fd);
1060 break;
1061 }
1062}
1063
1064/* Fill the window */
1065static int sw_fill_window(struct abis_nm_sw *sw)
1066{
1067 int rc;
1068
1069 while (sw->seg_in_window < sw->window_size) {
1070 rc = sw_load_segment(sw);
1071 if (rc < 0)
1072 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001073 if (sw->last_seg)
1074 break;
Harald Welte4724f992009-01-18 18:01:49 +00001075 }
1076 return 0;
1077}
1078
1079/* callback function from abis_nm_rcvmsg() handler */
1080static int abis_nm_rcvmsg_sw(struct msgb *mb)
1081{
1082 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001083 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001084 int rc = -1;
1085 struct abis_nm_sw *sw = &g_sw;
1086 enum sw_state old_state = sw->state;
1087
Harald Welte3ffd1372009-02-01 22:15:49 +00001088 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001089
1090 switch (sw->state) {
1091 case SW_STATE_WAIT_INITACK:
1092 switch (foh->msg_type) {
1093 case NM_MT_LOAD_INIT_ACK:
1094 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001095 if (sw->cbfn)
1096 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1097 NM_MT_LOAD_INIT_ACK, mb,
1098 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001099 rc = sw_fill_window(sw);
1100 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001101 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001102 break;
1103 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001104 if (sw->forced) {
1105 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1106 "Init NACK\n");
1107 if (sw->cbfn)
1108 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1109 NM_MT_LOAD_INIT_ACK, mb,
1110 sw->cb_data, NULL);
1111 rc = sw_fill_window(sw);
1112 sw->state = SW_STATE_WAIT_SEGACK;
1113 } else {
1114 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001115 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001116 if (sw->cbfn)
1117 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1118 NM_MT_LOAD_INIT_NACK, mb,
1119 sw->cb_data, NULL);
1120 sw->state = SW_STATE_ERROR;
1121 }
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 }
1125 break;
1126 case SW_STATE_WAIT_SEGACK:
1127 switch (foh->msg_type) {
1128 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001129 if (sw->cbfn)
1130 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1131 NM_MT_LOAD_SEG_ACK, mb,
1132 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001133 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001134 if (!sw->last_seg) {
1135 /* fill window with more segments */
1136 rc = sw_fill_window(sw);
1137 sw->state = SW_STATE_WAIT_SEGACK;
1138 } else {
1139 /* end the transfer */
1140 sw->state = SW_STATE_WAIT_ENDACK;
1141 rc = sw_load_end(sw);
1142 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001143 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001144 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001145 case NM_MT_LOAD_ABORT:
1146 if (sw->cbfn)
1147 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1148 NM_MT_LOAD_ABORT, mb,
1149 sw->cb_data, NULL);
1150 break;
Harald Welte4724f992009-01-18 18:01:49 +00001151 }
1152 break;
1153 case SW_STATE_WAIT_ENDACK:
1154 switch (foh->msg_type) {
1155 case NM_MT_LOAD_END_ACK:
1156 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001157 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1158 sw->bts->nr);
1159 sw->state = SW_STATE_NONE;
1160 if (sw->cbfn)
1161 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1162 NM_MT_LOAD_END_ACK, mb,
1163 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001164 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001165 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001166 break;
1167 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001168 if (sw->forced) {
1169 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1170 "End NACK\n");
1171 sw->state = SW_STATE_NONE;
1172 if (sw->cbfn)
1173 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1174 NM_MT_LOAD_END_ACK, mb,
1175 sw->cb_data, NULL);
1176 } else {
1177 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001178 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001179 sw->state = SW_STATE_ERROR;
1180 if (sw->cbfn)
1181 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1182 NM_MT_LOAD_END_NACK, mb,
1183 sw->cb_data, NULL);
1184 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001185 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001186 break;
1187 }
1188 case SW_STATE_WAIT_ACTACK:
1189 switch (foh->msg_type) {
1190 case NM_MT_ACTIVATE_SW_ACK:
1191 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001192 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001193 sw->state = SW_STATE_NONE;
1194 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001195 if (sw->cbfn)
1196 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1197 NM_MT_ACTIVATE_SW_ACK, mb,
1198 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001199 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001200 break;
1201 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001202 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001203 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001204 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001205 if (sw->cbfn)
1206 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1207 NM_MT_ACTIVATE_SW_NACK, mb,
1208 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001209 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001210 break;
1211 }
1212 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001213 switch (foh->msg_type) {
1214 case NM_MT_ACTIVATE_SW_ACK:
1215 rc = 0;
1216 break;
1217 }
1218 break;
Harald Welte4724f992009-01-18 18:01:49 +00001219 case SW_STATE_ERROR:
1220 break;
1221 }
1222
1223 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001224 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001225 foh->msg_type, old_state, sw->state);
1226
1227 return rc;
1228}
1229
1230/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001231int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001232 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001233 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001234{
1235 struct abis_nm_sw *sw = &g_sw;
1236 int rc;
1237
Harald Welte5e4d1b32009-02-01 13:36:56 +00001238 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1239 bts->nr, fname);
1240
Harald Welte4724f992009-01-18 18:01:49 +00001241 if (sw->state != SW_STATE_NONE)
1242 return -EBUSY;
1243
1244 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001245 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001246
1247 switch (bts->type) {
1248 case GSM_BTS_TYPE_BS11:
1249 sw->obj_class = NM_OC_SITE_MANAGER;
1250 sw->obj_instance[0] = 0xff;
1251 sw->obj_instance[1] = 0xff;
1252 sw->obj_instance[2] = 0xff;
1253 break;
1254 case GSM_BTS_TYPE_NANOBTS:
1255 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001256 sw->obj_instance[0] = sw->bts->nr;
1257 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001258 sw->obj_instance[2] = 0xff;
1259 break;
1260 case GSM_BTS_TYPE_UNKNOWN:
1261 default:
1262 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1263 return -1;
1264 break;
1265 }
Harald Welte4724f992009-01-18 18:01:49 +00001266 sw->window_size = win_size;
1267 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001268 sw->cbfn = cbfn;
1269 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001270 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001271
1272 rc = sw_open_file(sw, fname);
1273 if (rc < 0) {
1274 sw->state = SW_STATE_NONE;
1275 return rc;
1276 }
1277
1278 return sw_load_init(sw);
1279}
Harald Welte52b1f982008-12-23 20:25:15 +00001280
Harald Welte1602ade2009-01-29 21:12:39 +00001281int abis_nm_software_load_status(struct gsm_bts *bts)
1282{
1283 struct abis_nm_sw *sw = &g_sw;
1284 struct stat st;
1285 int rc, percent;
1286
1287 rc = fstat(sw->fd, &st);
1288 if (rc < 0) {
1289 perror("ERROR during stat");
1290 return rc;
1291 }
1292
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001293 if (sw->stream)
1294 percent = (ftell(sw->stream) * 100) / st.st_size;
1295 else
1296 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001297 return percent;
1298}
1299
Harald Welte5e4d1b32009-02-01 13:36:56 +00001300/* Activate the specified software into the BTS */
1301int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1302 gsm_cbfn *cbfn, void *cb_data)
1303{
1304 struct abis_nm_sw *sw = &g_sw;
1305 int rc;
1306
1307 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1308 bts->nr, fname);
1309
1310 if (sw->state != SW_STATE_NONE)
1311 return -EBUSY;
1312
1313 sw->bts = bts;
1314 sw->obj_class = NM_OC_SITE_MANAGER;
1315 sw->obj_instance[0] = 0xff;
1316 sw->obj_instance[1] = 0xff;
1317 sw->obj_instance[2] = 0xff;
1318 sw->state = SW_STATE_WAIT_ACTACK;
1319 sw->cbfn = cbfn;
1320 sw->cb_data = cb_data;
1321
1322 /* Open the file in order to fill some sw struct members */
1323 rc = sw_open_file(sw, fname);
1324 if (rc < 0) {
1325 sw->state = SW_STATE_NONE;
1326 return rc;
1327 }
1328 sw_close_file(sw);
1329
1330 return sw_activate(sw);
1331}
1332
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001333static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1334 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001335{
Harald Welteadaf08b2009-01-18 11:08:10 +00001336 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001337 ch->bts_port = bts_port;
1338 ch->timeslot = ts_nr;
1339 ch->subslot = subslot_nr;
1340}
1341
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001342int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1343 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1344 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001345{
1346 struct abis_om_hdr *oh;
1347 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001348 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001349 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001350
1351 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1352 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1353 bts->bts_nr, trx_nr, 0xff);
1354
Harald Welte8470bf22008-12-25 23:28:35 +00001355 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001356
1357 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1358 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1359
1360 return abis_nm_sendmsg(bts, msg);
1361}
1362
1363/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1364int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001365 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001366{
Harald Welte8470bf22008-12-25 23:28:35 +00001367 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001368 struct abis_om_hdr *oh;
1369 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001370 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001371
1372 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001373 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001374 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1375
1376 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1377 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1378
1379 return abis_nm_sendmsg(bts, msg);
1380}
1381
1382#if 0
1383int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1384 struct abis_nm_abis_channel *chan)
1385{
1386}
1387#endif
1388
1389int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001390 uint8_t e1_port, uint8_t e1_timeslot,
1391 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001392{
1393 struct gsm_bts *bts = ts->trx->bts;
1394 struct abis_om_hdr *oh;
1395 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001396 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001397
1398 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1399 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001400 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001401
1402 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1403 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1404
Harald Weltef325eb42009-02-19 17:07:39 +00001405 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1406 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001407 e1_port, e1_timeslot, e1_subslot);
1408
Harald Welte52b1f982008-12-23 20:25:15 +00001409 return abis_nm_sendmsg(bts, msg);
1410}
1411
1412#if 0
1413int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1414 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001415 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001416{
1417}
1418#endif
1419
Harald Weltefe568f22012-08-14 19:15:57 +02001420/* Chapter 8.11.1 */
1421int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1422 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1423 uint8_t *attr, uint8_t attr_len)
1424{
1425 struct abis_om_hdr *oh;
1426 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001427
1428 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1429
1430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1431 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1432 bts_nr, trx_nr, ts_nr);
1433 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1434
1435 return abis_nm_sendmsg(bts, msg);
1436}
1437
Harald Welte22af0db2009-02-14 15:41:08 +00001438/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001439int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001440{
1441 struct abis_om_hdr *oh;
1442 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001443 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001444
1445 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1446
1447 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001448 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 +00001449 cur = msgb_put(msg, attr_len);
1450 memcpy(cur, attr, attr_len);
1451
1452 return abis_nm_sendmsg(bts, msg);
1453}
1454
1455/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001456int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001457{
1458 struct abis_om_hdr *oh;
1459 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001460 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001461
1462 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1463
1464 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1465 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001466 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001467 cur = msgb_put(msg, attr_len);
1468 memcpy(cur, attr, attr_len);
1469
1470 return abis_nm_sendmsg(trx->bts, msg);
1471}
1472
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001473static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1474 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001475{
1476 int i;
1477
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001478 *reason = "Reason unknown";
1479
Harald Welte39c7deb2009-08-09 21:49:48 +02001480 /* As it turns out, the BS-11 has some very peculiar restrictions
1481 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301482 switch (ts->trx->bts->type) {
1483 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001484 switch (chan_comb) {
1485 case NM_CHANC_TCHHalf:
1486 case NM_CHANC_TCHHalf2:
1487 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001488 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001489 return -EINVAL;
1490 case NM_CHANC_SDCCH:
1491 /* only one SDCCH/8 per TRX */
1492 for (i = 0; i < TRX_NR_TS; i++) {
1493 if (i == ts->nr)
1494 continue;
1495 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001496 NM_CHANC_SDCCH) {
1497 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001498 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001499 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001500 }
1501 /* not allowed for TS0 of BCCH-TRX */
1502 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001503 ts->nr == 0) {
1504 *reason = "SDCCH/8 must be on TS0.";
1505 return -EINVAL;
1506 }
1507
Harald Welte39c7deb2009-08-09 21:49:48 +02001508 /* not on the same TRX that has a BCCH+SDCCH4
1509 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001510 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001511 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001512 ts->trx->ts[0].nm_chan_comb == 8)) {
1513 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1514 return -EINVAL;
1515 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001516 break;
1517 case NM_CHANC_mainBCCH:
1518 case NM_CHANC_BCCHComb:
1519 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001520 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1521 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001522 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001523 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001524 break;
1525 case NM_CHANC_BCCH:
1526 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001527 if (ts->trx != ts->trx->bts->c0) {
1528 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001529 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001530 }
1531 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1532 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001533 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001534 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001535 break;
1536 case 8: /* this is not like 08.58, but in fact
1537 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1538 /* FIXME: only one CBCH allowed per cell */
1539 break;
1540 }
Harald Welted6575f92009-12-02 02:45:23 +05301541 break;
1542 case GSM_BTS_TYPE_NANOBTS:
1543 switch (ts->nr) {
1544 case 0:
1545 if (ts->trx->nr == 0) {
1546 /* only on TRX0 */
1547 switch (chan_comb) {
1548 case NM_CHANC_BCCH:
1549 case NM_CHANC_mainBCCH:
1550 case NM_CHANC_BCCHComb:
1551 return 0;
1552 break;
1553 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001554 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301555 return -EINVAL;
1556 }
1557 } else {
1558 switch (chan_comb) {
1559 case NM_CHANC_TCHFull:
1560 case NM_CHANC_TCHHalf:
1561 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1562 return 0;
1563 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001564 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301565 return -EINVAL;
1566 }
1567 }
1568 break;
1569 case 1:
1570 if (ts->trx->nr == 0) {
1571 switch (chan_comb) {
1572 case NM_CHANC_SDCCH_CBCH:
1573 if (ts->trx->ts[0].nm_chan_comb ==
1574 NM_CHANC_mainBCCH)
1575 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001576 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301577 return -EINVAL;
1578 case NM_CHANC_SDCCH:
1579 case NM_CHANC_TCHFull:
1580 case NM_CHANC_TCHHalf:
1581 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1582 case NM_CHANC_IPAC_TCHFull_PDCH:
1583 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001584 default:
1585 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1586 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301587 }
1588 } else {
1589 switch (chan_comb) {
1590 case NM_CHANC_SDCCH:
1591 case NM_CHANC_TCHFull:
1592 case NM_CHANC_TCHHalf:
1593 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1594 return 0;
1595 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001596 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301597 return -EINVAL;
1598 }
1599 }
1600 break;
1601 case 2:
1602 case 3:
1603 case 4:
1604 case 5:
1605 case 6:
1606 case 7:
1607 switch (chan_comb) {
1608 case NM_CHANC_TCHFull:
1609 case NM_CHANC_TCHHalf:
1610 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1611 return 0;
1612 case NM_CHANC_IPAC_PDCH:
1613 case NM_CHANC_IPAC_TCHFull_PDCH:
1614 if (ts->trx->nr == 0)
1615 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001616 else {
1617 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301618 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001619 }
Harald Welted6575f92009-12-02 02:45:23 +05301620 }
1621 break;
1622 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001623 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301624 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001625 case GSM_BTS_TYPE_OSMO_SYSMO:
1626 /* no known restrictions */
1627 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301628 default:
1629 /* unknown BTS type */
1630 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001631 }
1632 return 0;
1633}
1634
Harald Welte22af0db2009-02-14 15:41:08 +00001635/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001636int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001637{
1638 struct gsm_bts *bts = ts->trx->bts;
1639 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001640 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001641 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001642 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001643 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001644
1645 if (bts->type == GSM_BTS_TYPE_BS11)
1646 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001647
Harald Weltef325eb42009-02-19 17:07:39 +00001648 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001649 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001650 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001651 LOGP(DNM, LOGL_ERROR,
1652 "Invalid Channel Combination %d on %s. Reason: %s\n",
1653 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001654 return -EINVAL;
1655 }
1656 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001657
Harald Welte52b1f982008-12-23 20:25:15 +00001658 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001659 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001660 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001661 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001662 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001663 if (ts->hopping.enabled) {
1664 unsigned int i;
1665 uint8_t *len;
1666
Harald Welte6e0cd042009-09-12 13:05:33 +02001667 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1668 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001669
1670 /* build the ARFCN list */
1671 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1672 len = msgb_put(msg, 1);
1673 *len = 0;
1674 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1675 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1676 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001677 /* At least BS-11 wants a TLV16 here */
1678 if (bts->type == GSM_BTS_TYPE_BS11)
1679 *len += 1;
1680 else
1681 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001682 }
1683 }
Harald Weltee0590df2009-02-15 03:34:15 +00001684 }
Harald Welte135a6482011-05-30 12:09:13 +02001685 if (ts->tsc == -1)
1686 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1687 else
1688 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001689 if (bts->type == GSM_BTS_TYPE_BS11)
1690 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001691
1692 return abis_nm_sendmsg(bts, msg);
1693}
1694
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001695int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1696 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001697{
1698 struct abis_om_hdr *oh;
1699 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001700 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1701 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001702
1703 if (nack) {
1704 len += 2;
1705 msgtype = NM_MT_SW_ACT_REQ_NACK;
1706 }
Harald Welte34a99682009-02-13 02:41:40 +00001707
1708 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001709 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1710
Harald Welte34a99682009-02-13 02:41:40 +00001711 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001712 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001713 memcpy(ptr, attr, att_len);
1714 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001715 if (nack)
1716 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001717
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001718 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001719}
1720
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001721int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001722{
Harald Welte8470bf22008-12-25 23:28:35 +00001723 struct msgb *msg = nm_msgb_alloc();
1724 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001725 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001726
1727 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1728 fill_om_hdr(oh, len);
1729 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001730 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001731
1732 return abis_nm_sendmsg(bts, msg);
1733}
1734
1735/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001736static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001737{
1738 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001739 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001740
1741 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001742 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001743 0xff, 0xff, 0xff);
1744
1745 return abis_nm_sendmsg(bts, msg);
1746}
1747
Harald Welte34a99682009-02-13 02:41:40 +00001748/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001749int 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 +00001750{
1751 struct abis_om_hdr *oh;
1752 struct msgb *msg = nm_msgb_alloc();
1753
1754 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1755 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1756
Harald Welte15c61722011-05-22 22:45:37 +02001757 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001758 DEBUGPC(DNM, "Sending OPSTART\n");
1759
Harald Welte34a99682009-02-13 02:41:40 +00001760 return abis_nm_sendmsg(bts, msg);
1761}
1762
1763/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001764int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1765 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001766{
1767 struct abis_om_hdr *oh;
1768 struct msgb *msg = nm_msgb_alloc();
1769
1770 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1771 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1772 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1773
1774 return abis_nm_sendmsg(bts, msg);
1775}
1776
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001777int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1778 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001779{
1780 struct abis_om_hdr *oh;
1781 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001782 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001783
1784 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1785 e1_port0, ts0, e1_port1, ts1);
1786
1787 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1788 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1789 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1790
1791 attr = msgb_put(msg, 3);
1792 attr[0] = NM_ATT_MDROP_LINK;
1793 attr[1] = e1_port0;
1794 attr[2] = ts0;
1795
1796 attr = msgb_put(msg, 3);
1797 attr[0] = NM_ATT_MDROP_NEXT;
1798 attr[1] = e1_port1;
1799 attr[2] = ts1;
1800
1801 return abis_nm_sendmsg(bts, msg);
1802}
Harald Welte34a99682009-02-13 02:41:40 +00001803
Harald Weltec7310382009-08-08 00:02:36 +02001804/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001805int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1806 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1807 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001808{
1809 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001810
Harald Welte15c61722011-05-22 22:45:37 +02001811 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001812
1813 if (!msg)
1814 msg = nm_msgb_alloc();
1815
1816 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1817 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1818 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1819 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001820 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001821
1822 return abis_nm_sendmsg(bts, msg);
1823}
1824
Harald Welte52b1f982008-12-23 20:25:15 +00001825int abis_nm_event_reports(struct gsm_bts *bts, int on)
1826{
1827 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001828 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001829 else
Harald Welte227d4072009-01-03 08:16:25 +00001830 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001831}
1832
Harald Welte47d88ae2009-01-04 12:02:08 +00001833/* Siemens (or BS-11) specific commands */
1834
Harald Welte3ffd1372009-02-01 22:15:49 +00001835int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1836{
1837 if (reconnect == 0)
1838 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1839 else
1840 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1841}
1842
Harald Welteb8427972009-02-05 19:27:17 +00001843int abis_nm_bs11_restart(struct gsm_bts *bts)
1844{
1845 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1846}
1847
1848
Harald Welte268bb402009-02-01 19:11:56 +00001849struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001850 uint16_t year;
1851 uint8_t month;
1852 uint8_t day;
1853 uint8_t hour;
1854 uint8_t min;
1855 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001856} __attribute__((packed));
1857
1858
1859void get_bs11_date_time(struct bs11_date_time *aet)
1860{
1861 time_t t;
1862 struct tm *tm;
1863
1864 t = time(NULL);
1865 tm = localtime(&t);
1866 aet->sec = tm->tm_sec;
1867 aet->min = tm->tm_min;
1868 aet->hour = tm->tm_hour;
1869 aet->day = tm->tm_mday;
1870 aet->month = tm->tm_mon;
1871 aet->year = htons(1900 + tm->tm_year);
1872}
1873
Harald Welte05188ee2009-01-18 11:39:08 +00001874int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001875{
Harald Welte4668fda2009-01-03 08:19:29 +00001876 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001877}
1878
Harald Welte05188ee2009-01-18 11:39:08 +00001879int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001880{
1881 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001882 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001883 else
Harald Welte4668fda2009-01-03 08:19:29 +00001884 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001885}
Harald Welte47d88ae2009-01-04 12:02:08 +00001886
Harald Welte05188ee2009-01-18 11:39:08 +00001887int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001888 enum abis_bs11_objtype type, uint8_t idx,
1889 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001890{
1891 struct abis_om_hdr *oh;
1892 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001893 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001894
1895 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001896 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001897 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001898 cur = msgb_put(msg, attr_len);
1899 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001900
1901 return abis_nm_sendmsg(bts, msg);
1902}
1903
Harald Welte78fc0d42009-02-19 02:50:57 +00001904int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001905 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001906{
1907 struct abis_om_hdr *oh;
1908 struct msgb *msg = nm_msgb_alloc();
1909
1910 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1911 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1912 NM_OC_BS11, type, 0, idx);
1913
1914 return abis_nm_sendmsg(bts, msg);
1915}
1916
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001917int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001918{
1919 struct abis_om_hdr *oh;
1920 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001921 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001922
1923 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001924 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001925 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1926 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001927
1928 return abis_nm_sendmsg(bts, msg);
1929}
1930
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001931int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001932{
1933 struct abis_om_hdr *oh;
1934 struct msgb *msg = nm_msgb_alloc();
1935
1936 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1937 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001938 idx, 0xff, 0xff);
1939
1940 return abis_nm_sendmsg(bts, msg);
1941}
1942
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001943int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001944{
1945 struct abis_om_hdr *oh;
1946 struct msgb *msg = nm_msgb_alloc();
1947
1948 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1949 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1950 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001951
1952 return abis_nm_sendmsg(bts, msg);
1953}
Harald Welte05188ee2009-01-18 11:39:08 +00001954
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001955static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001956int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1957{
1958 struct abis_om_hdr *oh;
1959 struct msgb *msg = nm_msgb_alloc();
1960
1961 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1962 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1963 0xff, 0xff, 0xff);
1964 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1965
1966 return abis_nm_sendmsg(bts, msg);
1967}
1968
Harald Welteb6c92ae2009-02-21 20:15:32 +00001969/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001970int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1971 uint8_t e1_timeslot, uint8_t e1_subslot,
1972 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001973{
1974 struct abis_om_hdr *oh;
1975 struct abis_nm_channel *ch;
1976 struct msgb *msg = nm_msgb_alloc();
1977
1978 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001979 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001980 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1981
1982 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1983 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001984 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001985
1986 return abis_nm_sendmsg(bts, msg);
1987}
1988
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001989int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001990{
1991 struct abis_om_hdr *oh;
1992 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001993
1994 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001995 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001996 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1997 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1998
1999 return abis_nm_sendmsg(trx->bts, msg);
2000}
2001
Harald Welte78fc0d42009-02-19 02:50:57 +00002002int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2003{
2004 struct abis_om_hdr *oh;
2005 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002006 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002007
2008 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2009 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2010 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2011 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2012
2013 return abis_nm_sendmsg(trx->bts, msg);
2014}
2015
Harald Welteaaf02d92009-04-29 13:25:57 +00002016int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2017{
2018 struct abis_om_hdr *oh;
2019 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002020 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002021
2022 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2023 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2024 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002025 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002026
2027 return abis_nm_sendmsg(bts, msg);
2028}
2029
Harald Welteef061952009-05-17 12:43:42 +00002030int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2031{
2032 struct abis_om_hdr *oh;
2033 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002034 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002035 NM_ATT_BS11_CCLK_TYPE };
2036
2037 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2038 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2039 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2040 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2041
2042 return abis_nm_sendmsg(bts, msg);
2043
2044}
Harald Welteaaf02d92009-04-29 13:25:57 +00002045
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002046//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002047
Harald Welte1bc09062009-01-18 14:17:52 +00002048int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002049{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002050 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2051}
2052
Daniel Willmann4b054c82010-01-07 00:46:26 +01002053int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2054{
2055 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2056}
2057
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002058int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002059{
Harald Welte05188ee2009-01-18 11:39:08 +00002060 struct abis_om_hdr *oh;
2061 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002062 struct bs11_date_time bdt;
2063
2064 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002065
2066 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002067 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002068 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002069 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002070 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002071 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002072 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002073 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002074 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002075 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002076 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002077 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002078 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002079 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002080 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002081 }
Harald Welte05188ee2009-01-18 11:39:08 +00002082
2083 return abis_nm_sendmsg(bts, msg);
2084}
Harald Welte1bc09062009-01-18 14:17:52 +00002085
2086int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2087{
2088 struct abis_om_hdr *oh;
2089 struct msgb *msg;
2090
2091 if (strlen(password) != 10)
2092 return -EINVAL;
2093
2094 msg = nm_msgb_alloc();
2095 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002096 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002097 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002098 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002099
2100 return abis_nm_sendmsg(bts, msg);
2101}
2102
Harald Weltee69f5fb2009-04-28 16:31:38 +00002103/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2104int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2105{
2106 struct abis_om_hdr *oh;
2107 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002108 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002109
2110 msg = nm_msgb_alloc();
2111 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2112 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2113 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002114
2115 if (locked)
2116 tlv_value = BS11_LI_PLL_LOCKED;
2117 else
2118 tlv_value = BS11_LI_PLL_STANDALONE;
2119
2120 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002121
2122 return abis_nm_sendmsg(bts, msg);
2123}
2124
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002125/* Set the calibration value of the PLL (work value/set value)
2126 * It depends on the login which one is changed */
2127int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2128{
2129 struct abis_om_hdr *oh;
2130 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002131 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002132
2133 msg = nm_msgb_alloc();
2134 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2135 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2136 BS11_OBJ_TRX1, 0x00, 0x00);
2137
2138 tlv_value[0] = value>>8;
2139 tlv_value[1] = value&0xff;
2140
2141 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2142
2143 return abis_nm_sendmsg(bts, msg);
2144}
2145
Harald Welte1bc09062009-01-18 14:17:52 +00002146int abis_nm_bs11_get_state(struct gsm_bts *bts)
2147{
2148 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2149}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002150
2151/* BS11 SWL */
2152
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002153void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002154
Harald Welte5e4d1b32009-02-01 13:36:56 +00002155struct abis_nm_bs11_sw {
2156 struct gsm_bts *bts;
2157 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002158 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002159 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002160 struct llist_head file_list;
2161 gsm_cbfn *user_cb; /* specified by the user */
2162};
2163static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2164
2165struct file_list_entry {
2166 struct llist_head list;
2167 char fname[PATH_MAX];
2168};
2169
2170struct file_list_entry *fl_dequeue(struct llist_head *queue)
2171{
2172 struct llist_head *lh;
2173
2174 if (llist_empty(queue))
2175 return NULL;
2176
2177 lh = queue->next;
2178 llist_del(lh);
2179
2180 return llist_entry(lh, struct file_list_entry, list);
2181}
2182
2183static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2184{
2185 char linebuf[255];
2186 struct llist_head *lh, *lh2;
2187 FILE *swl;
2188 int rc = 0;
2189
2190 swl = fopen(bs11_sw->swl_fname, "r");
2191 if (!swl)
2192 return -ENODEV;
2193
2194 /* zero the stale file list, if any */
2195 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2196 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002197 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002198 }
2199
2200 while (fgets(linebuf, sizeof(linebuf), swl)) {
2201 char file_id[12+1];
2202 char file_version[80+1];
2203 struct file_list_entry *fle;
2204 static char dir[PATH_MAX];
2205
2206 if (strlen(linebuf) < 4)
2207 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002208
Harald Welte5e4d1b32009-02-01 13:36:56 +00002209 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2210 if (rc < 0) {
2211 perror("ERR parsing SWL file");
2212 rc = -EINVAL;
2213 goto out;
2214 }
2215 if (rc < 2)
2216 continue;
2217
Harald Welte470ec292009-06-26 20:25:23 +02002218 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002219 if (!fle) {
2220 rc = -ENOMEM;
2221 goto out;
2222 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002223
2224 /* construct new filename */
2225 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2226 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2227 strcat(fle->fname, "/");
2228 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002229
2230 llist_add_tail(&fle->list, &bs11_sw->file_list);
2231 }
2232
2233out:
2234 fclose(swl);
2235 return rc;
2236}
2237
2238/* bs11 swload specific callback, passed to abis_nm core swload */
2239static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2240 struct msgb *msg, void *data, void *param)
2241{
2242 struct abis_nm_bs11_sw *bs11_sw = data;
2243 struct file_list_entry *fle;
2244 int rc = 0;
2245
Harald Welte5e4d1b32009-02-01 13:36:56 +00002246 switch (event) {
2247 case NM_MT_LOAD_END_ACK:
2248 fle = fl_dequeue(&bs11_sw->file_list);
2249 if (fle) {
2250 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002251 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002252 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002253 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002254 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002255 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002256 } else {
2257 /* activate the SWL */
2258 rc = abis_nm_software_activate(bs11_sw->bts,
2259 bs11_sw->swl_fname,
2260 bs11_swload_cbfn,
2261 bs11_sw);
2262 }
2263 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002264 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002265 case NM_MT_LOAD_END_NACK:
2266 case NM_MT_LOAD_INIT_ACK:
2267 case NM_MT_LOAD_INIT_NACK:
2268 case NM_MT_ACTIVATE_SW_NACK:
2269 case NM_MT_ACTIVATE_SW_ACK:
2270 default:
2271 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002272 if (bs11_sw->user_cb)
2273 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002274 break;
2275 }
2276
2277 return rc;
2278}
2279
2280/* Siemens provides a SWL file that is a mere listing of all the other
2281 * files that are part of a software release. We need to upload first
2282 * the list file, and then each file that is listed in the list file */
2283int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002284 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002285{
2286 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2287 struct file_list_entry *fle;
2288 int rc = 0;
2289
2290 INIT_LLIST_HEAD(&bs11_sw->file_list);
2291 bs11_sw->bts = bts;
2292 bs11_sw->win_size = win_size;
2293 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002294 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002295
2296 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2297 rc = bs11_read_swl_file(bs11_sw);
2298 if (rc < 0)
2299 return rc;
2300
2301 /* dequeue next item in file list */
2302 fle = fl_dequeue(&bs11_sw->file_list);
2303 if (!fle)
2304 return -EINVAL;
2305
2306 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002307 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002308 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002309 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002310 return rc;
2311}
2312
Harald Welte5083b0b2009-02-02 19:20:52 +00002313#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002314static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002315 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2316 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2317 NM_ATT_BS11_LMT_USER_NAME,
2318
2319 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2320
2321 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2322
2323 NM_ATT_BS11_SW_LOAD_STORED };
2324
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002325static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002326 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2327 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2328 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2329 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002330#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002331
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002332static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002333 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2334 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002335 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002336
2337int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2338{
2339 struct abis_om_hdr *oh;
2340 struct msgb *msg = nm_msgb_alloc();
2341
2342 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2343 /* SiemensHW CCTRL object */
2344 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2345 0x03, 0x00, 0x00);
2346 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2347
2348 return abis_nm_sendmsg(bts, msg);
2349}
Harald Welte268bb402009-02-01 19:11:56 +00002350
2351int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2352{
2353 struct abis_om_hdr *oh;
2354 struct msgb *msg = nm_msgb_alloc();
2355 struct bs11_date_time aet;
2356
2357 get_bs11_date_time(&aet);
2358 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2359 /* SiemensHW CCTRL object */
2360 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2361 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002362 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002363
2364 return abis_nm_sendmsg(bts, msg);
2365}
Harald Welte5c1e4582009-02-15 11:57:29 +00002366
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002367int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002368{
2369 struct abis_om_hdr *oh;
2370 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002371 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002372
2373 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2374 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2375 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2376 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2377
2378 return abis_nm_sendmsg(bts, msg);
2379}
2380
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002381int 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 +02002382{
2383 struct abis_om_hdr *oh;
2384 struct msgb *msg = nm_msgb_alloc();
2385 struct bs11_date_time aet;
2386
2387 get_bs11_date_time(&aet);
2388 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2389 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2390 bport, 0xff, 0x02);
2391 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2392
2393 return abis_nm_sendmsg(bts, msg);
2394}
2395
Harald Welte5c1e4582009-02-15 11:57:29 +00002396/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002397static const char ipaccess_magic[] = "com.ipaccess";
2398
Harald Welte677c21f2009-02-17 13:22:23 +00002399
2400static int abis_nm_rx_ipacc(struct msgb *msg)
2401{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002402 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002403 struct abis_om_hdr *oh = msgb_l2(msg);
2404 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002405 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002406 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002407 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002408 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002409
2410 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002411 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002412 return -EINVAL;
2413 }
2414
Harald Welte193fefc2009-04-30 15:16:27 +00002415 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002416 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002417
Harald Welte15c61722011-05-22 22:45:37 +02002418 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002419
Harald Welte746d6092009-10-19 22:11:11 +02002420 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002421
Harald Welte677c21f2009-02-17 13:22:23 +00002422 switch (foh->msg_type) {
2423 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002424 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002425 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2426 memcpy(&addr,
2427 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2428
2429 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2430 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002431 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002432 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002433 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002434 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002435 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2436 DEBUGPC(DNM, "STREAM=0x%02x ",
2437 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002438 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002439 break;
2440 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002441 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002442 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002443 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002444 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002445 else
2446 DEBUGPC(DNM, "\n");
2447 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002448 case NM_MT_IPACC_SET_NVATTR_ACK:
2449 DEBUGPC(DNM, "SET NVATTR ACK\n");
2450 /* FIXME: decode and show the actual attributes */
2451 break;
2452 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002453 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002454 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002455 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002456 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002457 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002458 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002459 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002460 case NM_MT_IPACC_GET_NVATTR_ACK:
2461 DEBUGPC(DNM, "GET NVATTR ACK\n");
2462 /* FIXME: decode and show the actual attributes */
2463 break;
2464 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002465 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002466 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002467 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002468 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002469 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002470 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002471 break;
Harald Welte15c44172009-10-08 20:15:24 +02002472 case NM_MT_IPACC_SET_ATTR_ACK:
2473 DEBUGPC(DNM, "SET ATTR ACK\n");
2474 break;
2475 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002476 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002477 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002478 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002479 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002480 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002481 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002482 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002483 default:
2484 DEBUGPC(DNM, "unknown\n");
2485 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002486 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002487
2488 /* signal handling */
2489 switch (foh->msg_type) {
2490 case NM_MT_IPACC_RSL_CONNECT_NACK:
2491 case NM_MT_IPACC_SET_NVATTR_NACK:
2492 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002493 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 +01002494 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002495 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002496 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002497 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002498 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 +01002499 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002500 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002501 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002502 default:
2503 break;
2504 }
2505
Harald Welte677c21f2009-02-17 13:22:23 +00002506 return 0;
2507}
2508
Harald Welte193fefc2009-04-30 15:16:27 +00002509/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002510int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2511 uint8_t obj_class, uint8_t bts_nr,
2512 uint8_t trx_nr, uint8_t ts_nr,
2513 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002514{
2515 struct msgb *msg = nm_msgb_alloc();
2516 struct abis_om_hdr *oh;
2517 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002518 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002519
2520 /* construct the 12.21 OM header, observe the erroneous length */
2521 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2522 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2523 oh->mdisc = ABIS_OM_MDISC_MANUF;
2524
2525 /* add the ip.access magic */
2526 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2527 *data++ = sizeof(ipaccess_magic);
2528 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2529
2530 /* fill the 12.21 FOM header */
2531 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2532 foh->msg_type = msg_type;
2533 foh->obj_class = obj_class;
2534 foh->obj_inst.bts_nr = bts_nr;
2535 foh->obj_inst.trx_nr = trx_nr;
2536 foh->obj_inst.ts_nr = ts_nr;
2537
2538 if (attr && attr_len) {
2539 data = msgb_put(msg, attr_len);
2540 memcpy(data, attr, attr_len);
2541 }
2542
2543 return abis_nm_sendmsg(bts, msg);
2544}
Harald Welte677c21f2009-02-17 13:22:23 +00002545
Harald Welte193fefc2009-04-30 15:16:27 +00002546/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002547int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002548 int attr_len)
2549{
Harald Welte2ef156d2010-01-07 20:39:42 +01002550 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2551 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002552 attr_len);
2553}
2554
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002555int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002556 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002557{
2558 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002559 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002560 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2561 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2562
2563 int attr_len = sizeof(attr);
2564
2565 ia.s_addr = htonl(ip);
2566 attr[1] = stream;
2567 attr[3] = port >> 8;
2568 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002569 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002570
2571 /* if ip == 0, we use the default IP */
2572 if (ip == 0)
2573 attr_len -= 5;
2574
2575 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002576 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002577
2578 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2579 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2580 trx->nr, 0xff, attr, attr_len);
2581}
2582
Harald Welte193fefc2009-04-30 15:16:27 +00002583/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002584int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002585{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002586 struct abis_om_hdr *oh;
2587 struct msgb *msg = nm_msgb_alloc();
2588
2589 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2590 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2591 trx->bts->nr, trx->nr, 0xff);
2592
2593 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002594}
Harald Weltedaef5212009-10-24 10:20:41 +02002595
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002596int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2597 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2598 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002599{
2600 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2601 obj_class, bts_nr, trx_nr, ts_nr,
2602 attr, attr_len);
2603}
Harald Welte0f255852009-11-12 14:48:42 +01002604
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002605void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002606{
2607 /* we simply reuse the GSM48 function and overwrite the RAC
2608 * with the Cell ID */
2609 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002610 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002611}
2612
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002613void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2614{
2615 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2616
Harald Welted64c0bc2011-05-30 12:07:53 +02002617 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002618 if (!trx->bts || !trx->bts->oml_link)
2619 return;
2620
2621 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2622 trx->bts->bts_nr, trx->nr, 0xff,
2623 new_state);
2624}
2625
Harald Welte92b1fe42010-03-25 11:45:30 +08002626static const struct value_string ipacc_testres_names[] = {
2627 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2628 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2629 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2630 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2631 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2632 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002633};
2634
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002635const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002636{
Harald Welte92b1fe42010-03-25 11:45:30 +08002637 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002638}
2639
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002640void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002641{
2642 cid->mcc = (buf[0] & 0xf) * 100;
2643 cid->mcc += (buf[0] >> 4) * 10;
2644 cid->mcc += (buf[1] & 0xf) * 1;
2645
2646 if (buf[1] >> 4 == 0xf) {
2647 cid->mnc = (buf[2] & 0xf) * 10;
2648 cid->mnc += (buf[2] >> 4) * 1;
2649 } else {
2650 cid->mnc = (buf[2] & 0xf) * 100;
2651 cid->mnc += (buf[2] >> 4) * 10;
2652 cid->mnc += (buf[1] >> 4) * 1;
2653 }
2654
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002655 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2656 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002657}
2658
Harald Welte0f255852009-11-12 14:48:42 +01002659/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002660int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002661{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002662 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002663 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002664
Harald Welteaf109b92010-07-22 18:14:36 +02002665 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002666
2667 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2668 return -EINVAL;
2669 cur++;
2670
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002671 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002672 cur += 2;
2673
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002674 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002675 cur += 2;
2676
2677 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2678 binf->freq_qual = *cur >> 2;
2679
Harald Welteaf109b92010-07-22 18:14:36 +02002680 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002681 binf->arfcn |= *cur++;
2682
2683 if (binf->info_type & IPAC_BINF_RXLEV)
2684 binf->rx_lev = *cur & 0x3f;
2685 cur++;
2686
2687 if (binf->info_type & IPAC_BINF_RXQUAL)
2688 binf->rx_qual = *cur & 0x7;
2689 cur++;
2690
2691 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002692 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002693 cur += 2;
2694
2695 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002696 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002697 cur += 2;
2698
2699 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002700 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002701 cur += 4;
2702
Harald Weltea780a3d2010-07-30 22:34:42 +02002703#if 0
2704 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002705 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002706#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002707 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002708 cur++;
2709
Harald Welteb40a38f2009-11-13 11:56:05 +01002710 ipac_parse_cgi(&binf->cgi, cur);
2711 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002712
2713 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2714 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2715 cur += sizeof(binf->ba_list_si2);
2716 }
2717
2718 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2719 memcpy(binf->ba_list_si2bis, cur,
2720 sizeof(binf->ba_list_si2bis));
2721 cur += sizeof(binf->ba_list_si2bis);
2722 }
2723
2724 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2725 memcpy(binf->ba_list_si2ter, cur,
2726 sizeof(binf->ba_list_si2ter));
2727 cur += sizeof(binf->ba_list_si2ter);
2728 }
2729
2730 return 0;
2731}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002732
2733void abis_nm_clear_queue(struct gsm_bts *bts)
2734{
2735 struct msgb *msg;
2736
2737 while (!llist_empty(&bts->abis_queue)) {
2738 msg = msgb_dequeue(&bts->abis_queue);
2739 msgb_free(msg);
2740 }
2741
2742 bts->abis_nm_pend = 0;
2743}