blob: 494d4cabafeb1f0023f78af34d8bca8ea974c9ea [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>
Harald Welte52b1f982008-12-23 20:25:15 +000046
Harald Welte8470bf22008-12-25 23:28:35 +000047#define OM_ALLOC_SIZE 1024
48#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010049#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000050
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020051int 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 +000052{
Harald Welte39315c42010-01-10 18:01:52 +010053 if (!bts->model)
54 return -EIO;
55 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000056}
Harald Weltee0590df2009-02-15 03:34:15 +000057
Harald Welte52b1f982008-12-23 20:25:15 +000058static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
59{
60 int i;
61
62 for (i = 0; i < size; i++) {
63 if (arr[i] == mt)
64 return 1;
65 }
66
67 return 0;
68}
69
Holger Freytherca362a62009-01-04 21:05:01 +000070#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000071/* is this msgtype the usual ACK/NACK type ? */
72static int is_ack_nack(enum abis_nm_msgtype mt)
73{
74 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
75}
Holger Freytherca362a62009-01-04 21:05:01 +000076#endif
Harald Welte52b1f982008-12-23 20:25:15 +000077
78/* is this msgtype a report ? */
79static int is_report(enum abis_nm_msgtype mt)
80{
Harald Welte15c61722011-05-22 22:45:37 +020081 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000082}
83
84#define MT_ACK(x) (x+1)
85#define MT_NACK(x) (x+2)
86
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020087static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000088{
89 oh->mdisc = ABIS_OM_MDISC_FOM;
90 oh->placement = ABIS_OM_PLACEMENT_ONLY;
91 oh->sequence = 0;
92 oh->length = len;
93}
94
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020095static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
96 uint8_t msg_type, uint8_t obj_class,
97 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +000098{
99 struct abis_om_fom_hdr *foh =
100 (struct abis_om_fom_hdr *) oh->data;
101
Harald Welte702d8702008-12-26 20:25:35 +0000102 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000103 foh->msg_type = msg_type;
104 foh->obj_class = obj_class;
105 foh->obj_inst.bts_nr = bts_nr;
106 foh->obj_inst.trx_nr = trx_nr;
107 foh->obj_inst.ts_nr = ts_nr;
108}
109
Harald Welte8470bf22008-12-25 23:28:35 +0000110static struct msgb *nm_msgb_alloc(void)
111{
Harald Welte966636f2009-06-26 19:39:35 +0200112 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
113 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000114}
115
Harald Welte52b1f982008-12-23 20:25:15 +0000116/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100117static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000118{
Holger Freyther59639e82009-02-09 23:09:55 +0000119 msg->trx = bts->c0;
120
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100121 /* queue OML messages */
122 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
123 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100124 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100125 } else {
126 msgb_enqueue(&bts->abis_queue, msg);
127 return 0;
128 }
129
130}
131
132int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
133{
134 OBSC_NM_W_ACK_CB(msg) = 1;
135 return abis_nm_queue_msg(bts, msg);
136}
137
138static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
139{
140 OBSC_NM_W_ACK_CB(msg) = 0;
141 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000142}
143
Harald Welte4724f992009-01-18 18:01:49 +0000144static int abis_nm_rcvmsg_sw(struct msgb *mb);
145
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100146int nm_is_running(struct gsm_nm_state *s) {
147 return (s->operational == NM_OPSTATE_ENABLED) && (
148 (s->availability == NM_AVSTATE_OK) ||
149 (s->availability == 0xff)
150 );
151}
152
Harald Weltee0590df2009-02-15 03:34:15 +0000153/* Update the administrative state of a given object in our in-memory data
154 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200155static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
156 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000157{
Harald Welteaeedeb42009-05-01 13:08:14 +0000158 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100159 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000160
Harald Welteaf9b8102011-03-06 21:20:38 +0100161 memset(&nsd, 0, sizeof(nsd));
162
Harald Welte978714d2011-06-06 18:31:20 +0200163 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100164 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100165 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200166 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000167 if (!nm_state)
168 return -1;
169
170 new_state = *nm_state;
171 new_state.administrative = adm_state;
172
Harald Weltef38ca9a2011-03-06 22:11:32 +0100173 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100174 nsd.obj_class = obj_class;
175 nsd.old_state = nm_state;
176 nsd.new_state = &new_state;
177 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200178 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000179
180 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000181
Harald Weltef338a032011-01-14 15:55:42 +0100182 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000183}
184
Harald Welte97ed1e72009-02-06 13:38:02 +0000185static int abis_nm_rx_statechg_rep(struct msgb *mb)
186{
Harald Weltee0590df2009-02-15 03:34:15 +0000187 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000188 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000189 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000190 struct tlv_parsed tp;
191 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000192
Harald Welte23897662009-05-01 14:52:51 +0000193 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000194
Harald Welte8b697c72009-06-05 19:18:45 +0000195 memset(&new_state, 0, sizeof(new_state));
196
Harald Welte978714d2011-06-06 18:31:20 +0200197 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000198 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100199 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000200 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000201 }
Harald Weltee0590df2009-02-15 03:34:15 +0000202
203 new_state = *nm_state;
204
Harald Welte39315c42010-01-10 18:01:52 +0100205 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000206 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
207 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200208 DEBUGPC(DNM, "OP_STATE=%s ",
209 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000210 }
211 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000212 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
213 new_state.availability = 0xff;
214 else
215 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200216 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
217 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000218 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100219 } else
220 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000221 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
222 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200223 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200224 get_value_string(abis_nm_adm_state_names,
225 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000226 }
227 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000228
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100229 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
230 new_state.operational != nm_state->operational ||
231 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000232 /* Update the operational state of a given object in our in-memory data
233 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100234 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200235 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100236 nsd.obj_class = foh->obj_class;
237 nsd.old_state = nm_state;
238 nsd.new_state = &new_state;
239 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100240 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200241 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100242 nm_state->operational = new_state.operational;
243 nm_state->availability = new_state.availability;
244 if (nm_state->administrative == 0)
245 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000246 }
247#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000248 if (op_state == 1) {
249 /* try to enable objects that are disabled */
250 abis_nm_opstart(bts, foh->obj_class,
251 foh->obj_inst.bts_nr,
252 foh->obj_inst.trx_nr,
253 foh->obj_inst.ts_nr);
254 }
Harald Weltee0590df2009-02-15 03:34:15 +0000255#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000256 return 0;
257}
258
Harald Welte0db97b22009-05-01 17:22:47 +0000259static int rx_fail_evt_rep(struct msgb *mb)
260{
261 struct abis_om_hdr *oh = msgb_l2(mb);
262 struct abis_om_fom_hdr *foh = msgb_l3(mb);
263 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100264 const uint8_t *p_val;
265 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000266
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200267 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000268
Harald Welte39315c42010-01-10 18:01:52 +0100269 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000270
271 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200272 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
273 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000274 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200275 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
276 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100277 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
278 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200279 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 +0100280 }
281 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
282 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
283 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
284 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200285 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100286 talloc_free(p_text);
287 }
288 }
Harald Welte0db97b22009-05-01 17:22:47 +0000289
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200290 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000291
292 return 0;
293}
294
Harald Welte97ed1e72009-02-06 13:38:02 +0000295static int abis_nm_rcvmsg_report(struct msgb *mb)
296{
297 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200298 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000299
Harald Welte15c61722011-05-22 22:45:37 +0200300 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000301
Harald Welte97ed1e72009-02-06 13:38:02 +0000302 //nmh->cfg->report_cb(mb, foh);
303
304 switch (mt) {
305 case NM_MT_STATECHG_EVENT_REP:
306 return abis_nm_rx_statechg_rep(mb);
307 break;
Harald Welte34a99682009-02-13 02:41:40 +0000308 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000309 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200310 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000311 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000312 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000313 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200314 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000315 break;
Harald Weltec7310382009-08-08 00:02:36 +0200316 case NM_MT_TEST_REP:
317 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200318 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200319 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000320 default:
Harald Welte23897662009-05-01 14:52:51 +0000321 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000322 break;
323
Harald Welte97ed1e72009-02-06 13:38:02 +0000324 };
325
Harald Welte97ed1e72009-02-06 13:38:02 +0000326 return 0;
327}
328
Harald Welte34a99682009-02-13 02:41:40 +0000329/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200330static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
331 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000332{
333 struct abis_om_hdr *oh;
334 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200335 uint8_t len = swdesc_len;
336 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000337
338 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
339 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
340
341 trailer = msgb_put(msg, swdesc_len);
342 memcpy(trailer, sw_desc, swdesc_len);
343
344 return abis_nm_sendmsg(bts, msg);
345}
346
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200347static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100348{
349 static const struct tlv_definition sw_descr_def = {
350 .def = {
351 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
352 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
353 },
354 };
355
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200356 uint8_t tag;
357 uint16_t tag_len;
358 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100359 int ofs = 0, len;
360
361 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
362 * nested nature and the fact you have to assume it contains only two sub
363 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
364
365 if (sw_descr[0] != NM_ATT_SW_DESCR) {
366 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
367 return -1;
368 }
369 ofs += 1;
370
371 len = tlv_parse_one(&tag, &tag_len, &val,
372 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
373 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
374 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
375 return -2;
376 }
377 ofs += len;
378
379 len = tlv_parse_one(&tag, &tag_len, &val,
380 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
381 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
382 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
383 return -3;
384 }
385 ofs += len;
386
387 return ofs;
388}
389
Harald Welte34a99682009-02-13 02:41:40 +0000390static int abis_nm_rx_sw_act_req(struct msgb *mb)
391{
392 struct abis_om_hdr *oh = msgb_l2(mb);
393 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200394 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200395 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100396 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000397
Harald Welte15c61722011-05-22 22:45:37 +0200398 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200399
400 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000401
Harald Welte97a282b2010-03-14 15:37:43 +0800402 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000403
404 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000405 foh->obj_inst.bts_nr,
406 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800407 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000408 foh->data, oh->length-sizeof(*foh));
409
Harald Welte39315c42010-01-10 18:01:52 +0100410 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200411 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
412 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
413 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
414 DEBUGP(DNM, "SW config not found! Can't continue.\n");
415 return -EINVAL;
416 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200417 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200418 }
419
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100420 /* Use the first SW_DESCR present in SW config */
421 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
422 if (sw_descr_len < 0)
423 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200424
Harald Welte34a99682009-02-13 02:41:40 +0000425 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
426 foh->obj_inst.bts_nr,
427 foh->obj_inst.trx_nr,
428 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100429 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000430}
431
Harald Weltee0590df2009-02-15 03:34:15 +0000432/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
433static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
434{
435 struct abis_om_hdr *oh = msgb_l2(mb);
436 struct abis_om_fom_hdr *foh = msgb_l3(mb);
437 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200438 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000439
Harald Welte39315c42010-01-10 18:01:52 +0100440 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000441 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
442 return -EINVAL;
443
444 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
445
446 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
447}
448
Harald Welteee670472009-02-22 21:58:49 +0000449static int abis_nm_rx_lmt_event(struct msgb *mb)
450{
451 struct abis_om_hdr *oh = msgb_l2(mb);
452 struct abis_om_fom_hdr *foh = msgb_l3(mb);
453 struct tlv_parsed tp;
454
455 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100456 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000457 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
458 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200459 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000460 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
461 }
462 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
463 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200464 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000465 DEBUGPC(DNM, "Level=%u ", level);
466 }
467 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
468 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
469 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
470 DEBUGPC(DNM, "Username=%s ", name);
471 }
472 DEBUGPC(DNM, "\n");
473 /* FIXME: parse LMT LOGON TIME */
474 return 0;
475}
476
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100477static void abis_nm_queue_send_next(struct gsm_bts *bts)
478{
479 int wait = 0;
480 struct msgb *msg;
481 /* the queue is empty */
482 while (!llist_empty(&bts->abis_queue)) {
483 msg = msgb_dequeue(&bts->abis_queue);
484 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100485 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100486
487 if (wait)
488 break;
489 }
490
491 bts->abis_nm_pend = wait;
492}
493
Harald Welte52b1f982008-12-23 20:25:15 +0000494/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000495static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000496{
Harald Welte6c96ba52009-05-01 13:03:40 +0000497 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000498 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200499 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100500 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000501
502 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000503 if (is_report(mt))
504 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000505
Harald Welte15c61722011-05-22 22:45:37 +0200506 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000507 return abis_nm_rcvmsg_sw(mb);
508
Harald Welte15c61722011-05-22 22:45:37 +0200509 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800510 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000511 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200512
Harald Welte15c61722011-05-22 22:45:37 +0200513 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200514
Harald Welte15c61722011-05-22 22:45:37 +0200515 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000516
Harald Welte39315c42010-01-10 18:01:52 +0100517 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000518 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200519 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200520 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000521 else
522 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200523
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800524 nack_data.msg = mb;
525 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200526 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100527 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200528 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000529 }
Harald Weltead384642008-12-26 10:20:07 +0000530#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000531 /* check if last message is to be acked */
532 if (is_ack_nack(nmh->last_msgtype)) {
533 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100534 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000535 /* we got our ACK, continue sending the next msg */
536 } else if (mt == MT_NACK(nmh->last_msgtype)) {
537 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100538 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000539 /* FIXME: somehow signal this to the caller */
540 } else {
541 /* really strange things happen */
542 return -EINVAL;
543 }
544 }
Harald Weltead384642008-12-26 10:20:07 +0000545#endif
546
Harald Welte97ed1e72009-02-06 13:38:02 +0000547 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000548 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100549 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000550 break;
Harald Welte34a99682009-02-13 02:41:40 +0000551 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100552 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000553 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000554 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100555 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000556 break;
Harald Welte1989c082009-08-06 17:58:31 +0200557 case NM_MT_CONN_MDROP_LINK_ACK:
558 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
559 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100560 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200561 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100562 break;
563 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200564 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100565 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100566 case NM_MT_SET_BTS_ATTR_ACK:
567 /* The HSL wants an OPSTART _after_ the SI has been set */
568 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
569 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
570 }
571 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000572 }
573
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100574 abis_nm_queue_send_next(mb->trx->bts);
575 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000576}
577
Harald Welte677c21f2009-02-17 13:22:23 +0000578static int abis_nm_rx_ipacc(struct msgb *mb);
579
580static int abis_nm_rcvmsg_manuf(struct msgb *mb)
581{
582 int rc;
583 int bts_type = mb->trx->bts->type;
584
585 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100586 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000587 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100588 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000589 break;
590 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100591 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
592 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000593 rc = 0;
594 break;
595 }
596
597 return rc;
598}
599
Harald Welte52b1f982008-12-23 20:25:15 +0000600/* High-Level API */
601/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000602int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000603{
Harald Welte52b1f982008-12-23 20:25:15 +0000604 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000605 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000606
607 /* Various consistency checks */
608 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100609 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000610 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200611 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
612 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000613 }
614 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100615 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000616 oh->sequence);
617 return -EINVAL;
618 }
Harald Welte702d8702008-12-26 20:25:35 +0000619#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200620 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000621 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000622 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100623 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000624 oh->length + sizeof(*oh), l2_len);
625 return -EINVAL;
626 }
Harald Welte702d8702008-12-26 20:25:35 +0000627 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100628 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 +0000629#endif
Harald Weltead384642008-12-26 10:20:07 +0000630 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000631
632 switch (oh->mdisc) {
633 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000634 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000635 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000636 case ABIS_OM_MDISC_MANUF:
637 rc = abis_nm_rcvmsg_manuf(msg);
638 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000639 case ABIS_OM_MDISC_MMI:
640 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100641 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000642 oh->mdisc);
643 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000644 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100645 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000646 oh->mdisc);
647 return -EINVAL;
648 }
649
Harald Weltead384642008-12-26 10:20:07 +0000650 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000651 return rc;
652}
653
654#if 0
655/* initialized all resources */
656struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
657{
658 struct abis_nm_h *nmh;
659
660 nmh = malloc(sizeof(*nmh));
661 if (!nmh)
662 return NULL;
663
664 nmh->cfg = cfg;
665
666 return nmh;
667}
668
669/* free all resources */
670void abis_nm_fini(struct abis_nm_h *nmh)
671{
672 free(nmh);
673}
674#endif
675
676/* Here we are trying to define a high-level API that can be used by
677 * the actual BSC implementation. However, the architecture is currently
678 * still under design. Ideally the calls to this API would be synchronous,
679 * while the underlying stack behind the APi runs in a traditional select
680 * based state machine.
681 */
682
Harald Welte4724f992009-01-18 18:01:49 +0000683/* 6.2 Software Load: */
684enum sw_state {
685 SW_STATE_NONE,
686 SW_STATE_WAIT_INITACK,
687 SW_STATE_WAIT_SEGACK,
688 SW_STATE_WAIT_ENDACK,
689 SW_STATE_WAIT_ACTACK,
690 SW_STATE_ERROR,
691};
Harald Welte52b1f982008-12-23 20:25:15 +0000692
Harald Welte52b1f982008-12-23 20:25:15 +0000693struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000694 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800695 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000696 gsm_cbfn *cbfn;
697 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000698 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000699
Harald Welte52b1f982008-12-23 20:25:15 +0000700 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200701 uint8_t obj_class;
702 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000703
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200704 uint8_t file_id[255];
705 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000706
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200707 uint8_t file_version[255];
708 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000709
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200710 uint8_t window_size;
711 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000712
713 int fd;
714 FILE *stream;
715 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000716 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000717};
718
Harald Welte4724f992009-01-18 18:01:49 +0000719static struct abis_nm_sw g_sw;
720
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100721static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
722{
723 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
724 msgb_v_put(msg, NM_ATT_SW_DESCR);
725 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
726 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
727 sw->file_version);
728 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
729 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
730 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
731 sw->file_version);
732 } else {
733 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
734 }
735}
736
Harald Welte4724f992009-01-18 18:01:49 +0000737/* 6.2.1 / 8.3.1: Load Data Initiate */
738static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000739{
Harald Welte4724f992009-01-18 18:01:49 +0000740 struct abis_om_hdr *oh;
741 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200742 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000743
744 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
745 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
746 sw->obj_instance[0], sw->obj_instance[1],
747 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100748
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100749 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000750 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
751
752 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000753}
754
Harald Welte1602ade2009-01-29 21:12:39 +0000755static int is_last_line(FILE *stream)
756{
757 char next_seg_buf[256];
758 long pos;
759
760 /* check if we're sending the last line */
761 pos = ftell(stream);
762 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
763 fseek(stream, pos, SEEK_SET);
764 return 1;
765 }
766
767 fseek(stream, pos, SEEK_SET);
768 return 0;
769}
770
Harald Welte4724f992009-01-18 18:01:49 +0000771/* 6.2.2 / 8.3.2 Load Data Segment */
772static int sw_load_segment(struct abis_nm_sw *sw)
773{
774 struct abis_om_hdr *oh;
775 struct msgb *msg = nm_msgb_alloc();
776 char seg_buf[256];
777 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000778 unsigned char *tlv;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200779 uint8_t len;
Harald Welte4724f992009-01-18 18:01:49 +0000780
781 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000782
783 switch (sw->bts->type) {
784 case GSM_BTS_TYPE_BS11:
785 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
786 perror("fgets reading segment");
787 return -EINVAL;
788 }
789 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000790
791 /* check if we're sending the last line */
792 sw->last_seg = is_last_line(sw->stream);
793 if (sw->last_seg)
794 seg_buf[1] = 0;
795 else
796 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000797
798 len = strlen(line_buf) + 2;
799 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200800 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000801 /* BS11 wants CR + LF in excess of the TLV length !?! */
802 tlv[1] -= 2;
803
804 /* we only now know the exact length for the OM hdr */
805 len = strlen(line_buf)+2;
806 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100807 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200808 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100809 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
810 if (len < 0) {
811 perror("read failed");
812 return -EINVAL;
813 }
814
815 if (len != IPACC_SEGMENT_SIZE)
816 sw->last_seg = 1;
817
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100818 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200819 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100820 len += 3;
821 break;
822 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000823 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100824 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000825 /* FIXME: Other BTS types */
826 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000827 }
Harald Welte4724f992009-01-18 18:01:49 +0000828
Harald Welte4724f992009-01-18 18:01:49 +0000829 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
830 sw->obj_instance[0], sw->obj_instance[1],
831 sw->obj_instance[2]);
832
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100833 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000834}
835
836/* 6.2.4 / 8.3.4 Load Data End */
837static int sw_load_end(struct abis_nm_sw *sw)
838{
839 struct abis_om_hdr *oh;
840 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200841 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000842
843 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
844 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
845 sw->obj_instance[0], sw->obj_instance[1],
846 sw->obj_instance[2]);
847
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100848 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000849 return abis_nm_sendmsg(sw->bts, msg);
850}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000851
Harald Welte52b1f982008-12-23 20:25:15 +0000852/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000853static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000854{
Harald Welte4724f992009-01-18 18:01:49 +0000855 struct abis_om_hdr *oh;
856 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200857 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000858
Harald Welte4724f992009-01-18 18:01:49 +0000859 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
860 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
861 sw->obj_instance[0], sw->obj_instance[1],
862 sw->obj_instance[2]);
863
864 /* FIXME: this is BS11 specific format */
865 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
866 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
867 sw->file_version);
868
869 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000870}
Harald Welte4724f992009-01-18 18:01:49 +0000871
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100872struct sdp_firmware {
873 char magic[4];
874 char more_magic[4];
875 unsigned int header_length;
876 unsigned int file_length;
877} __attribute__ ((packed));
878
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100879static int parse_sdp_header(struct abis_nm_sw *sw)
880{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100881 struct sdp_firmware firmware_header;
882 int rc;
883 struct stat stat;
884
885 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
886 if (rc != sizeof(firmware_header)) {
887 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
888 return -1;
889 }
890
891 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
892 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
893 return -1;
894 }
895
896 if (firmware_header.more_magic[0] != 0x10 ||
897 firmware_header.more_magic[1] != 0x02 ||
898 firmware_header.more_magic[2] != 0x00 ||
899 firmware_header.more_magic[3] != 0x00) {
900 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
901 return -1;
902 }
903
904
905 if (fstat(sw->fd, &stat) == -1) {
906 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
907 return -1;
908 }
909
910 if (ntohl(firmware_header.file_length) != stat.st_size) {
911 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
912 return -1;
913 }
914
915 /* go back to the start as we checked the whole filesize.. */
916 lseek(sw->fd, 0l, SEEK_SET);
917 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
918 "There might be checksums in the file that are not\n"
919 "verified and incomplete firmware might be flashed.\n"
920 "There is absolutely no WARRANTY that flashing will\n"
921 "work.\n");
922 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100923}
924
Harald Welte4724f992009-01-18 18:01:49 +0000925static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
926{
927 char file_id[12+1];
928 char file_version[80+1];
929 int rc;
930
931 sw->fd = open(fname, O_RDONLY);
932 if (sw->fd < 0)
933 return sw->fd;
934
935 switch (sw->bts->type) {
936 case GSM_BTS_TYPE_BS11:
937 sw->stream = fdopen(sw->fd, "r");
938 if (!sw->stream) {
939 perror("fdopen");
940 return -1;
941 }
942 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200943 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +0000944 file_id, file_version);
945 if (rc != 2) {
946 perror("parsing header line of software file");
947 return -1;
948 }
949 strcpy((char *)sw->file_id, file_id);
950 sw->file_id_len = strlen(file_id);
951 strcpy((char *)sw->file_version, file_version);
952 sw->file_version_len = strlen(file_version);
953 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +0000954 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +0000955 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100956 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100957 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100958 rc = parse_sdp_header(sw);
959 if (rc < 0) {
960 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
961 return -1;
962 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100963
964 strcpy((char *)sw->file_id, "id");
965 sw->file_id_len = 3;
966 strcpy((char *)sw->file_version, "version");
967 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +0100968 break;
Harald Welte4724f992009-01-18 18:01:49 +0000969 default:
970 /* We don't know how to treat them yet */
971 close(sw->fd);
972 return -EINVAL;
973 }
974
975 return 0;
976}
977
978static void sw_close_file(struct abis_nm_sw *sw)
979{
980 switch (sw->bts->type) {
981 case GSM_BTS_TYPE_BS11:
982 fclose(sw->stream);
983 break;
984 default:
985 close(sw->fd);
986 break;
987 }
988}
989
990/* Fill the window */
991static int sw_fill_window(struct abis_nm_sw *sw)
992{
993 int rc;
994
995 while (sw->seg_in_window < sw->window_size) {
996 rc = sw_load_segment(sw);
997 if (rc < 0)
998 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000999 if (sw->last_seg)
1000 break;
Harald Welte4724f992009-01-18 18:01:49 +00001001 }
1002 return 0;
1003}
1004
1005/* callback function from abis_nm_rcvmsg() handler */
1006static int abis_nm_rcvmsg_sw(struct msgb *mb)
1007{
1008 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1009 int rc = -1;
1010 struct abis_nm_sw *sw = &g_sw;
1011 enum sw_state old_state = sw->state;
1012
Harald Welte3ffd1372009-02-01 22:15:49 +00001013 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001014
1015 switch (sw->state) {
1016 case SW_STATE_WAIT_INITACK:
1017 switch (foh->msg_type) {
1018 case NM_MT_LOAD_INIT_ACK:
1019 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001020 if (sw->cbfn)
1021 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1022 NM_MT_LOAD_INIT_ACK, mb,
1023 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001024 rc = sw_fill_window(sw);
1025 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001026 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001027 break;
1028 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001029 if (sw->forced) {
1030 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1031 "Init NACK\n");
1032 if (sw->cbfn)
1033 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1034 NM_MT_LOAD_INIT_ACK, mb,
1035 sw->cb_data, NULL);
1036 rc = sw_fill_window(sw);
1037 sw->state = SW_STATE_WAIT_SEGACK;
1038 } else {
1039 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001040 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001041 if (sw->cbfn)
1042 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1043 NM_MT_LOAD_INIT_NACK, mb,
1044 sw->cb_data, NULL);
1045 sw->state = SW_STATE_ERROR;
1046 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001047 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001048 break;
1049 }
1050 break;
1051 case SW_STATE_WAIT_SEGACK:
1052 switch (foh->msg_type) {
1053 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001054 if (sw->cbfn)
1055 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1056 NM_MT_LOAD_SEG_ACK, mb,
1057 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001058 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001059 if (!sw->last_seg) {
1060 /* fill window with more segments */
1061 rc = sw_fill_window(sw);
1062 sw->state = SW_STATE_WAIT_SEGACK;
1063 } else {
1064 /* end the transfer */
1065 sw->state = SW_STATE_WAIT_ENDACK;
1066 rc = sw_load_end(sw);
1067 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001068 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001069 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001070 case NM_MT_LOAD_ABORT:
1071 if (sw->cbfn)
1072 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1073 NM_MT_LOAD_ABORT, mb,
1074 sw->cb_data, NULL);
1075 break;
Harald Welte4724f992009-01-18 18:01:49 +00001076 }
1077 break;
1078 case SW_STATE_WAIT_ENDACK:
1079 switch (foh->msg_type) {
1080 case NM_MT_LOAD_END_ACK:
1081 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001082 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1083 sw->bts->nr);
1084 sw->state = SW_STATE_NONE;
1085 if (sw->cbfn)
1086 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1087 NM_MT_LOAD_END_ACK, mb,
1088 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001089 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001090 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001091 break;
1092 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001093 if (sw->forced) {
1094 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1095 "End NACK\n");
1096 sw->state = SW_STATE_NONE;
1097 if (sw->cbfn)
1098 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1099 NM_MT_LOAD_END_ACK, mb,
1100 sw->cb_data, NULL);
1101 } else {
1102 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001103 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001104 sw->state = SW_STATE_ERROR;
1105 if (sw->cbfn)
1106 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1107 NM_MT_LOAD_END_NACK, mb,
1108 sw->cb_data, NULL);
1109 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001110 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001111 break;
1112 }
1113 case SW_STATE_WAIT_ACTACK:
1114 switch (foh->msg_type) {
1115 case NM_MT_ACTIVATE_SW_ACK:
1116 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001117 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001118 sw->state = SW_STATE_NONE;
1119 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001120 if (sw->cbfn)
1121 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1122 NM_MT_ACTIVATE_SW_ACK, mb,
1123 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001124 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001125 break;
1126 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001127 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001128 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001129 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001130 if (sw->cbfn)
1131 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1132 NM_MT_ACTIVATE_SW_NACK, mb,
1133 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001134 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001135 break;
1136 }
1137 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001138 switch (foh->msg_type) {
1139 case NM_MT_ACTIVATE_SW_ACK:
1140 rc = 0;
1141 break;
1142 }
1143 break;
Harald Welte4724f992009-01-18 18:01:49 +00001144 case SW_STATE_ERROR:
1145 break;
1146 }
1147
1148 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001149 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001150 foh->msg_type, old_state, sw->state);
1151
1152 return rc;
1153}
1154
1155/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001156int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001157 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001158 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001159{
1160 struct abis_nm_sw *sw = &g_sw;
1161 int rc;
1162
Harald Welte5e4d1b32009-02-01 13:36:56 +00001163 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1164 bts->nr, fname);
1165
Harald Welte4724f992009-01-18 18:01:49 +00001166 if (sw->state != SW_STATE_NONE)
1167 return -EBUSY;
1168
1169 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001170 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001171
1172 switch (bts->type) {
1173 case GSM_BTS_TYPE_BS11:
1174 sw->obj_class = NM_OC_SITE_MANAGER;
1175 sw->obj_instance[0] = 0xff;
1176 sw->obj_instance[1] = 0xff;
1177 sw->obj_instance[2] = 0xff;
1178 break;
1179 case GSM_BTS_TYPE_NANOBTS:
1180 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001181 sw->obj_instance[0] = sw->bts->nr;
1182 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001183 sw->obj_instance[2] = 0xff;
1184 break;
1185 case GSM_BTS_TYPE_UNKNOWN:
1186 default:
1187 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1188 return -1;
1189 break;
1190 }
Harald Welte4724f992009-01-18 18:01:49 +00001191 sw->window_size = win_size;
1192 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001193 sw->cbfn = cbfn;
1194 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001195 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001196
1197 rc = sw_open_file(sw, fname);
1198 if (rc < 0) {
1199 sw->state = SW_STATE_NONE;
1200 return rc;
1201 }
1202
1203 return sw_load_init(sw);
1204}
Harald Welte52b1f982008-12-23 20:25:15 +00001205
Harald Welte1602ade2009-01-29 21:12:39 +00001206int abis_nm_software_load_status(struct gsm_bts *bts)
1207{
1208 struct abis_nm_sw *sw = &g_sw;
1209 struct stat st;
1210 int rc, percent;
1211
1212 rc = fstat(sw->fd, &st);
1213 if (rc < 0) {
1214 perror("ERROR during stat");
1215 return rc;
1216 }
1217
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001218 if (sw->stream)
1219 percent = (ftell(sw->stream) * 100) / st.st_size;
1220 else
1221 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001222 return percent;
1223}
1224
Harald Welte5e4d1b32009-02-01 13:36:56 +00001225/* Activate the specified software into the BTS */
1226int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1227 gsm_cbfn *cbfn, void *cb_data)
1228{
1229 struct abis_nm_sw *sw = &g_sw;
1230 int rc;
1231
1232 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1233 bts->nr, fname);
1234
1235 if (sw->state != SW_STATE_NONE)
1236 return -EBUSY;
1237
1238 sw->bts = bts;
1239 sw->obj_class = NM_OC_SITE_MANAGER;
1240 sw->obj_instance[0] = 0xff;
1241 sw->obj_instance[1] = 0xff;
1242 sw->obj_instance[2] = 0xff;
1243 sw->state = SW_STATE_WAIT_ACTACK;
1244 sw->cbfn = cbfn;
1245 sw->cb_data = cb_data;
1246
1247 /* Open the file in order to fill some sw struct members */
1248 rc = sw_open_file(sw, fname);
1249 if (rc < 0) {
1250 sw->state = SW_STATE_NONE;
1251 return rc;
1252 }
1253 sw_close_file(sw);
1254
1255 return sw_activate(sw);
1256}
1257
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001258static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1259 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001260{
Harald Welteadaf08b2009-01-18 11:08:10 +00001261 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001262 ch->bts_port = bts_port;
1263 ch->timeslot = ts_nr;
1264 ch->subslot = subslot_nr;
1265}
1266
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001267int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1268 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1269 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001270{
1271 struct abis_om_hdr *oh;
1272 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001273 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001274 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001275
1276 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1277 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1278 bts->bts_nr, trx_nr, 0xff);
1279
Harald Welte8470bf22008-12-25 23:28:35 +00001280 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001281
1282 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1283 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1284
1285 return abis_nm_sendmsg(bts, msg);
1286}
1287
1288/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1289int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001290 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001291{
Harald Welte8470bf22008-12-25 23:28:35 +00001292 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001293 struct abis_om_hdr *oh;
1294 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001295 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001296
1297 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001298 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001299 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1300
1301 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1302 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1303
1304 return abis_nm_sendmsg(bts, msg);
1305}
1306
1307#if 0
1308int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1309 struct abis_nm_abis_channel *chan)
1310{
1311}
1312#endif
1313
1314int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001315 uint8_t e1_port, uint8_t e1_timeslot,
1316 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001317{
1318 struct gsm_bts *bts = ts->trx->bts;
1319 struct abis_om_hdr *oh;
1320 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001321 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001322
1323 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1324 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001325 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001326
1327 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1328 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1329
Harald Weltef325eb42009-02-19 17:07:39 +00001330 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1331 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001332 e1_port, e1_timeslot, e1_subslot);
1333
Harald Welte52b1f982008-12-23 20:25:15 +00001334 return abis_nm_sendmsg(bts, msg);
1335}
1336
1337#if 0
1338int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1339 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001340 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001341{
1342}
1343#endif
1344
Harald Welte22af0db2009-02-14 15:41:08 +00001345/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001346int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001347{
1348 struct abis_om_hdr *oh;
1349 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001350 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001351
1352 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1353
1354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001355 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 +00001356 cur = msgb_put(msg, attr_len);
1357 memcpy(cur, attr, attr_len);
1358
1359 return abis_nm_sendmsg(bts, msg);
1360}
1361
1362/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001363int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001364{
1365 struct abis_om_hdr *oh;
1366 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001367 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001368
1369 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1370
1371 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1372 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001373 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001374 cur = msgb_put(msg, attr_len);
1375 memcpy(cur, attr, attr_len);
1376
1377 return abis_nm_sendmsg(trx->bts, msg);
1378}
1379
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001380static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001381{
1382 int i;
1383
1384 /* As it turns out, the BS-11 has some very peculiar restrictions
1385 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301386 switch (ts->trx->bts->type) {
1387 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001388 switch (chan_comb) {
1389 case NM_CHANC_TCHHalf:
1390 case NM_CHANC_TCHHalf2:
1391 /* not supported */
1392 return -EINVAL;
1393 case NM_CHANC_SDCCH:
1394 /* only one SDCCH/8 per TRX */
1395 for (i = 0; i < TRX_NR_TS; i++) {
1396 if (i == ts->nr)
1397 continue;
1398 if (ts->trx->ts[i].nm_chan_comb ==
1399 NM_CHANC_SDCCH)
1400 return -EINVAL;
1401 }
1402 /* not allowed for TS0 of BCCH-TRX */
1403 if (ts->trx == ts->trx->bts->c0 &&
1404 ts->nr == 0)
1405 return -EINVAL;
1406 /* not on the same TRX that has a BCCH+SDCCH4
1407 * combination */
1408 if (ts->trx == ts->trx->bts->c0 &&
1409 (ts->trx->ts[0].nm_chan_comb == 5 ||
1410 ts->trx->ts[0].nm_chan_comb == 8))
1411 return -EINVAL;
1412 break;
1413 case NM_CHANC_mainBCCH:
1414 case NM_CHANC_BCCHComb:
1415 /* allowed only for TS0 of C0 */
1416 if (ts->trx != ts->trx->bts->c0 ||
1417 ts->nr != 0)
1418 return -EINVAL;
1419 break;
1420 case NM_CHANC_BCCH:
1421 /* allowed only for TS 2/4/6 of C0 */
1422 if (ts->trx != ts->trx->bts->c0)
1423 return -EINVAL;
1424 if (ts->nr != 2 && ts->nr != 4 &&
1425 ts->nr != 6)
1426 return -EINVAL;
1427 break;
1428 case 8: /* this is not like 08.58, but in fact
1429 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1430 /* FIXME: only one CBCH allowed per cell */
1431 break;
1432 }
Harald Welted6575f92009-12-02 02:45:23 +05301433 break;
1434 case GSM_BTS_TYPE_NANOBTS:
1435 switch (ts->nr) {
1436 case 0:
1437 if (ts->trx->nr == 0) {
1438 /* only on TRX0 */
1439 switch (chan_comb) {
1440 case NM_CHANC_BCCH:
1441 case NM_CHANC_mainBCCH:
1442 case NM_CHANC_BCCHComb:
1443 return 0;
1444 break;
1445 default:
1446 return -EINVAL;
1447 }
1448 } else {
1449 switch (chan_comb) {
1450 case NM_CHANC_TCHFull:
1451 case NM_CHANC_TCHHalf:
1452 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1453 return 0;
1454 default:
1455 return -EINVAL;
1456 }
1457 }
1458 break;
1459 case 1:
1460 if (ts->trx->nr == 0) {
1461 switch (chan_comb) {
1462 case NM_CHANC_SDCCH_CBCH:
1463 if (ts->trx->ts[0].nm_chan_comb ==
1464 NM_CHANC_mainBCCH)
1465 return 0;
1466 return -EINVAL;
1467 case NM_CHANC_SDCCH:
1468 case NM_CHANC_TCHFull:
1469 case NM_CHANC_TCHHalf:
1470 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1471 case NM_CHANC_IPAC_TCHFull_PDCH:
1472 return 0;
1473 }
1474 } else {
1475 switch (chan_comb) {
1476 case NM_CHANC_SDCCH:
1477 case NM_CHANC_TCHFull:
1478 case NM_CHANC_TCHHalf:
1479 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1480 return 0;
1481 default:
1482 return -EINVAL;
1483 }
1484 }
1485 break;
1486 case 2:
1487 case 3:
1488 case 4:
1489 case 5:
1490 case 6:
1491 case 7:
1492 switch (chan_comb) {
1493 case NM_CHANC_TCHFull:
1494 case NM_CHANC_TCHHalf:
1495 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1496 return 0;
1497 case NM_CHANC_IPAC_PDCH:
1498 case NM_CHANC_IPAC_TCHFull_PDCH:
1499 if (ts->trx->nr == 0)
1500 return 0;
1501 else
1502 return -EINVAL;
1503 }
1504 break;
1505 }
1506 return -EINVAL;
1507 default:
1508 /* unknown BTS type */
1509 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001510 }
1511 return 0;
1512}
1513
Harald Welte22af0db2009-02-14 15:41:08 +00001514/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001515int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001516{
1517 struct gsm_bts *bts = ts->trx->bts;
1518 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001519 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001520 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001521 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00001522
1523 if (bts->type == GSM_BTS_TYPE_BS11)
1524 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001525
Harald Weltef325eb42009-02-19 17:07:39 +00001526 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001527 if (verify_chan_comb(ts, chan_comb) < 0) {
1528 msgb_free(msg);
1529 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1530 return -EINVAL;
1531 }
1532 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001533
Harald Welte52b1f982008-12-23 20:25:15 +00001534 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001535 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001536 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001537 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001538 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001539 if (ts->hopping.enabled) {
1540 unsigned int i;
1541 uint8_t *len;
1542
Harald Welte6e0cd042009-09-12 13:05:33 +02001543 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1544 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001545
1546 /* build the ARFCN list */
1547 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1548 len = msgb_put(msg, 1);
1549 *len = 0;
1550 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1551 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1552 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001553 /* At least BS-11 wants a TLV16 here */
1554 if (bts->type == GSM_BTS_TYPE_BS11)
1555 *len += 1;
1556 else
1557 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001558 }
1559 }
Harald Weltee0590df2009-02-15 03:34:15 +00001560 }
Harald Welte135a6482011-05-30 12:09:13 +02001561 if (ts->tsc == -1)
1562 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1563 else
1564 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001565 if (bts->type == GSM_BTS_TYPE_BS11)
1566 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001567
1568 return abis_nm_sendmsg(bts, msg);
1569}
1570
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001571int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1572 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001573{
1574 struct abis_om_hdr *oh;
1575 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001576 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1577 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001578
1579 if (nack) {
1580 len += 2;
1581 msgtype = NM_MT_SW_ACT_REQ_NACK;
1582 }
Harald Welte34a99682009-02-13 02:41:40 +00001583
1584 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001585 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1586
Harald Welte34a99682009-02-13 02:41:40 +00001587 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001588 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001589 memcpy(ptr, attr, att_len);
1590 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001591 if (nack)
1592 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001593
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001594 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001595}
1596
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001597int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001598{
Harald Welte8470bf22008-12-25 23:28:35 +00001599 struct msgb *msg = nm_msgb_alloc();
1600 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001601 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001602
1603 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1604 fill_om_hdr(oh, len);
1605 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001606 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001607
1608 return abis_nm_sendmsg(bts, msg);
1609}
1610
1611/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001612static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001613{
1614 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001615 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001616
1617 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001618 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001619 0xff, 0xff, 0xff);
1620
1621 return abis_nm_sendmsg(bts, msg);
1622}
1623
Harald Welte34a99682009-02-13 02:41:40 +00001624/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001625int 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 +00001626{
1627 struct abis_om_hdr *oh;
1628 struct msgb *msg = nm_msgb_alloc();
1629
1630 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1631 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1632
Harald Welte15c61722011-05-22 22:45:37 +02001633 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001634 DEBUGPC(DNM, "Sending OPSTART\n");
1635
Harald Welte34a99682009-02-13 02:41:40 +00001636 return abis_nm_sendmsg(bts, msg);
1637}
1638
1639/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001640int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1641 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001642{
1643 struct abis_om_hdr *oh;
1644 struct msgb *msg = nm_msgb_alloc();
1645
1646 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1647 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1648 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1649
1650 return abis_nm_sendmsg(bts, msg);
1651}
1652
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001653int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1654 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001655{
1656 struct abis_om_hdr *oh;
1657 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001658 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001659
1660 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1661 e1_port0, ts0, e1_port1, ts1);
1662
1663 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1664 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1665 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1666
1667 attr = msgb_put(msg, 3);
1668 attr[0] = NM_ATT_MDROP_LINK;
1669 attr[1] = e1_port0;
1670 attr[2] = ts0;
1671
1672 attr = msgb_put(msg, 3);
1673 attr[0] = NM_ATT_MDROP_NEXT;
1674 attr[1] = e1_port1;
1675 attr[2] = ts1;
1676
1677 return abis_nm_sendmsg(bts, msg);
1678}
Harald Welte34a99682009-02-13 02:41:40 +00001679
Harald Weltec7310382009-08-08 00:02:36 +02001680/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001681int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1682 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1683 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001684{
1685 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001686
Harald Welte15c61722011-05-22 22:45:37 +02001687 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001688
1689 if (!msg)
1690 msg = nm_msgb_alloc();
1691
1692 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1693 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1694 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1695 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001696 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001697
1698 return abis_nm_sendmsg(bts, msg);
1699}
1700
Harald Welte52b1f982008-12-23 20:25:15 +00001701int abis_nm_event_reports(struct gsm_bts *bts, int on)
1702{
1703 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001704 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001705 else
Harald Welte227d4072009-01-03 08:16:25 +00001706 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001707}
1708
Harald Welte47d88ae2009-01-04 12:02:08 +00001709/* Siemens (or BS-11) specific commands */
1710
Harald Welte3ffd1372009-02-01 22:15:49 +00001711int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1712{
1713 if (reconnect == 0)
1714 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1715 else
1716 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1717}
1718
Harald Welteb8427972009-02-05 19:27:17 +00001719int abis_nm_bs11_restart(struct gsm_bts *bts)
1720{
1721 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1722}
1723
1724
Harald Welte268bb402009-02-01 19:11:56 +00001725struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001726 uint16_t year;
1727 uint8_t month;
1728 uint8_t day;
1729 uint8_t hour;
1730 uint8_t min;
1731 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001732} __attribute__((packed));
1733
1734
1735void get_bs11_date_time(struct bs11_date_time *aet)
1736{
1737 time_t t;
1738 struct tm *tm;
1739
1740 t = time(NULL);
1741 tm = localtime(&t);
1742 aet->sec = tm->tm_sec;
1743 aet->min = tm->tm_min;
1744 aet->hour = tm->tm_hour;
1745 aet->day = tm->tm_mday;
1746 aet->month = tm->tm_mon;
1747 aet->year = htons(1900 + tm->tm_year);
1748}
1749
Harald Welte05188ee2009-01-18 11:39:08 +00001750int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001751{
Harald Welte4668fda2009-01-03 08:19:29 +00001752 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001753}
1754
Harald Welte05188ee2009-01-18 11:39:08 +00001755int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001756{
1757 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001758 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001759 else
Harald Welte4668fda2009-01-03 08:19:29 +00001760 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001761}
Harald Welte47d88ae2009-01-04 12:02:08 +00001762
Harald Welte05188ee2009-01-18 11:39:08 +00001763int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001764 enum abis_bs11_objtype type, uint8_t idx,
1765 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001766{
1767 struct abis_om_hdr *oh;
1768 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001769 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001770
1771 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001772 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001773 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001774 cur = msgb_put(msg, attr_len);
1775 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001776
1777 return abis_nm_sendmsg(bts, msg);
1778}
1779
Harald Welte78fc0d42009-02-19 02:50:57 +00001780int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001781 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001782{
1783 struct abis_om_hdr *oh;
1784 struct msgb *msg = nm_msgb_alloc();
1785
1786 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1787 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1788 NM_OC_BS11, type, 0, idx);
1789
1790 return abis_nm_sendmsg(bts, msg);
1791}
1792
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001793int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001794{
1795 struct abis_om_hdr *oh;
1796 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001797 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001798
1799 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001800 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001801 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1802 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001803
1804 return abis_nm_sendmsg(bts, msg);
1805}
1806
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001807int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001808{
1809 struct abis_om_hdr *oh;
1810 struct msgb *msg = nm_msgb_alloc();
1811
1812 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1813 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001814 idx, 0xff, 0xff);
1815
1816 return abis_nm_sendmsg(bts, msg);
1817}
1818
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001819int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001820{
1821 struct abis_om_hdr *oh;
1822 struct msgb *msg = nm_msgb_alloc();
1823
1824 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1825 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1826 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001827
1828 return abis_nm_sendmsg(bts, msg);
1829}
Harald Welte05188ee2009-01-18 11:39:08 +00001830
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001831static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001832int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1833{
1834 struct abis_om_hdr *oh;
1835 struct msgb *msg = nm_msgb_alloc();
1836
1837 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1838 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1839 0xff, 0xff, 0xff);
1840 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1841
1842 return abis_nm_sendmsg(bts, msg);
1843}
1844
Harald Welteb6c92ae2009-02-21 20:15:32 +00001845/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001846int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1847 uint8_t e1_timeslot, uint8_t e1_subslot,
1848 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001849{
1850 struct abis_om_hdr *oh;
1851 struct abis_nm_channel *ch;
1852 struct msgb *msg = nm_msgb_alloc();
1853
1854 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001855 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001856 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1857
1858 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1859 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001860 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001861
1862 return abis_nm_sendmsg(bts, msg);
1863}
1864
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001865int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00001866{
1867 struct abis_om_hdr *oh;
1868 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00001869
1870 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001871 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001872 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1873 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1874
1875 return abis_nm_sendmsg(trx->bts, msg);
1876}
1877
Harald Welte78fc0d42009-02-19 02:50:57 +00001878int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1879{
1880 struct abis_om_hdr *oh;
1881 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001882 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00001883
1884 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1885 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1886 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1887 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1888
1889 return abis_nm_sendmsg(trx->bts, msg);
1890}
1891
Harald Welteaaf02d92009-04-29 13:25:57 +00001892int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1893{
1894 struct abis_om_hdr *oh;
1895 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001896 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00001897
1898 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1899 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1900 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00001901 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00001902
1903 return abis_nm_sendmsg(bts, msg);
1904}
1905
Harald Welteef061952009-05-17 12:43:42 +00001906int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1907{
1908 struct abis_om_hdr *oh;
1909 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001910 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00001911 NM_ATT_BS11_CCLK_TYPE };
1912
1913 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1914 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1915 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1916 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1917
1918 return abis_nm_sendmsg(bts, msg);
1919
1920}
Harald Welteaaf02d92009-04-29 13:25:57 +00001921
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001922//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00001923
Harald Welte1bc09062009-01-18 14:17:52 +00001924int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00001925{
Daniel Willmann493db4e2010-01-07 00:43:11 +01001926 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1927}
1928
Daniel Willmann4b054c82010-01-07 00:46:26 +01001929int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1930{
1931 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1932}
1933
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001934int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001935{
Harald Welte05188ee2009-01-18 11:39:08 +00001936 struct abis_om_hdr *oh;
1937 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00001938 struct bs11_date_time bdt;
1939
1940 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00001941
1942 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00001943 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001944 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01001945 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00001946 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001947 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00001948 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001949 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00001950 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01001951 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00001952 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001953 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00001954 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00001955 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00001956 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00001957 }
Harald Welte05188ee2009-01-18 11:39:08 +00001958
1959 return abis_nm_sendmsg(bts, msg);
1960}
Harald Welte1bc09062009-01-18 14:17:52 +00001961
1962int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
1963{
1964 struct abis_om_hdr *oh;
1965 struct msgb *msg;
1966
1967 if (strlen(password) != 10)
1968 return -EINVAL;
1969
1970 msg = nm_msgb_alloc();
1971 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001972 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00001973 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001974 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00001975
1976 return abis_nm_sendmsg(bts, msg);
1977}
1978
Harald Weltee69f5fb2009-04-28 16:31:38 +00001979/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
1980int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
1981{
1982 struct abis_om_hdr *oh;
1983 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001984 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00001985
1986 msg = nm_msgb_alloc();
1987 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1988 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
1989 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00001990
1991 if (locked)
1992 tlv_value = BS11_LI_PLL_LOCKED;
1993 else
1994 tlv_value = BS11_LI_PLL_STANDALONE;
1995
1996 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00001997
1998 return abis_nm_sendmsg(bts, msg);
1999}
2000
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002001/* Set the calibration value of the PLL (work value/set value)
2002 * It depends on the login which one is changed */
2003int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2004{
2005 struct abis_om_hdr *oh;
2006 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002007 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002008
2009 msg = nm_msgb_alloc();
2010 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2011 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2012 BS11_OBJ_TRX1, 0x00, 0x00);
2013
2014 tlv_value[0] = value>>8;
2015 tlv_value[1] = value&0xff;
2016
2017 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2018
2019 return abis_nm_sendmsg(bts, msg);
2020}
2021
Harald Welte1bc09062009-01-18 14:17:52 +00002022int abis_nm_bs11_get_state(struct gsm_bts *bts)
2023{
2024 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2025}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002026
2027/* BS11 SWL */
2028
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002029void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002030
Harald Welte5e4d1b32009-02-01 13:36:56 +00002031struct abis_nm_bs11_sw {
2032 struct gsm_bts *bts;
2033 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002034 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002035 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002036 struct llist_head file_list;
2037 gsm_cbfn *user_cb; /* specified by the user */
2038};
2039static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2040
2041struct file_list_entry {
2042 struct llist_head list;
2043 char fname[PATH_MAX];
2044};
2045
2046struct file_list_entry *fl_dequeue(struct llist_head *queue)
2047{
2048 struct llist_head *lh;
2049
2050 if (llist_empty(queue))
2051 return NULL;
2052
2053 lh = queue->next;
2054 llist_del(lh);
2055
2056 return llist_entry(lh, struct file_list_entry, list);
2057}
2058
2059static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2060{
2061 char linebuf[255];
2062 struct llist_head *lh, *lh2;
2063 FILE *swl;
2064 int rc = 0;
2065
2066 swl = fopen(bs11_sw->swl_fname, "r");
2067 if (!swl)
2068 return -ENODEV;
2069
2070 /* zero the stale file list, if any */
2071 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2072 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002073 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002074 }
2075
2076 while (fgets(linebuf, sizeof(linebuf), swl)) {
2077 char file_id[12+1];
2078 char file_version[80+1];
2079 struct file_list_entry *fle;
2080 static char dir[PATH_MAX];
2081
2082 if (strlen(linebuf) < 4)
2083 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002084
Harald Welte5e4d1b32009-02-01 13:36:56 +00002085 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2086 if (rc < 0) {
2087 perror("ERR parsing SWL file");
2088 rc = -EINVAL;
2089 goto out;
2090 }
2091 if (rc < 2)
2092 continue;
2093
Harald Welte470ec292009-06-26 20:25:23 +02002094 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002095 if (!fle) {
2096 rc = -ENOMEM;
2097 goto out;
2098 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002099
2100 /* construct new filename */
2101 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2102 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2103 strcat(fle->fname, "/");
2104 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002105
2106 llist_add_tail(&fle->list, &bs11_sw->file_list);
2107 }
2108
2109out:
2110 fclose(swl);
2111 return rc;
2112}
2113
2114/* bs11 swload specific callback, passed to abis_nm core swload */
2115static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2116 struct msgb *msg, void *data, void *param)
2117{
2118 struct abis_nm_bs11_sw *bs11_sw = data;
2119 struct file_list_entry *fle;
2120 int rc = 0;
2121
Harald Welte5e4d1b32009-02-01 13:36:56 +00002122 switch (event) {
2123 case NM_MT_LOAD_END_ACK:
2124 fle = fl_dequeue(&bs11_sw->file_list);
2125 if (fle) {
2126 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002127 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002128 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002129 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002130 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002131 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002132 } else {
2133 /* activate the SWL */
2134 rc = abis_nm_software_activate(bs11_sw->bts,
2135 bs11_sw->swl_fname,
2136 bs11_swload_cbfn,
2137 bs11_sw);
2138 }
2139 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002140 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002141 case NM_MT_LOAD_END_NACK:
2142 case NM_MT_LOAD_INIT_ACK:
2143 case NM_MT_LOAD_INIT_NACK:
2144 case NM_MT_ACTIVATE_SW_NACK:
2145 case NM_MT_ACTIVATE_SW_ACK:
2146 default:
2147 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002148 if (bs11_sw->user_cb)
2149 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002150 break;
2151 }
2152
2153 return rc;
2154}
2155
2156/* Siemens provides a SWL file that is a mere listing of all the other
2157 * files that are part of a software release. We need to upload first
2158 * the list file, and then each file that is listed in the list file */
2159int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002160 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002161{
2162 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2163 struct file_list_entry *fle;
2164 int rc = 0;
2165
2166 INIT_LLIST_HEAD(&bs11_sw->file_list);
2167 bs11_sw->bts = bts;
2168 bs11_sw->win_size = win_size;
2169 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002170 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002171
2172 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2173 rc = bs11_read_swl_file(bs11_sw);
2174 if (rc < 0)
2175 return rc;
2176
2177 /* dequeue next item in file list */
2178 fle = fl_dequeue(&bs11_sw->file_list);
2179 if (!fle)
2180 return -EINVAL;
2181
2182 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002183 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002184 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002185 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002186 return rc;
2187}
2188
Harald Welte5083b0b2009-02-02 19:20:52 +00002189#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002190static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002191 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2192 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2193 NM_ATT_BS11_LMT_USER_NAME,
2194
2195 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2196
2197 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2198
2199 NM_ATT_BS11_SW_LOAD_STORED };
2200
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002201static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002202 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2203 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2204 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2205 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002206#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002207
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002208static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002209 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2210 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002211 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002212
2213int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2214{
2215 struct abis_om_hdr *oh;
2216 struct msgb *msg = nm_msgb_alloc();
2217
2218 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2219 /* SiemensHW CCTRL object */
2220 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2221 0x03, 0x00, 0x00);
2222 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2223
2224 return abis_nm_sendmsg(bts, msg);
2225}
Harald Welte268bb402009-02-01 19:11:56 +00002226
2227int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2228{
2229 struct abis_om_hdr *oh;
2230 struct msgb *msg = nm_msgb_alloc();
2231 struct bs11_date_time aet;
2232
2233 get_bs11_date_time(&aet);
2234 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2235 /* SiemensHW CCTRL object */
2236 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2237 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002238 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002239
2240 return abis_nm_sendmsg(bts, msg);
2241}
Harald Welte5c1e4582009-02-15 11:57:29 +00002242
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002243int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002244{
2245 struct abis_om_hdr *oh;
2246 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002247 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002248
2249 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2250 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2251 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2252 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2253
2254 return abis_nm_sendmsg(bts, msg);
2255}
2256
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002257int 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 +02002258{
2259 struct abis_om_hdr *oh;
2260 struct msgb *msg = nm_msgb_alloc();
2261 struct bs11_date_time aet;
2262
2263 get_bs11_date_time(&aet);
2264 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2265 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2266 bport, 0xff, 0x02);
2267 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2268
2269 return abis_nm_sendmsg(bts, msg);
2270}
2271
Harald Welte5c1e4582009-02-15 11:57:29 +00002272/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002273static const char ipaccess_magic[] = "com.ipaccess";
2274
Harald Welte677c21f2009-02-17 13:22:23 +00002275
2276static int abis_nm_rx_ipacc(struct msgb *msg)
2277{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002278 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002279 struct abis_om_hdr *oh = msgb_l2(msg);
2280 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002281 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002282 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002283 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002284
2285 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002286 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002287 return -EINVAL;
2288 }
2289
Harald Welte193fefc2009-04-30 15:16:27 +00002290 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002291 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002292
Harald Welte15c61722011-05-22 22:45:37 +02002293 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002294
Harald Welte746d6092009-10-19 22:11:11 +02002295 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002296
Harald Welte677c21f2009-02-17 13:22:23 +00002297 switch (foh->msg_type) {
2298 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002299 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002300 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2301 memcpy(&addr,
2302 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2303
2304 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2305 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002306 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002307 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002308 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002309 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002310 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2311 DEBUGPC(DNM, "STREAM=0x%02x ",
2312 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002313 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002314 break;
2315 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002316 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002317 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002318 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002319 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002320 else
2321 DEBUGPC(DNM, "\n");
2322 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002323 case NM_MT_IPACC_SET_NVATTR_ACK:
2324 DEBUGPC(DNM, "SET NVATTR ACK\n");
2325 /* FIXME: decode and show the actual attributes */
2326 break;
2327 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002328 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002329 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002330 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002331 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002332 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002333 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002334 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002335 case NM_MT_IPACC_GET_NVATTR_ACK:
2336 DEBUGPC(DNM, "GET NVATTR ACK\n");
2337 /* FIXME: decode and show the actual attributes */
2338 break;
2339 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002340 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002341 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002342 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002343 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002344 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002345 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002346 break;
Harald Welte15c44172009-10-08 20:15:24 +02002347 case NM_MT_IPACC_SET_ATTR_ACK:
2348 DEBUGPC(DNM, "SET ATTR ACK\n");
2349 break;
2350 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002351 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002352 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002353 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002354 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002355 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002356 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002357 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002358 default:
2359 DEBUGPC(DNM, "unknown\n");
2360 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002361 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002362
2363 /* signal handling */
2364 switch (foh->msg_type) {
2365 case NM_MT_IPACC_RSL_CONNECT_NACK:
2366 case NM_MT_IPACC_SET_NVATTR_NACK:
2367 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002368 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002369 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002370 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002371 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002372 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002373 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002374 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002375 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002376 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002377 default:
2378 break;
2379 }
2380
Harald Welte677c21f2009-02-17 13:22:23 +00002381 return 0;
2382}
2383
Harald Welte193fefc2009-04-30 15:16:27 +00002384/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002385int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2386 uint8_t obj_class, uint8_t bts_nr,
2387 uint8_t trx_nr, uint8_t ts_nr,
2388 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002389{
2390 struct msgb *msg = nm_msgb_alloc();
2391 struct abis_om_hdr *oh;
2392 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002393 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002394
2395 /* construct the 12.21 OM header, observe the erroneous length */
2396 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2397 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2398 oh->mdisc = ABIS_OM_MDISC_MANUF;
2399
2400 /* add the ip.access magic */
2401 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2402 *data++ = sizeof(ipaccess_magic);
2403 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2404
2405 /* fill the 12.21 FOM header */
2406 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2407 foh->msg_type = msg_type;
2408 foh->obj_class = obj_class;
2409 foh->obj_inst.bts_nr = bts_nr;
2410 foh->obj_inst.trx_nr = trx_nr;
2411 foh->obj_inst.ts_nr = ts_nr;
2412
2413 if (attr && attr_len) {
2414 data = msgb_put(msg, attr_len);
2415 memcpy(data, attr, attr_len);
2416 }
2417
2418 return abis_nm_sendmsg(bts, msg);
2419}
Harald Welte677c21f2009-02-17 13:22:23 +00002420
Harald Welte193fefc2009-04-30 15:16:27 +00002421/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002422int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002423 int attr_len)
2424{
Harald Welte2ef156d2010-01-07 20:39:42 +01002425 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2426 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002427 attr_len);
2428}
2429
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002430int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002431 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002432{
2433 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002434 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002435 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2436 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2437
2438 int attr_len = sizeof(attr);
2439
2440 ia.s_addr = htonl(ip);
2441 attr[1] = stream;
2442 attr[3] = port >> 8;
2443 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002444 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002445
2446 /* if ip == 0, we use the default IP */
2447 if (ip == 0)
2448 attr_len -= 5;
2449
2450 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002451 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002452
2453 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2454 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2455 trx->nr, 0xff, attr, attr_len);
2456}
2457
Harald Welte193fefc2009-04-30 15:16:27 +00002458/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002459int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002460{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002461 struct abis_om_hdr *oh;
2462 struct msgb *msg = nm_msgb_alloc();
2463
2464 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2465 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2466 trx->bts->nr, trx->nr, 0xff);
2467
2468 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002469}
Harald Weltedaef5212009-10-24 10:20:41 +02002470
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002471int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2472 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2473 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002474{
2475 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2476 obj_class, bts_nr, trx_nr, ts_nr,
2477 attr, attr_len);
2478}
Harald Welte0f255852009-11-12 14:48:42 +01002479
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002480void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002481{
2482 /* we simply reuse the GSM48 function and overwrite the RAC
2483 * with the Cell ID */
2484 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002485 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002486}
2487
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002488void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2489{
2490 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2491
Harald Welted64c0bc2011-05-30 12:07:53 +02002492 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002493 if (!trx->bts || !trx->bts->oml_link)
2494 return;
2495
2496 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2497 trx->bts->bts_nr, trx->nr, 0xff,
2498 new_state);
2499}
2500
Harald Welte92b1fe42010-03-25 11:45:30 +08002501static const struct value_string ipacc_testres_names[] = {
2502 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2503 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2504 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2505 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2506 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2507 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002508};
2509
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002510const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002511{
Harald Welte92b1fe42010-03-25 11:45:30 +08002512 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002513}
2514
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002515void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002516{
2517 cid->mcc = (buf[0] & 0xf) * 100;
2518 cid->mcc += (buf[0] >> 4) * 10;
2519 cid->mcc += (buf[1] & 0xf) * 1;
2520
2521 if (buf[1] >> 4 == 0xf) {
2522 cid->mnc = (buf[2] & 0xf) * 10;
2523 cid->mnc += (buf[2] >> 4) * 1;
2524 } else {
2525 cid->mnc = (buf[2] & 0xf) * 100;
2526 cid->mnc += (buf[2] >> 4) * 10;
2527 cid->mnc += (buf[1] >> 4) * 1;
2528 }
2529
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002530 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2531 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002532}
2533
Harald Welte0f255852009-11-12 14:48:42 +01002534/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002535int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002536{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002537 uint8_t *cur = buf;
2538 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01002539
Harald Welteaf109b92010-07-22 18:14:36 +02002540 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002541
2542 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2543 return -EINVAL;
2544 cur++;
2545
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002546 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002547 cur += 2;
2548
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002549 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002550 cur += 2;
2551
2552 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2553 binf->freq_qual = *cur >> 2;
2554
Harald Welteaf109b92010-07-22 18:14:36 +02002555 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002556 binf->arfcn |= *cur++;
2557
2558 if (binf->info_type & IPAC_BINF_RXLEV)
2559 binf->rx_lev = *cur & 0x3f;
2560 cur++;
2561
2562 if (binf->info_type & IPAC_BINF_RXQUAL)
2563 binf->rx_qual = *cur & 0x7;
2564 cur++;
2565
2566 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002567 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002568 cur += 2;
2569
2570 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002571 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002572 cur += 2;
2573
2574 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002575 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002576 cur += 4;
2577
Harald Weltea780a3d2010-07-30 22:34:42 +02002578#if 0
2579 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002580 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002581#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002582 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002583 cur++;
2584
Harald Welteb40a38f2009-11-13 11:56:05 +01002585 ipac_parse_cgi(&binf->cgi, cur);
2586 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002587
2588 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2589 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2590 cur += sizeof(binf->ba_list_si2);
2591 }
2592
2593 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2594 memcpy(binf->ba_list_si2bis, cur,
2595 sizeof(binf->ba_list_si2bis));
2596 cur += sizeof(binf->ba_list_si2bis);
2597 }
2598
2599 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2600 memcpy(binf->ba_list_si2ter, cur,
2601 sizeof(binf->ba_list_si2ter));
2602 cur += sizeof(binf->ba_list_si2ter);
2603 }
2604
2605 return 0;
2606}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002607
2608void abis_nm_clear_queue(struct gsm_bts *bts)
2609{
2610 struct msgb *msg;
2611
2612 while (!llist_empty(&bts->abis_queue)) {
2613 msg = msgb_dequeue(&bts->abis_queue);
2614 msgb_free(msg);
2615 }
2616
2617 bts->abis_nm_pend = 0;
2618}