blob: 3bf55ec5667ee205387275361fec45d4ac0c5d90 [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 Freyther686191a2014-04-04 12:56:34 +020096static struct abis_om_fom_hdr *fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020097 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;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200109 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000110}
111
Harald Welte8470bf22008-12-25 23:28:35 +0000112static struct msgb *nm_msgb_alloc(void)
113{
Harald Welte966636f2009-06-26 19:39:35 +0200114 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
115 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000116}
117
Harald Welte15eae8d2011-09-26 23:43:23 +0200118int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200119{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200120 msg->l2h = msg->data;
121
122 if (!msg->dst) {
123 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
124 return -EINVAL;
125 }
126
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200127 return abis_sendmsg(msg);
128}
129
Harald Welte52b1f982008-12-23 20:25:15 +0000130/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100131static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000132{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200133 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000134
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100135 /* queue OML messages */
136 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
137 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200138 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100139 } else {
140 msgb_enqueue(&bts->abis_queue, msg);
141 return 0;
142 }
143
144}
145
146int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
147{
148 OBSC_NM_W_ACK_CB(msg) = 1;
149 return abis_nm_queue_msg(bts, msg);
150}
151
152static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
153{
154 OBSC_NM_W_ACK_CB(msg) = 0;
155 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000156}
157
Harald Welte4724f992009-01-18 18:01:49 +0000158static int abis_nm_rcvmsg_sw(struct msgb *mb);
159
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100160int nm_is_running(struct gsm_nm_state *s) {
161 return (s->operational == NM_OPSTATE_ENABLED) && (
162 (s->availability == NM_AVSTATE_OK) ||
163 (s->availability == 0xff)
164 );
165}
166
Harald Weltee0590df2009-02-15 03:34:15 +0000167/* Update the administrative state of a given object in our in-memory data
168 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200169static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
170 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000171{
Harald Welteaeedeb42009-05-01 13:08:14 +0000172 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100173 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000174
Harald Welteaf9b8102011-03-06 21:20:38 +0100175 memset(&nsd, 0, sizeof(nsd));
176
Harald Welte978714d2011-06-06 18:31:20 +0200177 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100178 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100179 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200180 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000181 if (!nm_state)
182 return -1;
183
184 new_state = *nm_state;
185 new_state.administrative = adm_state;
186
Harald Weltef38ca9a2011-03-06 22:11:32 +0100187 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100188 nsd.obj_class = obj_class;
189 nsd.old_state = nm_state;
190 nsd.new_state = &new_state;
191 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200192 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000193
194 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000195
Harald Weltef338a032011-01-14 15:55:42 +0100196 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000197}
198
Harald Welte97ed1e72009-02-06 13:38:02 +0000199static int abis_nm_rx_statechg_rep(struct msgb *mb)
200{
Harald Weltee0590df2009-02-15 03:34:15 +0000201 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000202 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200203 struct e1inp_sign_link *sign_link = mb->dst;
204 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000205 struct tlv_parsed tp;
206 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000207
Harald Welte23897662009-05-01 14:52:51 +0000208 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000209
Harald Welte8b697c72009-06-05 19:18:45 +0000210 memset(&new_state, 0, sizeof(new_state));
211
Harald Welte978714d2011-06-06 18:31:20 +0200212 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000213 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100214 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000215 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000216 }
Harald Weltee0590df2009-02-15 03:34:15 +0000217
218 new_state = *nm_state;
219
Harald Welte39315c42010-01-10 18:01:52 +0100220 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000221 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
222 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200223 DEBUGPC(DNM, "OP_STATE=%s ",
224 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000225 }
226 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000227 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
228 new_state.availability = 0xff;
229 else
230 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200231 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
232 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000233 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100234 } else
235 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000236 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
237 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200238 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200239 get_value_string(abis_nm_adm_state_names,
240 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000241 }
242 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000243
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100244 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
245 new_state.operational != nm_state->operational ||
246 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000247 /* Update the operational state of a given object in our in-memory data
248 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100249 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200250 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100251 nsd.obj_class = foh->obj_class;
252 nsd.old_state = nm_state;
253 nsd.new_state = &new_state;
254 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100255 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200256 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100257 nm_state->operational = new_state.operational;
258 nm_state->availability = new_state.availability;
259 if (nm_state->administrative == 0)
260 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000261 }
262#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000263 if (op_state == 1) {
264 /* try to enable objects that are disabled */
265 abis_nm_opstart(bts, foh->obj_class,
266 foh->obj_inst.bts_nr,
267 foh->obj_inst.trx_nr,
268 foh->obj_inst.ts_nr);
269 }
Harald Weltee0590df2009-02-15 03:34:15 +0000270#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000271 return 0;
272}
273
Harald Welte0db97b22009-05-01 17:22:47 +0000274static int rx_fail_evt_rep(struct msgb *mb)
275{
276 struct abis_om_hdr *oh = msgb_l2(mb);
277 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200278 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000279 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100280 const uint8_t *p_val;
281 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000282
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200283 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000284
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200285 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000286
287 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200288 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
289 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000290 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200291 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
292 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100293 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
294 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200295 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 +0100296 }
297 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
298 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
299 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
300 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200301 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100302 talloc_free(p_text);
303 }
304 }
Harald Welte0db97b22009-05-01 17:22:47 +0000305
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200306 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000307
308 return 0;
309}
310
Harald Welte97ed1e72009-02-06 13:38:02 +0000311static int abis_nm_rcvmsg_report(struct msgb *mb)
312{
313 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200314 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000315
Harald Welte15c61722011-05-22 22:45:37 +0200316 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000317
Harald Welte97ed1e72009-02-06 13:38:02 +0000318 //nmh->cfg->report_cb(mb, foh);
319
320 switch (mt) {
321 case NM_MT_STATECHG_EVENT_REP:
322 return abis_nm_rx_statechg_rep(mb);
323 break;
Harald Welte34a99682009-02-13 02:41:40 +0000324 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000325 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200326 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000327 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000328 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000329 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200330 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000331 break;
Harald Weltec7310382009-08-08 00:02:36 +0200332 case NM_MT_TEST_REP:
333 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200334 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200335 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000336 default:
Harald Welte23897662009-05-01 14:52:51 +0000337 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000338 break;
339
Harald Welte97ed1e72009-02-06 13:38:02 +0000340 };
341
Harald Welte97ed1e72009-02-06 13:38:02 +0000342 return 0;
343}
344
Harald Welte34a99682009-02-13 02:41:40 +0000345/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200346static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
347 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000348{
349 struct abis_om_hdr *oh;
350 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200351 uint8_t len = swdesc_len;
352 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000353
354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
355 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
356
357 trailer = msgb_put(msg, swdesc_len);
358 memcpy(trailer, sw_desc, swdesc_len);
359
360 return abis_nm_sendmsg(bts, msg);
361}
362
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100363int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
364 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100365{
366 static const struct tlv_definition sw_descr_def = {
367 .def = {
368 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
369 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
370 },
371 };
372
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100373 size_t pos = 0;
374 int desc_pos = 0;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100375
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100376 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
377 uint8_t tag;
378 uint16_t tag_len;
379 const uint8_t *val;
380 int len;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100381
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100382 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
383 desc[desc_pos].start = &sw_descr[pos];
384
385 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
386 * nested nature and the fact you have to assume it contains only two sub
387 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
388 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
389 LOGP(DNM, LOGL_ERROR,
390 "SW_DESCR attribute identifier not found!\n");
391 return -1;
392 }
393
394 pos += 1;
395 len = tlv_parse_one(&tag, &tag_len, &val,
396 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
397 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
398 LOGP(DNM, LOGL_ERROR,
399 "FILE_ID attribute identifier not found!\n");
400 return -2;
401 }
402 desc[desc_pos].file_id = val;
403 desc[desc_pos].file_id_len = tag_len;
404 pos += len;
405
406
407 len = tlv_parse_one(&tag, &tag_len, &val,
408 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
409 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
410 LOGP(DNM, LOGL_ERROR,
411 "FILE_VERSION attribute identifier not found!\n");
412 return -3;
413 }
414 desc[desc_pos].file_ver = val;
415 desc[desc_pos].file_ver_len = tag_len;
416 pos += len;
417
418 /* final size */
419 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100420 }
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100421
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100422 return desc_pos;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100423}
424
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100425int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
426 const size_t size)
427{
428 int res = 0;
429 int i;
430
431 for (i = 1; i < size; ++i) {
432 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
433 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
434 res = i;
435 }
436 }
437
438 return res;
439}
440
Harald Welte34a99682009-02-13 02:41:40 +0000441static int abis_nm_rx_sw_act_req(struct msgb *mb)
442{
443 struct abis_om_hdr *oh = msgb_l2(mb);
444 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200445 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200446 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200447 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100448 int ret, sw_config_len, len;
449 struct abis_nm_sw_descr sw_descr[5];
Harald Welte34a99682009-02-13 02:41:40 +0000450
Harald Welte15c61722011-05-22 22:45:37 +0200451 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200452
453 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000454
Harald Welte97a282b2010-03-14 15:37:43 +0800455 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000456
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200457 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000458 foh->obj_inst.bts_nr,
459 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800460 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000461 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100462 if (ret != 0) {
463 LOGP(DNM, LOGL_ERROR,
464 "Sending SW ActReq ACK failed: %d\n", ret);
465 return ret;
466 }
Harald Welte34a99682009-02-13 02:41:40 +0000467
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200468 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200469 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
470 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
471 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100472 LOGP(DNM, LOGL_ERROR,
473 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200474 return -EINVAL;
475 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200476 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200477 }
478
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100479 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100480 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100481 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100482 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100483 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100484 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100485 }
Mike Habena03f9772009-10-01 14:56:13 +0200486
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100487 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
488 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
489
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200490 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000491 foh->obj_inst.bts_nr,
492 foh->obj_inst.trx_nr,
493 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100494 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte34a99682009-02-13 02:41:40 +0000495}
496
Harald Weltee0590df2009-02-15 03:34:15 +0000497/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
498static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
499{
500 struct abis_om_hdr *oh = msgb_l2(mb);
501 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200502 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000503 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200504 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000505
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200506 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000507 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
508 return -EINVAL;
509
510 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
511
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200512 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000513}
514
Harald Welteee670472009-02-22 21:58:49 +0000515static int abis_nm_rx_lmt_event(struct msgb *mb)
516{
517 struct abis_om_hdr *oh = msgb_l2(mb);
518 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200519 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000520 struct tlv_parsed tp;
521
522 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200523 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000524 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
525 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200526 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000527 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
528 }
529 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
530 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200531 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000532 DEBUGPC(DNM, "Level=%u ", level);
533 }
534 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
535 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
536 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
537 DEBUGPC(DNM, "Username=%s ", name);
538 }
539 DEBUGPC(DNM, "\n");
540 /* FIXME: parse LMT LOGON TIME */
541 return 0;
542}
543
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200544void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100545{
546 int wait = 0;
547 struct msgb *msg;
548 /* the queue is empty */
549 while (!llist_empty(&bts->abis_queue)) {
550 msg = msgb_dequeue(&bts->abis_queue);
551 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200552 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100553
554 if (wait)
555 break;
556 }
557
558 bts->abis_nm_pend = wait;
559}
560
Harald Welte52b1f982008-12-23 20:25:15 +0000561/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000562static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000563{
Harald Welte6c96ba52009-05-01 13:03:40 +0000564 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000565 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200566 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200567 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100568 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000569
570 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000571 if (is_report(mt))
572 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000573
Harald Welte15c61722011-05-22 22:45:37 +0200574 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000575 return abis_nm_rcvmsg_sw(mb);
576
Harald Welte15c61722011-05-22 22:45:37 +0200577 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800578 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000579 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200580
Harald Welte15c61722011-05-22 22:45:37 +0200581 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200582
Harald Welte15c61722011-05-22 22:45:37 +0200583 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000584
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200585 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000586 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200587 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200588 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000589 else
590 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200591
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800592 nack_data.msg = mb;
593 nack_data.mt = mt;
Holger Hans Peter Freytherde1674a2012-11-11 18:26:23 +0100594 nack_data.bts = sign_link->trx->bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200595 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200596 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200597 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000598 }
Harald Weltead384642008-12-26 10:20:07 +0000599#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000600 /* check if last message is to be acked */
601 if (is_ack_nack(nmh->last_msgtype)) {
602 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100603 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000604 /* we got our ACK, continue sending the next msg */
605 } else if (mt == MT_NACK(nmh->last_msgtype)) {
606 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100607 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000608 /* FIXME: somehow signal this to the caller */
609 } else {
610 /* really strange things happen */
611 return -EINVAL;
612 }
613 }
Harald Weltead384642008-12-26 10:20:07 +0000614#endif
615
Harald Welte97ed1e72009-02-06 13:38:02 +0000616 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000617 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100618 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000619 break;
Harald Welte34a99682009-02-13 02:41:40 +0000620 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100621 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000622 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000623 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100624 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000625 break;
Harald Welte1989c082009-08-06 17:58:31 +0200626 case NM_MT_CONN_MDROP_LINK_ACK:
627 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
628 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100629 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200630 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100631 break;
632 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200633 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100634 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100635 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100636 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000637 }
638
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200639 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100640 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000641}
642
Harald Welte677c21f2009-02-17 13:22:23 +0000643static int abis_nm_rx_ipacc(struct msgb *mb);
644
645static int abis_nm_rcvmsg_manuf(struct msgb *mb)
646{
647 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200648 struct e1inp_sign_link *sign_link = mb->dst;
649 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000650
651 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100652 case GSM_BTS_TYPE_NANOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +0200653 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte677c21f2009-02-17 13:22:23 +0000654 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200655 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000656 break;
657 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100658 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
659 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000660 rc = 0;
661 break;
662 }
663
664 return rc;
665}
666
Harald Welte52b1f982008-12-23 20:25:15 +0000667/* High-Level API */
668/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000669int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000670{
Harald Welte52b1f982008-12-23 20:25:15 +0000671 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000672 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000673
674 /* Various consistency checks */
675 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100676 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000677 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200678 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
679 rc = -EINVAL;
680 goto err;
681 }
Harald Welte52b1f982008-12-23 20:25:15 +0000682 }
683 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100684 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000685 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200686 rc = -EINVAL;
687 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000688 }
Harald Welte702d8702008-12-26 20:25:35 +0000689#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200690 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000691 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000692 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100693 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000694 oh->length + sizeof(*oh), l2_len);
695 return -EINVAL;
696 }
Harald Welte702d8702008-12-26 20:25:35 +0000697 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100698 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 +0000699#endif
Harald Weltead384642008-12-26 10:20:07 +0000700 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000701
702 switch (oh->mdisc) {
703 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000704 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000705 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000706 case ABIS_OM_MDISC_MANUF:
707 rc = abis_nm_rcvmsg_manuf(msg);
708 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000709 case ABIS_OM_MDISC_MMI:
710 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100711 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000712 oh->mdisc);
713 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000714 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100715 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000716 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200717 rc = -EINVAL;
718 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000719 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200720err:
Harald Weltead384642008-12-26 10:20:07 +0000721 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000722 return rc;
723}
724
725#if 0
726/* initialized all resources */
727struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
728{
729 struct abis_nm_h *nmh;
730
731 nmh = malloc(sizeof(*nmh));
732 if (!nmh)
733 return NULL;
734
735 nmh->cfg = cfg;
736
737 return nmh;
738}
739
740/* free all resources */
741void abis_nm_fini(struct abis_nm_h *nmh)
742{
743 free(nmh);
744}
745#endif
746
747/* Here we are trying to define a high-level API that can be used by
748 * the actual BSC implementation. However, the architecture is currently
749 * still under design. Ideally the calls to this API would be synchronous,
750 * while the underlying stack behind the APi runs in a traditional select
751 * based state machine.
752 */
753
Harald Welte4724f992009-01-18 18:01:49 +0000754/* 6.2 Software Load: */
755enum sw_state {
756 SW_STATE_NONE,
757 SW_STATE_WAIT_INITACK,
758 SW_STATE_WAIT_SEGACK,
759 SW_STATE_WAIT_ENDACK,
760 SW_STATE_WAIT_ACTACK,
761 SW_STATE_ERROR,
762};
Harald Welte52b1f982008-12-23 20:25:15 +0000763
Harald Welte52b1f982008-12-23 20:25:15 +0000764struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000765 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800766 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000767 gsm_cbfn *cbfn;
768 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000769 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000770
Harald Welte52b1f982008-12-23 20:25:15 +0000771 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200772 uint8_t obj_class;
773 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000774
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200775 uint8_t file_id[255];
776 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000777
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200778 uint8_t file_version[255];
779 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000780
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200781 uint8_t window_size;
782 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000783
784 int fd;
785 FILE *stream;
786 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000787 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000788};
789
Harald Welte4724f992009-01-18 18:01:49 +0000790static struct abis_nm_sw g_sw;
791
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100792static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
793{
794 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
795 msgb_v_put(msg, NM_ATT_SW_DESCR);
796 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
797 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
798 sw->file_version);
799 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
800 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
801 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
802 sw->file_version);
803 } else {
804 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
805 }
806}
807
Harald Welte4724f992009-01-18 18:01:49 +0000808/* 6.2.1 / 8.3.1: Load Data Initiate */
809static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000810{
Harald Welte4724f992009-01-18 18:01:49 +0000811 struct abis_om_hdr *oh;
812 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200813 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000814
815 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
816 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
817 sw->obj_instance[0], sw->obj_instance[1],
818 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100819
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100820 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000821 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
822
823 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000824}
825
Harald Welte1602ade2009-01-29 21:12:39 +0000826static int is_last_line(FILE *stream)
827{
828 char next_seg_buf[256];
829 long pos;
830
831 /* check if we're sending the last line */
832 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200833
834 /* Did ftell fail? Then we are at the end for sure */
835 if (pos < 0)
836 return 1;
837
Harald Welte1602ade2009-01-29 21:12:39 +0000838 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
839 fseek(stream, pos, SEEK_SET);
840 return 1;
841 }
842
843 fseek(stream, pos, SEEK_SET);
844 return 0;
845}
846
Harald Welte4724f992009-01-18 18:01:49 +0000847/* 6.2.2 / 8.3.2 Load Data Segment */
848static int sw_load_segment(struct abis_nm_sw *sw)
849{
850 struct abis_om_hdr *oh;
851 struct msgb *msg = nm_msgb_alloc();
852 char seg_buf[256];
853 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000854 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200855 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000856
857 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000858
859 switch (sw->bts->type) {
860 case GSM_BTS_TYPE_BS11:
861 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
862 perror("fgets reading segment");
863 return -EINVAL;
864 }
865 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000866
867 /* check if we're sending the last line */
868 sw->last_seg = is_last_line(sw->stream);
869 if (sw->last_seg)
870 seg_buf[1] = 0;
871 else
872 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000873
874 len = strlen(line_buf) + 2;
875 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200876 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000877 /* BS11 wants CR + LF in excess of the TLV length !?! */
878 tlv[1] -= 2;
879
880 /* we only now know the exact length for the OM hdr */
881 len = strlen(line_buf)+2;
882 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100883 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200884 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100885 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
886 if (len < 0) {
887 perror("read failed");
888 return -EINVAL;
889 }
890
891 if (len != IPACC_SEGMENT_SIZE)
892 sw->last_seg = 1;
893
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100894 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200895 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100896 len += 3;
897 break;
898 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000899 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100900 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000901 /* FIXME: Other BTS types */
902 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000903 }
Harald Welte4724f992009-01-18 18:01:49 +0000904
Harald Welte4724f992009-01-18 18:01:49 +0000905 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
906 sw->obj_instance[0], sw->obj_instance[1],
907 sw->obj_instance[2]);
908
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100909 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000910}
911
912/* 6.2.4 / 8.3.4 Load Data End */
913static int sw_load_end(struct abis_nm_sw *sw)
914{
915 struct abis_om_hdr *oh;
916 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200917 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000918
919 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
920 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
921 sw->obj_instance[0], sw->obj_instance[1],
922 sw->obj_instance[2]);
923
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100924 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000925 return abis_nm_sendmsg(sw->bts, msg);
926}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000927
Harald Welte52b1f982008-12-23 20:25:15 +0000928/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000929static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000930{
Harald Welte4724f992009-01-18 18:01:49 +0000931 struct abis_om_hdr *oh;
932 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200933 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000934
Harald Welte4724f992009-01-18 18:01:49 +0000935 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
936 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
937 sw->obj_instance[0], sw->obj_instance[1],
938 sw->obj_instance[2]);
939
940 /* FIXME: this is BS11 specific format */
941 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
942 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
943 sw->file_version);
944
945 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000946}
Harald Welte4724f992009-01-18 18:01:49 +0000947
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100948struct sdp_firmware {
949 char magic[4];
950 char more_magic[4];
951 unsigned int header_length;
952 unsigned int file_length;
953} __attribute__ ((packed));
954
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100955static int parse_sdp_header(struct abis_nm_sw *sw)
956{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100957 struct sdp_firmware firmware_header;
958 int rc;
959 struct stat stat;
960
961 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
962 if (rc != sizeof(firmware_header)) {
963 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
964 return -1;
965 }
966
967 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
968 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
969 return -1;
970 }
971
972 if (firmware_header.more_magic[0] != 0x10 ||
973 firmware_header.more_magic[1] != 0x02 ||
974 firmware_header.more_magic[2] != 0x00 ||
975 firmware_header.more_magic[3] != 0x00) {
976 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
977 return -1;
978 }
979
980
981 if (fstat(sw->fd, &stat) == -1) {
982 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
983 return -1;
984 }
985
986 if (ntohl(firmware_header.file_length) != stat.st_size) {
987 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
988 return -1;
989 }
990
991 /* go back to the start as we checked the whole filesize.. */
992 lseek(sw->fd, 0l, SEEK_SET);
993 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
994 "There might be checksums in the file that are not\n"
995 "verified and incomplete firmware might be flashed.\n"
996 "There is absolutely no WARRANTY that flashing will\n"
997 "work.\n");
998 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100999}
1000
Harald Welte4724f992009-01-18 18:01:49 +00001001static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1002{
1003 char file_id[12+1];
1004 char file_version[80+1];
1005 int rc;
1006
1007 sw->fd = open(fname, O_RDONLY);
1008 if (sw->fd < 0)
1009 return sw->fd;
1010
1011 switch (sw->bts->type) {
1012 case GSM_BTS_TYPE_BS11:
1013 sw->stream = fdopen(sw->fd, "r");
1014 if (!sw->stream) {
1015 perror("fdopen");
1016 return -1;
1017 }
1018 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001019 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001020 file_id, file_version);
1021 if (rc != 2) {
1022 perror("parsing header line of software file");
1023 return -1;
1024 }
1025 strcpy((char *)sw->file_id, file_id);
1026 sw->file_id_len = strlen(file_id);
1027 strcpy((char *)sw->file_version, file_version);
1028 sw->file_version_len = strlen(file_version);
1029 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001030 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001031 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001032 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001033 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001034 rc = parse_sdp_header(sw);
1035 if (rc < 0) {
1036 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1037 return -1;
1038 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001039
1040 strcpy((char *)sw->file_id, "id");
1041 sw->file_id_len = 3;
1042 strcpy((char *)sw->file_version, "version");
1043 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001044 break;
Harald Welte4724f992009-01-18 18:01:49 +00001045 default:
1046 /* We don't know how to treat them yet */
1047 close(sw->fd);
1048 return -EINVAL;
1049 }
1050
1051 return 0;
1052}
1053
1054static void sw_close_file(struct abis_nm_sw *sw)
1055{
1056 switch (sw->bts->type) {
1057 case GSM_BTS_TYPE_BS11:
1058 fclose(sw->stream);
1059 break;
1060 default:
1061 close(sw->fd);
1062 break;
1063 }
1064}
1065
1066/* Fill the window */
1067static int sw_fill_window(struct abis_nm_sw *sw)
1068{
1069 int rc;
1070
1071 while (sw->seg_in_window < sw->window_size) {
1072 rc = sw_load_segment(sw);
1073 if (rc < 0)
1074 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001075 if (sw->last_seg)
1076 break;
Harald Welte4724f992009-01-18 18:01:49 +00001077 }
1078 return 0;
1079}
1080
1081/* callback function from abis_nm_rcvmsg() handler */
1082static int abis_nm_rcvmsg_sw(struct msgb *mb)
1083{
1084 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001085 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001086 int rc = -1;
1087 struct abis_nm_sw *sw = &g_sw;
1088 enum sw_state old_state = sw->state;
1089
Harald Welte3ffd1372009-02-01 22:15:49 +00001090 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001091
1092 switch (sw->state) {
1093 case SW_STATE_WAIT_INITACK:
1094 switch (foh->msg_type) {
1095 case NM_MT_LOAD_INIT_ACK:
1096 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001097 if (sw->cbfn)
1098 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1099 NM_MT_LOAD_INIT_ACK, mb,
1100 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001101 rc = sw_fill_window(sw);
1102 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001103 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001104 break;
1105 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001106 if (sw->forced) {
1107 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1108 "Init NACK\n");
1109 if (sw->cbfn)
1110 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1111 NM_MT_LOAD_INIT_ACK, mb,
1112 sw->cb_data, NULL);
1113 rc = sw_fill_window(sw);
1114 sw->state = SW_STATE_WAIT_SEGACK;
1115 } else {
1116 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001117 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001118 if (sw->cbfn)
1119 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1120 NM_MT_LOAD_INIT_NACK, mb,
1121 sw->cb_data, NULL);
1122 sw->state = SW_STATE_ERROR;
1123 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001124 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001125 break;
1126 }
1127 break;
1128 case SW_STATE_WAIT_SEGACK:
1129 switch (foh->msg_type) {
1130 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001131 if (sw->cbfn)
1132 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1133 NM_MT_LOAD_SEG_ACK, mb,
1134 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001135 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001136 if (!sw->last_seg) {
1137 /* fill window with more segments */
1138 rc = sw_fill_window(sw);
1139 sw->state = SW_STATE_WAIT_SEGACK;
1140 } else {
1141 /* end the transfer */
1142 sw->state = SW_STATE_WAIT_ENDACK;
1143 rc = sw_load_end(sw);
1144 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001145 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001146 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001147 case NM_MT_LOAD_ABORT:
1148 if (sw->cbfn)
1149 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1150 NM_MT_LOAD_ABORT, mb,
1151 sw->cb_data, NULL);
1152 break;
Harald Welte4724f992009-01-18 18:01:49 +00001153 }
1154 break;
1155 case SW_STATE_WAIT_ENDACK:
1156 switch (foh->msg_type) {
1157 case NM_MT_LOAD_END_ACK:
1158 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001159 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1160 sw->bts->nr);
1161 sw->state = SW_STATE_NONE;
1162 if (sw->cbfn)
1163 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1164 NM_MT_LOAD_END_ACK, mb,
1165 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001166 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001167 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001168 break;
1169 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001170 if (sw->forced) {
1171 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1172 "End NACK\n");
1173 sw->state = SW_STATE_NONE;
1174 if (sw->cbfn)
1175 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1176 NM_MT_LOAD_END_ACK, mb,
1177 sw->cb_data, NULL);
1178 } else {
1179 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001180 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001181 sw->state = SW_STATE_ERROR;
1182 if (sw->cbfn)
1183 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1184 NM_MT_LOAD_END_NACK, mb,
1185 sw->cb_data, NULL);
1186 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001187 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001188 break;
1189 }
1190 case SW_STATE_WAIT_ACTACK:
1191 switch (foh->msg_type) {
1192 case NM_MT_ACTIVATE_SW_ACK:
1193 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001194 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001195 sw->state = SW_STATE_NONE;
1196 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001197 if (sw->cbfn)
1198 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1199 NM_MT_ACTIVATE_SW_ACK, mb,
1200 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001201 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001202 break;
1203 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001204 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001205 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001206 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001207 if (sw->cbfn)
1208 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1209 NM_MT_ACTIVATE_SW_NACK, mb,
1210 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001211 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001212 break;
1213 }
1214 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001215 switch (foh->msg_type) {
1216 case NM_MT_ACTIVATE_SW_ACK:
1217 rc = 0;
1218 break;
1219 }
1220 break;
Harald Welte4724f992009-01-18 18:01:49 +00001221 case SW_STATE_ERROR:
1222 break;
1223 }
1224
1225 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001226 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001227 foh->msg_type, old_state, sw->state);
1228
1229 return rc;
1230}
1231
1232/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001233int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001234 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001235 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001236{
1237 struct abis_nm_sw *sw = &g_sw;
1238 int rc;
1239
Harald Welte5e4d1b32009-02-01 13:36:56 +00001240 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1241 bts->nr, fname);
1242
Harald Welte4724f992009-01-18 18:01:49 +00001243 if (sw->state != SW_STATE_NONE)
1244 return -EBUSY;
1245
1246 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001247 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001248
1249 switch (bts->type) {
1250 case GSM_BTS_TYPE_BS11:
1251 sw->obj_class = NM_OC_SITE_MANAGER;
1252 sw->obj_instance[0] = 0xff;
1253 sw->obj_instance[1] = 0xff;
1254 sw->obj_instance[2] = 0xff;
1255 break;
1256 case GSM_BTS_TYPE_NANOBTS:
1257 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001258 sw->obj_instance[0] = sw->bts->nr;
1259 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001260 sw->obj_instance[2] = 0xff;
1261 break;
1262 case GSM_BTS_TYPE_UNKNOWN:
1263 default:
1264 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1265 return -1;
1266 break;
1267 }
Harald Welte4724f992009-01-18 18:01:49 +00001268 sw->window_size = win_size;
1269 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001270 sw->cbfn = cbfn;
1271 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001272 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001273
1274 rc = sw_open_file(sw, fname);
1275 if (rc < 0) {
1276 sw->state = SW_STATE_NONE;
1277 return rc;
1278 }
1279
1280 return sw_load_init(sw);
1281}
Harald Welte52b1f982008-12-23 20:25:15 +00001282
Harald Welte1602ade2009-01-29 21:12:39 +00001283int abis_nm_software_load_status(struct gsm_bts *bts)
1284{
1285 struct abis_nm_sw *sw = &g_sw;
1286 struct stat st;
1287 int rc, percent;
1288
1289 rc = fstat(sw->fd, &st);
1290 if (rc < 0) {
1291 perror("ERROR during stat");
1292 return rc;
1293 }
1294
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001295 if (sw->stream)
1296 percent = (ftell(sw->stream) * 100) / st.st_size;
1297 else
1298 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001299 return percent;
1300}
1301
Harald Welte5e4d1b32009-02-01 13:36:56 +00001302/* Activate the specified software into the BTS */
1303int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1304 gsm_cbfn *cbfn, void *cb_data)
1305{
1306 struct abis_nm_sw *sw = &g_sw;
1307 int rc;
1308
1309 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1310 bts->nr, fname);
1311
1312 if (sw->state != SW_STATE_NONE)
1313 return -EBUSY;
1314
1315 sw->bts = bts;
1316 sw->obj_class = NM_OC_SITE_MANAGER;
1317 sw->obj_instance[0] = 0xff;
1318 sw->obj_instance[1] = 0xff;
1319 sw->obj_instance[2] = 0xff;
1320 sw->state = SW_STATE_WAIT_ACTACK;
1321 sw->cbfn = cbfn;
1322 sw->cb_data = cb_data;
1323
1324 /* Open the file in order to fill some sw struct members */
1325 rc = sw_open_file(sw, fname);
1326 if (rc < 0) {
1327 sw->state = SW_STATE_NONE;
1328 return rc;
1329 }
1330 sw_close_file(sw);
1331
1332 return sw_activate(sw);
1333}
1334
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001335static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1336 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001337{
Harald Welteadaf08b2009-01-18 11:08:10 +00001338 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001339 ch->bts_port = bts_port;
1340 ch->timeslot = ts_nr;
1341 ch->subslot = subslot_nr;
1342}
1343
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001344int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1345 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1346 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001347{
1348 struct abis_om_hdr *oh;
1349 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001350 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001351 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001352
1353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1354 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1355 bts->bts_nr, trx_nr, 0xff);
1356
Harald Welte8470bf22008-12-25 23:28:35 +00001357 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001358
1359 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1360 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1361
1362 return abis_nm_sendmsg(bts, msg);
1363}
1364
1365/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1366int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001367 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001368{
Harald Welte8470bf22008-12-25 23:28:35 +00001369 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001370 struct abis_om_hdr *oh;
1371 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001372 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001373
1374 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001375 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001376 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1377
1378 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1379 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1380
1381 return abis_nm_sendmsg(bts, msg);
1382}
1383
1384#if 0
1385int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1386 struct abis_nm_abis_channel *chan)
1387{
1388}
1389#endif
1390
1391int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001392 uint8_t e1_port, uint8_t e1_timeslot,
1393 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001394{
1395 struct gsm_bts *bts = ts->trx->bts;
1396 struct abis_om_hdr *oh;
1397 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001398 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001399
1400 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1401 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001402 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001403
1404 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1405 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1406
Harald Weltef325eb42009-02-19 17:07:39 +00001407 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1408 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001409 e1_port, e1_timeslot, e1_subslot);
1410
Harald Welte52b1f982008-12-23 20:25:15 +00001411 return abis_nm_sendmsg(bts, msg);
1412}
1413
1414#if 0
1415int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1416 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001417 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001418{
1419}
1420#endif
1421
Harald Weltefe568f22012-08-14 19:15:57 +02001422/* Chapter 8.11.1 */
1423int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1424 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1425 uint8_t *attr, uint8_t attr_len)
1426{
1427 struct abis_om_hdr *oh;
1428 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001429
1430 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1431
1432 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1433 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1434 bts_nr, trx_nr, ts_nr);
1435 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1436
1437 return abis_nm_sendmsg(bts, msg);
1438}
1439
Harald Welte22af0db2009-02-14 15:41:08 +00001440/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001441int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001442{
1443 struct abis_om_hdr *oh;
1444 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001445 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001446
1447 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1448
1449 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001450 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 +00001451 cur = msgb_put(msg, attr_len);
1452 memcpy(cur, attr, attr_len);
1453
1454 return abis_nm_sendmsg(bts, msg);
1455}
1456
1457/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001458int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001459{
1460 struct abis_om_hdr *oh;
1461 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001462 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001463
1464 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1465
1466 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1467 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001468 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001469 cur = msgb_put(msg, attr_len);
1470 memcpy(cur, attr, attr_len);
1471
1472 return abis_nm_sendmsg(trx->bts, msg);
1473}
1474
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001475int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1476{
1477 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1478 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1479}
1480
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001481static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1482 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001483{
1484 int i;
1485
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001486 *reason = "Reason unknown";
1487
Harald Welte39c7deb2009-08-09 21:49:48 +02001488 /* As it turns out, the BS-11 has some very peculiar restrictions
1489 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301490 switch (ts->trx->bts->type) {
1491 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001492 switch (chan_comb) {
1493 case NM_CHANC_TCHHalf:
1494 case NM_CHANC_TCHHalf2:
1495 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001496 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001497 return -EINVAL;
1498 case NM_CHANC_SDCCH:
1499 /* only one SDCCH/8 per TRX */
1500 for (i = 0; i < TRX_NR_TS; i++) {
1501 if (i == ts->nr)
1502 continue;
1503 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001504 NM_CHANC_SDCCH) {
1505 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001506 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001507 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001508 }
1509 /* not allowed for TS0 of BCCH-TRX */
1510 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001511 ts->nr == 0) {
1512 *reason = "SDCCH/8 must be on TS0.";
1513 return -EINVAL;
1514 }
1515
Harald Welte39c7deb2009-08-09 21:49:48 +02001516 /* not on the same TRX that has a BCCH+SDCCH4
1517 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001518 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001519 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001520 ts->trx->ts[0].nm_chan_comb == 8)) {
1521 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1522 return -EINVAL;
1523 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001524 break;
1525 case NM_CHANC_mainBCCH:
1526 case NM_CHANC_BCCHComb:
1527 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001528 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1529 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001530 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001531 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001532 break;
1533 case NM_CHANC_BCCH:
1534 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001535 if (ts->trx != ts->trx->bts->c0) {
1536 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001537 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001538 }
1539 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1540 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001541 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001542 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001543 break;
1544 case 8: /* this is not like 08.58, but in fact
1545 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1546 /* FIXME: only one CBCH allowed per cell */
1547 break;
1548 }
Harald Welted6575f92009-12-02 02:45:23 +05301549 break;
1550 case GSM_BTS_TYPE_NANOBTS:
1551 switch (ts->nr) {
1552 case 0:
1553 if (ts->trx->nr == 0) {
1554 /* only on TRX0 */
1555 switch (chan_comb) {
1556 case NM_CHANC_BCCH:
1557 case NM_CHANC_mainBCCH:
1558 case NM_CHANC_BCCHComb:
1559 return 0;
1560 break;
1561 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001562 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301563 return -EINVAL;
1564 }
1565 } else {
1566 switch (chan_comb) {
1567 case NM_CHANC_TCHFull:
1568 case NM_CHANC_TCHHalf:
1569 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1570 return 0;
1571 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001572 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301573 return -EINVAL;
1574 }
1575 }
1576 break;
1577 case 1:
1578 if (ts->trx->nr == 0) {
1579 switch (chan_comb) {
1580 case NM_CHANC_SDCCH_CBCH:
1581 if (ts->trx->ts[0].nm_chan_comb ==
1582 NM_CHANC_mainBCCH)
1583 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001584 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301585 return -EINVAL;
1586 case NM_CHANC_SDCCH:
1587 case NM_CHANC_TCHFull:
1588 case NM_CHANC_TCHHalf:
1589 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1590 case NM_CHANC_IPAC_TCHFull_PDCH:
1591 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001592 default:
1593 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1594 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301595 }
1596 } else {
1597 switch (chan_comb) {
1598 case NM_CHANC_SDCCH:
1599 case NM_CHANC_TCHFull:
1600 case NM_CHANC_TCHHalf:
1601 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1602 return 0;
1603 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001604 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301605 return -EINVAL;
1606 }
1607 }
1608 break;
1609 case 2:
1610 case 3:
1611 case 4:
1612 case 5:
1613 case 6:
1614 case 7:
1615 switch (chan_comb) {
1616 case NM_CHANC_TCHFull:
1617 case NM_CHANC_TCHHalf:
1618 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1619 return 0;
1620 case NM_CHANC_IPAC_PDCH:
1621 case NM_CHANC_IPAC_TCHFull_PDCH:
1622 if (ts->trx->nr == 0)
1623 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001624 else {
1625 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301626 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001627 }
Harald Welted6575f92009-12-02 02:45:23 +05301628 }
1629 break;
1630 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001631 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301632 return -EINVAL;
Harald Weltef383aa12012-07-02 19:51:55 +02001633 case GSM_BTS_TYPE_OSMO_SYSMO:
1634 /* no known restrictions */
1635 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301636 default:
1637 /* unknown BTS type */
1638 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001639 }
1640 return 0;
1641}
1642
Harald Welte22af0db2009-02-14 15:41:08 +00001643/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001644int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001645{
1646 struct gsm_bts *bts = ts->trx->bts;
1647 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001648 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001649 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001650 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001651 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001652
1653 if (bts->type == GSM_BTS_TYPE_BS11)
1654 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001655
Harald Weltef325eb42009-02-19 17:07:39 +00001656 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001657 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001658 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001659 LOGP(DNM, LOGL_ERROR,
1660 "Invalid Channel Combination %d on %s. Reason: %s\n",
1661 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001662 return -EINVAL;
1663 }
1664 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001665
Harald Welte52b1f982008-12-23 20:25:15 +00001666 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001667 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001668 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001669 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001670 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001671 if (ts->hopping.enabled) {
1672 unsigned int i;
1673 uint8_t *len;
1674
Harald Welte6e0cd042009-09-12 13:05:33 +02001675 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1676 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001677
1678 /* build the ARFCN list */
1679 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1680 len = msgb_put(msg, 1);
1681 *len = 0;
1682 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1683 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1684 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001685 /* At least BS-11 wants a TLV16 here */
1686 if (bts->type == GSM_BTS_TYPE_BS11)
1687 *len += 1;
1688 else
1689 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001690 }
1691 }
Harald Weltee0590df2009-02-15 03:34:15 +00001692 }
Harald Welte1fe24122014-01-19 17:18:21 +01001693 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001694 if (bts->type == GSM_BTS_TYPE_BS11)
1695 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001696
1697 return abis_nm_sendmsg(bts, msg);
1698}
1699
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001700int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1701 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001702{
1703 struct abis_om_hdr *oh;
1704 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001705 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1706 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001707
1708 if (nack) {
1709 len += 2;
1710 msgtype = NM_MT_SW_ACT_REQ_NACK;
1711 }
Harald Welte34a99682009-02-13 02:41:40 +00001712
1713 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001714 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1715
Harald Welte34a99682009-02-13 02:41:40 +00001716 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001717 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001718 memcpy(ptr, attr, att_len);
1719 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001720 if (nack)
1721 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001722
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001723 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001724}
1725
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001726int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001727{
Harald Welte8470bf22008-12-25 23:28:35 +00001728 struct msgb *msg = nm_msgb_alloc();
1729 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001730 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001731
1732 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1733 fill_om_hdr(oh, len);
1734 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001735 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001736
1737 return abis_nm_sendmsg(bts, msg);
1738}
1739
1740/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001741static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001742{
1743 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001744 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001745
1746 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001747 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001748 0xff, 0xff, 0xff);
1749
1750 return abis_nm_sendmsg(bts, msg);
1751}
1752
Harald Welte34a99682009-02-13 02:41:40 +00001753/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001754int 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 +00001755{
1756 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001757 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001758 struct msgb *msg = nm_msgb_alloc();
1759
1760 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001761 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001762
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001763 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001764 DEBUGPC(DNM, "Sending OPSTART\n");
1765
Harald Welte34a99682009-02-13 02:41:40 +00001766 return abis_nm_sendmsg(bts, msg);
1767}
1768
1769/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001770int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1771 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001772{
1773 struct abis_om_hdr *oh;
1774 struct msgb *msg = nm_msgb_alloc();
1775
1776 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1777 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1778 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1779
1780 return abis_nm_sendmsg(bts, msg);
1781}
1782
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001783int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1784 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001785{
1786 struct abis_om_hdr *oh;
1787 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001788 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001789
1790 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1791 e1_port0, ts0, e1_port1, ts1);
1792
1793 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1794 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1795 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1796
1797 attr = msgb_put(msg, 3);
1798 attr[0] = NM_ATT_MDROP_LINK;
1799 attr[1] = e1_port0;
1800 attr[2] = ts0;
1801
1802 attr = msgb_put(msg, 3);
1803 attr[0] = NM_ATT_MDROP_NEXT;
1804 attr[1] = e1_port1;
1805 attr[2] = ts1;
1806
1807 return abis_nm_sendmsg(bts, msg);
1808}
Harald Welte34a99682009-02-13 02:41:40 +00001809
Harald Weltec7310382009-08-08 00:02:36 +02001810/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001811int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1812 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1813 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001814{
1815 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001816
Harald Welte15c61722011-05-22 22:45:37 +02001817 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001818
1819 if (!msg)
1820 msg = nm_msgb_alloc();
1821
1822 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1823 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1824 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1825 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001826 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001827
1828 return abis_nm_sendmsg(bts, msg);
1829}
1830
Harald Welte52b1f982008-12-23 20:25:15 +00001831int abis_nm_event_reports(struct gsm_bts *bts, int on)
1832{
1833 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001834 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001835 else
Harald Welte227d4072009-01-03 08:16:25 +00001836 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001837}
1838
Harald Welte47d88ae2009-01-04 12:02:08 +00001839/* Siemens (or BS-11) specific commands */
1840
Harald Welte3ffd1372009-02-01 22:15:49 +00001841int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1842{
1843 if (reconnect == 0)
1844 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1845 else
1846 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1847}
1848
Harald Welteb8427972009-02-05 19:27:17 +00001849int abis_nm_bs11_restart(struct gsm_bts *bts)
1850{
1851 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1852}
1853
1854
Harald Welte268bb402009-02-01 19:11:56 +00001855struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001856 uint16_t year;
1857 uint8_t month;
1858 uint8_t day;
1859 uint8_t hour;
1860 uint8_t min;
1861 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001862} __attribute__((packed));
1863
1864
1865void get_bs11_date_time(struct bs11_date_time *aet)
1866{
1867 time_t t;
1868 struct tm *tm;
1869
1870 t = time(NULL);
1871 tm = localtime(&t);
1872 aet->sec = tm->tm_sec;
1873 aet->min = tm->tm_min;
1874 aet->hour = tm->tm_hour;
1875 aet->day = tm->tm_mday;
1876 aet->month = tm->tm_mon;
1877 aet->year = htons(1900 + tm->tm_year);
1878}
1879
Harald Welte05188ee2009-01-18 11:39:08 +00001880int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001881{
Harald Welte4668fda2009-01-03 08:19:29 +00001882 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001883}
1884
Harald Welte05188ee2009-01-18 11:39:08 +00001885int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001886{
1887 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001888 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001889 else
Harald Welte4668fda2009-01-03 08:19:29 +00001890 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001891}
Harald Welte47d88ae2009-01-04 12:02:08 +00001892
Harald Welte05188ee2009-01-18 11:39:08 +00001893int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001894 enum abis_bs11_objtype type, uint8_t idx,
1895 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001896{
1897 struct abis_om_hdr *oh;
1898 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001899 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001900
1901 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001902 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001903 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001904 cur = msgb_put(msg, attr_len);
1905 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001906
1907 return abis_nm_sendmsg(bts, msg);
1908}
1909
Harald Welte78fc0d42009-02-19 02:50:57 +00001910int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001911 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001912{
1913 struct abis_om_hdr *oh;
1914 struct msgb *msg = nm_msgb_alloc();
1915
1916 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1917 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1918 NM_OC_BS11, type, 0, idx);
1919
1920 return abis_nm_sendmsg(bts, msg);
1921}
1922
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001923int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001924{
1925 struct abis_om_hdr *oh;
1926 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001927 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001928
1929 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001930 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001931 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1932 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001933
1934 return abis_nm_sendmsg(bts, msg);
1935}
1936
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001937int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001938{
1939 struct abis_om_hdr *oh;
1940 struct msgb *msg = nm_msgb_alloc();
1941
1942 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1943 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001944 idx, 0xff, 0xff);
1945
1946 return abis_nm_sendmsg(bts, msg);
1947}
1948
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001949int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001950{
1951 struct abis_om_hdr *oh;
1952 struct msgb *msg = nm_msgb_alloc();
1953
1954 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1955 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1956 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001957
1958 return abis_nm_sendmsg(bts, msg);
1959}
Harald Welte05188ee2009-01-18 11:39:08 +00001960
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001961static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001962int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1963{
1964 struct abis_om_hdr *oh;
1965 struct msgb *msg = nm_msgb_alloc();
1966
1967 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1968 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1969 0xff, 0xff, 0xff);
1970 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1971
1972 return abis_nm_sendmsg(bts, msg);
1973}
1974
Harald Welteb6c92ae2009-02-21 20:15:32 +00001975/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001976int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1977 uint8_t e1_timeslot, uint8_t e1_subslot,
1978 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001979{
1980 struct abis_om_hdr *oh;
1981 struct abis_nm_channel *ch;
1982 struct msgb *msg = nm_msgb_alloc();
1983
1984 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001985 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001986 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1987
1988 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1989 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001990 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001991
1992 return abis_nm_sendmsg(bts, msg);
1993}
1994
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001995int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001996{
1997 struct abis_om_hdr *oh;
1998 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001999
2000 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002001 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002002 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2003 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2004
2005 return abis_nm_sendmsg(trx->bts, msg);
2006}
2007
Harald Welte78fc0d42009-02-19 02:50:57 +00002008int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2009{
2010 struct abis_om_hdr *oh;
2011 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002012 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002013
2014 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2015 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2016 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2017 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2018
2019 return abis_nm_sendmsg(trx->bts, msg);
2020}
2021
Harald Welteaaf02d92009-04-29 13:25:57 +00002022int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2023{
2024 struct abis_om_hdr *oh;
2025 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002026 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002027
2028 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2029 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2030 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002031 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002032
2033 return abis_nm_sendmsg(bts, msg);
2034}
2035
Harald Welteef061952009-05-17 12:43:42 +00002036int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2037{
2038 struct abis_om_hdr *oh;
2039 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002040 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002041 NM_ATT_BS11_CCLK_TYPE };
2042
2043 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2044 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2045 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2046 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2047
2048 return abis_nm_sendmsg(bts, msg);
2049
2050}
Harald Welteaaf02d92009-04-29 13:25:57 +00002051
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002052//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002053
Harald Welte1bc09062009-01-18 14:17:52 +00002054int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002055{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002056 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2057}
2058
Daniel Willmann4b054c82010-01-07 00:46:26 +01002059int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2060{
2061 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2062}
2063
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002064int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002065{
Harald Welte05188ee2009-01-18 11:39:08 +00002066 struct abis_om_hdr *oh;
2067 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002068 struct bs11_date_time bdt;
2069
2070 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002071
2072 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002073 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002074 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002075 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002076 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002077 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002078 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002079 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002080 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002081 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002082 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002083 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002084 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002085 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002086 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002087 }
Harald Welte05188ee2009-01-18 11:39:08 +00002088
2089 return abis_nm_sendmsg(bts, msg);
2090}
Harald Welte1bc09062009-01-18 14:17:52 +00002091
2092int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2093{
2094 struct abis_om_hdr *oh;
2095 struct msgb *msg;
2096
2097 if (strlen(password) != 10)
2098 return -EINVAL;
2099
2100 msg = nm_msgb_alloc();
2101 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002102 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002103 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002104 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002105
2106 return abis_nm_sendmsg(bts, msg);
2107}
2108
Harald Weltee69f5fb2009-04-28 16:31:38 +00002109/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2110int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2111{
2112 struct abis_om_hdr *oh;
2113 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002114 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002115
2116 msg = nm_msgb_alloc();
2117 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2118 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2119 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002120
2121 if (locked)
2122 tlv_value = BS11_LI_PLL_LOCKED;
2123 else
2124 tlv_value = BS11_LI_PLL_STANDALONE;
2125
2126 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002127
2128 return abis_nm_sendmsg(bts, msg);
2129}
2130
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002131/* Set the calibration value of the PLL (work value/set value)
2132 * It depends on the login which one is changed */
2133int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2134{
2135 struct abis_om_hdr *oh;
2136 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002137 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002138
2139 msg = nm_msgb_alloc();
2140 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2141 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2142 BS11_OBJ_TRX1, 0x00, 0x00);
2143
2144 tlv_value[0] = value>>8;
2145 tlv_value[1] = value&0xff;
2146
2147 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2148
2149 return abis_nm_sendmsg(bts, msg);
2150}
2151
Harald Welte1bc09062009-01-18 14:17:52 +00002152int abis_nm_bs11_get_state(struct gsm_bts *bts)
2153{
2154 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2155}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002156
2157/* BS11 SWL */
2158
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002159void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002160
Harald Welte5e4d1b32009-02-01 13:36:56 +00002161struct abis_nm_bs11_sw {
2162 struct gsm_bts *bts;
2163 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002164 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002165 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002166 struct llist_head file_list;
2167 gsm_cbfn *user_cb; /* specified by the user */
2168};
2169static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2170
2171struct file_list_entry {
2172 struct llist_head list;
2173 char fname[PATH_MAX];
2174};
2175
2176struct file_list_entry *fl_dequeue(struct llist_head *queue)
2177{
2178 struct llist_head *lh;
2179
2180 if (llist_empty(queue))
2181 return NULL;
2182
2183 lh = queue->next;
2184 llist_del(lh);
2185
2186 return llist_entry(lh, struct file_list_entry, list);
2187}
2188
2189static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2190{
2191 char linebuf[255];
2192 struct llist_head *lh, *lh2;
2193 FILE *swl;
2194 int rc = 0;
2195
2196 swl = fopen(bs11_sw->swl_fname, "r");
2197 if (!swl)
2198 return -ENODEV;
2199
2200 /* zero the stale file list, if any */
2201 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2202 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002203 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002204 }
2205
2206 while (fgets(linebuf, sizeof(linebuf), swl)) {
2207 char file_id[12+1];
2208 char file_version[80+1];
2209 struct file_list_entry *fle;
2210 static char dir[PATH_MAX];
2211
2212 if (strlen(linebuf) < 4)
2213 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002214
Harald Welte5e4d1b32009-02-01 13:36:56 +00002215 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2216 if (rc < 0) {
2217 perror("ERR parsing SWL file");
2218 rc = -EINVAL;
2219 goto out;
2220 }
2221 if (rc < 2)
2222 continue;
2223
Harald Welte470ec292009-06-26 20:25:23 +02002224 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002225 if (!fle) {
2226 rc = -ENOMEM;
2227 goto out;
2228 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002229
2230 /* construct new filename */
2231 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2232 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2233 strcat(fle->fname, "/");
2234 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002235
2236 llist_add_tail(&fle->list, &bs11_sw->file_list);
2237 }
2238
2239out:
2240 fclose(swl);
2241 return rc;
2242}
2243
2244/* bs11 swload specific callback, passed to abis_nm core swload */
2245static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2246 struct msgb *msg, void *data, void *param)
2247{
2248 struct abis_nm_bs11_sw *bs11_sw = data;
2249 struct file_list_entry *fle;
2250 int rc = 0;
2251
Harald Welte5e4d1b32009-02-01 13:36:56 +00002252 switch (event) {
2253 case NM_MT_LOAD_END_ACK:
2254 fle = fl_dequeue(&bs11_sw->file_list);
2255 if (fle) {
2256 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002257 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002258 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002259 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002260 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002261 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002262 } else {
2263 /* activate the SWL */
2264 rc = abis_nm_software_activate(bs11_sw->bts,
2265 bs11_sw->swl_fname,
2266 bs11_swload_cbfn,
2267 bs11_sw);
2268 }
2269 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002270 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002271 case NM_MT_LOAD_END_NACK:
2272 case NM_MT_LOAD_INIT_ACK:
2273 case NM_MT_LOAD_INIT_NACK:
2274 case NM_MT_ACTIVATE_SW_NACK:
2275 case NM_MT_ACTIVATE_SW_ACK:
2276 default:
2277 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002278 if (bs11_sw->user_cb)
2279 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002280 break;
2281 }
2282
2283 return rc;
2284}
2285
2286/* Siemens provides a SWL file that is a mere listing of all the other
2287 * files that are part of a software release. We need to upload first
2288 * the list file, and then each file that is listed in the list file */
2289int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002290 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002291{
2292 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2293 struct file_list_entry *fle;
2294 int rc = 0;
2295
2296 INIT_LLIST_HEAD(&bs11_sw->file_list);
2297 bs11_sw->bts = bts;
2298 bs11_sw->win_size = win_size;
2299 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002300 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002301
2302 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2303 rc = bs11_read_swl_file(bs11_sw);
2304 if (rc < 0)
2305 return rc;
2306
2307 /* dequeue next item in file list */
2308 fle = fl_dequeue(&bs11_sw->file_list);
2309 if (!fle)
2310 return -EINVAL;
2311
2312 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002313 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002314 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002315 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002316 return rc;
2317}
2318
Harald Welte5083b0b2009-02-02 19:20:52 +00002319#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002320static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002321 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2322 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2323 NM_ATT_BS11_LMT_USER_NAME,
2324
2325 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2326
2327 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2328
2329 NM_ATT_BS11_SW_LOAD_STORED };
2330
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002331static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002332 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2333 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2334 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2335 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002336#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002337
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002338static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002339 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2340 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002341 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002342
2343int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2344{
2345 struct abis_om_hdr *oh;
2346 struct msgb *msg = nm_msgb_alloc();
2347
2348 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2349 /* SiemensHW CCTRL object */
2350 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2351 0x03, 0x00, 0x00);
2352 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2353
2354 return abis_nm_sendmsg(bts, msg);
2355}
Harald Welte268bb402009-02-01 19:11:56 +00002356
2357int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2358{
2359 struct abis_om_hdr *oh;
2360 struct msgb *msg = nm_msgb_alloc();
2361 struct bs11_date_time aet;
2362
2363 get_bs11_date_time(&aet);
2364 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2365 /* SiemensHW CCTRL object */
2366 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2367 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002368 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002369
2370 return abis_nm_sendmsg(bts, msg);
2371}
Harald Welte5c1e4582009-02-15 11:57:29 +00002372
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002373int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002374{
2375 struct abis_om_hdr *oh;
2376 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002377 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002378
2379 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2380 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2381 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2382 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2383
2384 return abis_nm_sendmsg(bts, msg);
2385}
2386
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002387int 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 +02002388{
2389 struct abis_om_hdr *oh;
2390 struct msgb *msg = nm_msgb_alloc();
2391 struct bs11_date_time aet;
2392
2393 get_bs11_date_time(&aet);
2394 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2395 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2396 bport, 0xff, 0x02);
2397 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2398
2399 return abis_nm_sendmsg(bts, msg);
2400}
2401
Harald Welte5c1e4582009-02-15 11:57:29 +00002402/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002403static const char ipaccess_magic[] = "com.ipaccess";
2404
Harald Welte677c21f2009-02-17 13:22:23 +00002405
2406static int abis_nm_rx_ipacc(struct msgb *msg)
2407{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002408 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002409 struct abis_om_hdr *oh = msgb_l2(msg);
2410 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002411 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002412 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002413 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002414 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002415
2416 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002417 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002418 return -EINVAL;
2419 }
2420
Harald Welte193fefc2009-04-30 15:16:27 +00002421 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002422 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002423
Harald Welte15c61722011-05-22 22:45:37 +02002424 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002425
Harald Welte746d6092009-10-19 22:11:11 +02002426 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002427
Harald Welte677c21f2009-02-17 13:22:23 +00002428 switch (foh->msg_type) {
2429 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002430 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002431 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2432 memcpy(&addr,
2433 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2434
2435 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2436 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002437 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002438 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002439 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002440 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002441 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2442 DEBUGPC(DNM, "STREAM=0x%02x ",
2443 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002444 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002445 break;
2446 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002447 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002448 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002449 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002450 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002451 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002452 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002453 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002454 case NM_MT_IPACC_SET_NVATTR_ACK:
2455 DEBUGPC(DNM, "SET NVATTR ACK\n");
2456 /* FIXME: decode and show the actual attributes */
2457 break;
2458 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002459 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002460 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002461 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002462 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002463 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002464 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002465 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002466 case NM_MT_IPACC_GET_NVATTR_ACK:
2467 DEBUGPC(DNM, "GET NVATTR ACK\n");
2468 /* FIXME: decode and show the actual attributes */
2469 break;
2470 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002471 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002472 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002473 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002474 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002475 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002476 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002477 break;
Harald Welte15c44172009-10-08 20:15:24 +02002478 case NM_MT_IPACC_SET_ATTR_ACK:
2479 DEBUGPC(DNM, "SET ATTR ACK\n");
2480 break;
2481 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002482 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002483 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002484 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002485 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002486 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002487 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002488 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002489 default:
2490 DEBUGPC(DNM, "unknown\n");
2491 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002492 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002493
2494 /* signal handling */
2495 switch (foh->msg_type) {
2496 case NM_MT_IPACC_RSL_CONNECT_NACK:
2497 case NM_MT_IPACC_SET_NVATTR_NACK:
2498 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002499 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 +01002500 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002501 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002502 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002503 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002504 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 +01002505 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002506 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002507 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002508 default:
2509 break;
2510 }
2511
Harald Welte677c21f2009-02-17 13:22:23 +00002512 return 0;
2513}
2514
Harald Welte193fefc2009-04-30 15:16:27 +00002515/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002516int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2517 uint8_t obj_class, uint8_t bts_nr,
2518 uint8_t trx_nr, uint8_t ts_nr,
2519 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002520{
2521 struct msgb *msg = nm_msgb_alloc();
2522 struct abis_om_hdr *oh;
2523 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002524 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002525
2526 /* construct the 12.21 OM header, observe the erroneous length */
2527 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2528 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2529 oh->mdisc = ABIS_OM_MDISC_MANUF;
2530
2531 /* add the ip.access magic */
2532 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2533 *data++ = sizeof(ipaccess_magic);
2534 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2535
2536 /* fill the 12.21 FOM header */
2537 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2538 foh->msg_type = msg_type;
2539 foh->obj_class = obj_class;
2540 foh->obj_inst.bts_nr = bts_nr;
2541 foh->obj_inst.trx_nr = trx_nr;
2542 foh->obj_inst.ts_nr = ts_nr;
2543
2544 if (attr && attr_len) {
2545 data = msgb_put(msg, attr_len);
2546 memcpy(data, attr, attr_len);
2547 }
2548
2549 return abis_nm_sendmsg(bts, msg);
2550}
Harald Welte677c21f2009-02-17 13:22:23 +00002551
Harald Welte193fefc2009-04-30 15:16:27 +00002552/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002553int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002554 int attr_len)
2555{
Harald Welte2ef156d2010-01-07 20:39:42 +01002556 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2557 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002558 attr_len);
2559}
2560
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002561int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002562 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002563{
2564 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002565 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002566 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2567 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2568
2569 int attr_len = sizeof(attr);
2570
2571 ia.s_addr = htonl(ip);
2572 attr[1] = stream;
2573 attr[3] = port >> 8;
2574 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002575 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002576
2577 /* if ip == 0, we use the default IP */
2578 if (ip == 0)
2579 attr_len -= 5;
2580
2581 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002582 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002583
2584 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2585 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2586 trx->nr, 0xff, attr, attr_len);
2587}
2588
Harald Welte193fefc2009-04-30 15:16:27 +00002589/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002590int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002591{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002592 struct abis_om_hdr *oh;
2593 struct msgb *msg = nm_msgb_alloc();
2594
2595 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2596 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2597 trx->bts->nr, trx->nr, 0xff);
2598
2599 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002600}
Harald Weltedaef5212009-10-24 10:20:41 +02002601
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002602int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2603 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2604 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002605{
2606 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2607 obj_class, bts_nr, trx_nr, ts_nr,
2608 attr, attr_len);
2609}
Harald Welte0f255852009-11-12 14:48:42 +01002610
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002611void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002612{
2613 /* we simply reuse the GSM48 function and overwrite the RAC
2614 * with the Cell ID */
2615 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002616 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002617}
2618
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002619void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2620{
2621 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2622
Harald Welted64c0bc2011-05-30 12:07:53 +02002623 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002624 if (!trx->bts || !trx->bts->oml_link)
2625 return;
2626
2627 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2628 trx->bts->bts_nr, trx->nr, 0xff,
2629 new_state);
2630}
2631
Harald Welte92b1fe42010-03-25 11:45:30 +08002632static const struct value_string ipacc_testres_names[] = {
2633 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2634 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2635 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2636 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2637 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2638 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002639};
2640
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002641const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002642{
Harald Welte92b1fe42010-03-25 11:45:30 +08002643 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002644}
2645
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002646void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002647{
2648 cid->mcc = (buf[0] & 0xf) * 100;
2649 cid->mcc += (buf[0] >> 4) * 10;
2650 cid->mcc += (buf[1] & 0xf) * 1;
2651
2652 if (buf[1] >> 4 == 0xf) {
2653 cid->mnc = (buf[2] & 0xf) * 10;
2654 cid->mnc += (buf[2] >> 4) * 1;
2655 } else {
2656 cid->mnc = (buf[2] & 0xf) * 100;
2657 cid->mnc += (buf[2] >> 4) * 10;
2658 cid->mnc += (buf[1] >> 4) * 1;
2659 }
2660
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002661 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2662 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002663}
2664
Harald Welte0f255852009-11-12 14:48:42 +01002665/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002666int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002667{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002668 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002669 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002670
Harald Welteaf109b92010-07-22 18:14:36 +02002671 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002672
2673 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2674 return -EINVAL;
2675 cur++;
2676
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002677 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002678 cur += 2;
2679
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002680 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002681 cur += 2;
2682
2683 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2684 binf->freq_qual = *cur >> 2;
2685
Harald Welteaf109b92010-07-22 18:14:36 +02002686 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002687 binf->arfcn |= *cur++;
2688
2689 if (binf->info_type & IPAC_BINF_RXLEV)
2690 binf->rx_lev = *cur & 0x3f;
2691 cur++;
2692
2693 if (binf->info_type & IPAC_BINF_RXQUAL)
2694 binf->rx_qual = *cur & 0x7;
2695 cur++;
2696
2697 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002698 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002699 cur += 2;
2700
2701 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002702 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002703 cur += 2;
2704
2705 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002706 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002707 cur += 4;
2708
Harald Weltea780a3d2010-07-30 22:34:42 +02002709#if 0
2710 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002711 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002712#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002713 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002714 cur++;
2715
Harald Welteb40a38f2009-11-13 11:56:05 +01002716 ipac_parse_cgi(&binf->cgi, cur);
2717 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002718
2719 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2720 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2721 cur += sizeof(binf->ba_list_si2);
2722 }
2723
2724 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2725 memcpy(binf->ba_list_si2bis, cur,
2726 sizeof(binf->ba_list_si2bis));
2727 cur += sizeof(binf->ba_list_si2bis);
2728 }
2729
2730 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2731 memcpy(binf->ba_list_si2ter, cur,
2732 sizeof(binf->ba_list_si2ter));
2733 cur += sizeof(binf->ba_list_si2ter);
2734 }
2735
2736 return 0;
2737}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002738
2739void abis_nm_clear_queue(struct gsm_bts *bts)
2740{
2741 struct msgb *msg;
2742
2743 while (!llist_empty(&bts->abis_queue)) {
2744 msg = msgb_dequeue(&bts->abis_queue);
2745 msgb_free(msg);
2746 }
2747
2748 bts->abis_nm_pend = 0;
2749}