blob: f2220a7b7e54746eddd609534bd0039aba813f2e [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/* obtain the gsm_nm_state data structure for a given object instance */
154static struct gsm_nm_state *
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200155objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
Harald Weltee0590df2009-02-15 03:34:15 +0000156 struct abis_om_obj_inst *obj_inst)
157{
158 struct gsm_bts_trx *trx;
159 struct gsm_nm_state *nm_state = NULL;
160
161 switch (obj_class) {
162 case NM_OC_BTS:
163 nm_state = &bts->nm_state;
164 break;
165 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100166 if (obj_inst->trx_nr >= bts->num_trx) {
167 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000168 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100169 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200170 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000171 nm_state = &trx->nm_state;
172 break;
173 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100174 if (obj_inst->trx_nr >= bts->num_trx) {
175 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000176 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100177 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200178 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000179 nm_state = &trx->bb_transc.nm_state;
180 break;
181 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100182 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100183 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000184 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100185 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200186 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000187 if (obj_inst->ts_nr >= TRX_NR_TS)
188 return NULL;
189 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
190 break;
191 case NM_OC_SITE_MANAGER:
192 nm_state = &bts->site_mgr.nm_state;
193 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000194 case NM_OC_BS11:
195 switch (obj_inst->bts_nr) {
196 case BS11_OBJ_CCLK:
197 nm_state = &bts->bs11.cclk.nm_state;
198 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000199 case BS11_OBJ_BBSIG:
200 if (obj_inst->ts_nr > bts->num_trx)
201 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200202 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000203 nm_state = &trx->bs11.bbsig.nm_state;
204 break;
205 case BS11_OBJ_PA:
206 if (obj_inst->ts_nr > bts->num_trx)
207 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200208 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000209 nm_state = &trx->bs11.pa.nm_state;
210 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000211 default:
212 return NULL;
213 }
214 case NM_OC_BS11_RACK:
215 nm_state = &bts->bs11.rack.nm_state;
216 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000217 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100218 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000219 return NULL;
220 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
221 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200222 case NM_OC_GPRS_NSE:
223 nm_state = &bts->gprs.nse.nm_state;
224 break;
225 case NM_OC_GPRS_CELL:
226 nm_state = &bts->gprs.cell.nm_state;
227 break;
228 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100229 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200230 return NULL;
231 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
232 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000233 }
234 return nm_state;
235}
236
237/* obtain the in-memory data structure of a given object instance */
238static void *
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200239objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
Harald Weltee0590df2009-02-15 03:34:15 +0000240 struct abis_om_obj_inst *obj_inst)
241{
242 struct gsm_bts_trx *trx;
243 void *obj = NULL;
244
245 switch (obj_class) {
246 case NM_OC_BTS:
247 obj = bts;
248 break;
249 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100250 if (obj_inst->trx_nr >= bts->num_trx) {
251 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000252 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100253 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200254 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000255 obj = trx;
256 break;
257 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100258 if (obj_inst->trx_nr >= bts->num_trx) {
259 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000260 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100261 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200262 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000263 obj = &trx->bb_transc;
264 break;
265 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100266 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100267 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000268 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100269 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200270 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000271 if (obj_inst->ts_nr >= TRX_NR_TS)
272 return NULL;
273 obj = &trx->ts[obj_inst->ts_nr];
274 break;
275 case NM_OC_SITE_MANAGER:
276 obj = &bts->site_mgr;
277 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200278 case NM_OC_GPRS_NSE:
279 obj = &bts->gprs.nse;
280 break;
281 case NM_OC_GPRS_CELL:
282 obj = &bts->gprs.cell;
283 break;
284 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100285 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200286 return NULL;
287 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
288 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000289 }
290 return obj;
291}
292
293/* Update the administrative state of a given object in our in-memory data
294 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200295static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
296 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000297{
Harald Welteaeedeb42009-05-01 13:08:14 +0000298 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100299 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000300
Harald Welteaf9b8102011-03-06 21:20:38 +0100301 memset(&nsd, 0, sizeof(nsd));
302
Harald Weltef338a032011-01-14 15:55:42 +0100303 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
304 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100305 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000306 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
307 if (!nm_state)
308 return -1;
309
310 new_state = *nm_state;
311 new_state.administrative = adm_state;
312
Harald Weltef38ca9a2011-03-06 22:11:32 +0100313 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100314 nsd.obj_class = obj_class;
315 nsd.old_state = nm_state;
316 nsd.new_state = &new_state;
317 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200318 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000319
320 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000321
Harald Weltef338a032011-01-14 15:55:42 +0100322 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000323}
324
Harald Welte97ed1e72009-02-06 13:38:02 +0000325static int abis_nm_rx_statechg_rep(struct msgb *mb)
326{
Harald Weltee0590df2009-02-15 03:34:15 +0000327 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000328 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000329 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000330 struct tlv_parsed tp;
331 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000332
Harald Welte23897662009-05-01 14:52:51 +0000333 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000334
Harald Welte8b697c72009-06-05 19:18:45 +0000335 memset(&new_state, 0, sizeof(new_state));
336
Harald Weltee0590df2009-02-15 03:34:15 +0000337 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
338 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100339 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000340 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000341 }
Harald Weltee0590df2009-02-15 03:34:15 +0000342
343 new_state = *nm_state;
344
Harald Welte39315c42010-01-10 18:01:52 +0100345 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000346 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
347 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200348 DEBUGPC(DNM, "OP_STATE=%s ",
349 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000350 }
351 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000352 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
353 new_state.availability = 0xff;
354 else
355 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200356 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
357 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000358 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100359 } else
360 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000361 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
362 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200363 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200364 get_value_string(abis_nm_adm_state_names,
365 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000366 }
367 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000368
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100369 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
370 new_state.operational != nm_state->operational ||
371 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000372 /* Update the operational state of a given object in our in-memory data
373 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100374 struct nm_statechg_signal_data nsd;
375 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
376 nsd.obj_class = foh->obj_class;
377 nsd.old_state = nm_state;
378 nsd.new_state = &new_state;
379 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100380 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200381 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100382 nm_state->operational = new_state.operational;
383 nm_state->availability = new_state.availability;
384 if (nm_state->administrative == 0)
385 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000386 }
387#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000388 if (op_state == 1) {
389 /* try to enable objects that are disabled */
390 abis_nm_opstart(bts, foh->obj_class,
391 foh->obj_inst.bts_nr,
392 foh->obj_inst.trx_nr,
393 foh->obj_inst.ts_nr);
394 }
Harald Weltee0590df2009-02-15 03:34:15 +0000395#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000396 return 0;
397}
398
Harald Welte0db97b22009-05-01 17:22:47 +0000399static int rx_fail_evt_rep(struct msgb *mb)
400{
401 struct abis_om_hdr *oh = msgb_l2(mb);
402 struct abis_om_fom_hdr *foh = msgb_l3(mb);
403 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100404 const uint8_t *p_val;
405 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000406
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200407 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000408
Harald Welte39315c42010-01-10 18:01:52 +0100409 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000410
411 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200412 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
413 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000414 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200415 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
416 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100417 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
418 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200419 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 +0100420 }
421 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
422 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
423 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
424 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200425 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100426 talloc_free(p_text);
427 }
428 }
Harald Welte0db97b22009-05-01 17:22:47 +0000429
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200430 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000431
432 return 0;
433}
434
Harald Welte97ed1e72009-02-06 13:38:02 +0000435static int abis_nm_rcvmsg_report(struct msgb *mb)
436{
437 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200438 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000439
Harald Welte15c61722011-05-22 22:45:37 +0200440 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000441
Harald Welte97ed1e72009-02-06 13:38:02 +0000442 //nmh->cfg->report_cb(mb, foh);
443
444 switch (mt) {
445 case NM_MT_STATECHG_EVENT_REP:
446 return abis_nm_rx_statechg_rep(mb);
447 break;
Harald Welte34a99682009-02-13 02:41:40 +0000448 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000449 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200450 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000451 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000452 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000453 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200454 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000455 break;
Harald Weltec7310382009-08-08 00:02:36 +0200456 case NM_MT_TEST_REP:
457 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200458 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200459 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000460 default:
Harald Welte23897662009-05-01 14:52:51 +0000461 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000462 break;
463
Harald Welte97ed1e72009-02-06 13:38:02 +0000464 };
465
Harald Welte97ed1e72009-02-06 13:38:02 +0000466 return 0;
467}
468
Harald Welte34a99682009-02-13 02:41:40 +0000469/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200470static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
471 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000472{
473 struct abis_om_hdr *oh;
474 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200475 uint8_t len = swdesc_len;
476 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000477
478 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
479 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
480
481 trailer = msgb_put(msg, swdesc_len);
482 memcpy(trailer, sw_desc, swdesc_len);
483
484 return abis_nm_sendmsg(bts, msg);
485}
486
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200487static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100488{
489 static const struct tlv_definition sw_descr_def = {
490 .def = {
491 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
492 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
493 },
494 };
495
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200496 uint8_t tag;
497 uint16_t tag_len;
498 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100499 int ofs = 0, len;
500
501 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
502 * nested nature and the fact you have to assume it contains only two sub
503 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
504
505 if (sw_descr[0] != NM_ATT_SW_DESCR) {
506 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
507 return -1;
508 }
509 ofs += 1;
510
511 len = tlv_parse_one(&tag, &tag_len, &val,
512 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
513 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
514 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
515 return -2;
516 }
517 ofs += len;
518
519 len = tlv_parse_one(&tag, &tag_len, &val,
520 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
521 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
522 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
523 return -3;
524 }
525 ofs += len;
526
527 return ofs;
528}
529
Harald Welte34a99682009-02-13 02:41:40 +0000530static int abis_nm_rx_sw_act_req(struct msgb *mb)
531{
532 struct abis_om_hdr *oh = msgb_l2(mb);
533 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200534 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200535 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100536 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000537
Harald Welte15c61722011-05-22 22:45:37 +0200538 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200539
540 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000541
Harald Welte97a282b2010-03-14 15:37:43 +0800542 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000543
544 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000545 foh->obj_inst.bts_nr,
546 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800547 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000548 foh->data, oh->length-sizeof(*foh));
549
Harald Welte39315c42010-01-10 18:01:52 +0100550 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200551 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
552 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
553 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
554 DEBUGP(DNM, "SW config not found! Can't continue.\n");
555 return -EINVAL;
556 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200557 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200558 }
559
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100560 /* Use the first SW_DESCR present in SW config */
561 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
562 if (sw_descr_len < 0)
563 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200564
Harald Welte34a99682009-02-13 02:41:40 +0000565 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
566 foh->obj_inst.bts_nr,
567 foh->obj_inst.trx_nr,
568 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100569 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000570}
571
Harald Weltee0590df2009-02-15 03:34:15 +0000572/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
573static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
574{
575 struct abis_om_hdr *oh = msgb_l2(mb);
576 struct abis_om_fom_hdr *foh = msgb_l3(mb);
577 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200578 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000579
Harald Welte39315c42010-01-10 18:01:52 +0100580 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000581 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
582 return -EINVAL;
583
584 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
585
586 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
587}
588
Harald Welteee670472009-02-22 21:58:49 +0000589static int abis_nm_rx_lmt_event(struct msgb *mb)
590{
591 struct abis_om_hdr *oh = msgb_l2(mb);
592 struct abis_om_fom_hdr *foh = msgb_l3(mb);
593 struct tlv_parsed tp;
594
595 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100596 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000597 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
598 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200599 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000600 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
601 }
602 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
603 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200604 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000605 DEBUGPC(DNM, "Level=%u ", level);
606 }
607 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
608 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
609 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
610 DEBUGPC(DNM, "Username=%s ", name);
611 }
612 DEBUGPC(DNM, "\n");
613 /* FIXME: parse LMT LOGON TIME */
614 return 0;
615}
616
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100617static void abis_nm_queue_send_next(struct gsm_bts *bts)
618{
619 int wait = 0;
620 struct msgb *msg;
621 /* the queue is empty */
622 while (!llist_empty(&bts->abis_queue)) {
623 msg = msgb_dequeue(&bts->abis_queue);
624 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100625 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100626
627 if (wait)
628 break;
629 }
630
631 bts->abis_nm_pend = wait;
632}
633
Harald Welte52b1f982008-12-23 20:25:15 +0000634/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000635static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000636{
Harald Welte6c96ba52009-05-01 13:03:40 +0000637 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000638 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200639 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100640 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000641
642 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000643 if (is_report(mt))
644 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000645
Harald Welte15c61722011-05-22 22:45:37 +0200646 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000647 return abis_nm_rcvmsg_sw(mb);
648
Harald Welte15c61722011-05-22 22:45:37 +0200649 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800650 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000651 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200652
Harald Welte15c61722011-05-22 22:45:37 +0200653 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200654
Harald Welte15c61722011-05-22 22:45:37 +0200655 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000656
Harald Welte39315c42010-01-10 18:01:52 +0100657 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000658 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200659 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200660 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000661 else
662 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200663
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800664 nack_data.msg = mb;
665 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200666 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100667 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200668 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000669 }
Harald Weltead384642008-12-26 10:20:07 +0000670#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000671 /* check if last message is to be acked */
672 if (is_ack_nack(nmh->last_msgtype)) {
673 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100674 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000675 /* we got our ACK, continue sending the next msg */
676 } else if (mt == MT_NACK(nmh->last_msgtype)) {
677 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100678 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000679 /* FIXME: somehow signal this to the caller */
680 } else {
681 /* really strange things happen */
682 return -EINVAL;
683 }
684 }
Harald Weltead384642008-12-26 10:20:07 +0000685#endif
686
Harald Welte97ed1e72009-02-06 13:38:02 +0000687 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000688 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100689 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000690 break;
Harald Welte34a99682009-02-13 02:41:40 +0000691 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100692 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000693 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000694 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100695 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000696 break;
Harald Welte1989c082009-08-06 17:58:31 +0200697 case NM_MT_CONN_MDROP_LINK_ACK:
698 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
699 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100700 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200701 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100702 break;
703 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200704 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100705 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100706 case NM_MT_SET_BTS_ATTR_ACK:
707 /* The HSL wants an OPSTART _after_ the SI has been set */
708 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
709 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
710 }
711 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000712 }
713
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100714 abis_nm_queue_send_next(mb->trx->bts);
715 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000716}
717
Harald Welte677c21f2009-02-17 13:22:23 +0000718static int abis_nm_rx_ipacc(struct msgb *mb);
719
720static int abis_nm_rcvmsg_manuf(struct msgb *mb)
721{
722 int rc;
723 int bts_type = mb->trx->bts->type;
724
725 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100726 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000727 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100728 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000729 break;
730 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100731 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
732 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000733 rc = 0;
734 break;
735 }
736
737 return rc;
738}
739
Harald Welte52b1f982008-12-23 20:25:15 +0000740/* High-Level API */
741/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000742int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000743{
Harald Welte52b1f982008-12-23 20:25:15 +0000744 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000745 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000746
747 /* Various consistency checks */
748 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100749 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000750 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200751 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
752 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000753 }
754 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100755 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000756 oh->sequence);
757 return -EINVAL;
758 }
Harald Welte702d8702008-12-26 20:25:35 +0000759#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200760 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000761 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000762 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100763 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000764 oh->length + sizeof(*oh), l2_len);
765 return -EINVAL;
766 }
Harald Welte702d8702008-12-26 20:25:35 +0000767 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100768 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 +0000769#endif
Harald Weltead384642008-12-26 10:20:07 +0000770 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000771
772 switch (oh->mdisc) {
773 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000774 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000775 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000776 case ABIS_OM_MDISC_MANUF:
777 rc = abis_nm_rcvmsg_manuf(msg);
778 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000779 case ABIS_OM_MDISC_MMI:
780 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100781 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000782 oh->mdisc);
783 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000784 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100785 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000786 oh->mdisc);
787 return -EINVAL;
788 }
789
Harald Weltead384642008-12-26 10:20:07 +0000790 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000791 return rc;
792}
793
794#if 0
795/* initialized all resources */
796struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
797{
798 struct abis_nm_h *nmh;
799
800 nmh = malloc(sizeof(*nmh));
801 if (!nmh)
802 return NULL;
803
804 nmh->cfg = cfg;
805
806 return nmh;
807}
808
809/* free all resources */
810void abis_nm_fini(struct abis_nm_h *nmh)
811{
812 free(nmh);
813}
814#endif
815
816/* Here we are trying to define a high-level API that can be used by
817 * the actual BSC implementation. However, the architecture is currently
818 * still under design. Ideally the calls to this API would be synchronous,
819 * while the underlying stack behind the APi runs in a traditional select
820 * based state machine.
821 */
822
Harald Welte4724f992009-01-18 18:01:49 +0000823/* 6.2 Software Load: */
824enum sw_state {
825 SW_STATE_NONE,
826 SW_STATE_WAIT_INITACK,
827 SW_STATE_WAIT_SEGACK,
828 SW_STATE_WAIT_ENDACK,
829 SW_STATE_WAIT_ACTACK,
830 SW_STATE_ERROR,
831};
Harald Welte52b1f982008-12-23 20:25:15 +0000832
Harald Welte52b1f982008-12-23 20:25:15 +0000833struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000834 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800835 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000836 gsm_cbfn *cbfn;
837 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000838 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000839
Harald Welte52b1f982008-12-23 20:25:15 +0000840 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200841 uint8_t obj_class;
842 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000843
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200844 uint8_t file_id[255];
845 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000846
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200847 uint8_t file_version[255];
848 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000849
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200850 uint8_t window_size;
851 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000852
853 int fd;
854 FILE *stream;
855 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000856 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000857};
858
Harald Welte4724f992009-01-18 18:01:49 +0000859static struct abis_nm_sw g_sw;
860
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100861static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
862{
863 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
864 msgb_v_put(msg, NM_ATT_SW_DESCR);
865 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
866 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
867 sw->file_version);
868 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
869 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
870 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
871 sw->file_version);
872 } else {
873 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
874 }
875}
876
Harald Welte4724f992009-01-18 18:01:49 +0000877/* 6.2.1 / 8.3.1: Load Data Initiate */
878static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000879{
Harald Welte4724f992009-01-18 18:01:49 +0000880 struct abis_om_hdr *oh;
881 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200882 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000883
884 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
885 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
886 sw->obj_instance[0], sw->obj_instance[1],
887 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100888
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100889 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000890 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
891
892 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000893}
894
Harald Welte1602ade2009-01-29 21:12:39 +0000895static int is_last_line(FILE *stream)
896{
897 char next_seg_buf[256];
898 long pos;
899
900 /* check if we're sending the last line */
901 pos = ftell(stream);
902 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
903 fseek(stream, pos, SEEK_SET);
904 return 1;
905 }
906
907 fseek(stream, pos, SEEK_SET);
908 return 0;
909}
910
Harald Welte4724f992009-01-18 18:01:49 +0000911/* 6.2.2 / 8.3.2 Load Data Segment */
912static int sw_load_segment(struct abis_nm_sw *sw)
913{
914 struct abis_om_hdr *oh;
915 struct msgb *msg = nm_msgb_alloc();
916 char seg_buf[256];
917 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000918 unsigned char *tlv;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200919 uint8_t len;
Harald Welte4724f992009-01-18 18:01:49 +0000920
921 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000922
923 switch (sw->bts->type) {
924 case GSM_BTS_TYPE_BS11:
925 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
926 perror("fgets reading segment");
927 return -EINVAL;
928 }
929 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000930
931 /* check if we're sending the last line */
932 sw->last_seg = is_last_line(sw->stream);
933 if (sw->last_seg)
934 seg_buf[1] = 0;
935 else
936 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000937
938 len = strlen(line_buf) + 2;
939 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200940 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000941 /* BS11 wants CR + LF in excess of the TLV length !?! */
942 tlv[1] -= 2;
943
944 /* we only now know the exact length for the OM hdr */
945 len = strlen(line_buf)+2;
946 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100947 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200948 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100949 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
950 if (len < 0) {
951 perror("read failed");
952 return -EINVAL;
953 }
954
955 if (len != IPACC_SEGMENT_SIZE)
956 sw->last_seg = 1;
957
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100958 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200959 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100960 len += 3;
961 break;
962 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000963 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100964 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000965 /* FIXME: Other BTS types */
966 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000967 }
Harald Welte4724f992009-01-18 18:01:49 +0000968
Harald Welte4724f992009-01-18 18:01:49 +0000969 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
970 sw->obj_instance[0], sw->obj_instance[1],
971 sw->obj_instance[2]);
972
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100973 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000974}
975
976/* 6.2.4 / 8.3.4 Load Data End */
977static int sw_load_end(struct abis_nm_sw *sw)
978{
979 struct abis_om_hdr *oh;
980 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200981 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000982
983 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
984 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
985 sw->obj_instance[0], sw->obj_instance[1],
986 sw->obj_instance[2]);
987
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100988 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000989 return abis_nm_sendmsg(sw->bts, msg);
990}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000991
Harald Welte52b1f982008-12-23 20:25:15 +0000992/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000993static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000994{
Harald Welte4724f992009-01-18 18:01:49 +0000995 struct abis_om_hdr *oh;
996 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200997 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000998
Harald Welte4724f992009-01-18 18:01:49 +0000999 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1000 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1001 sw->obj_instance[0], sw->obj_instance[1],
1002 sw->obj_instance[2]);
1003
1004 /* FIXME: this is BS11 specific format */
1005 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1006 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1007 sw->file_version);
1008
1009 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001010}
Harald Welte4724f992009-01-18 18:01:49 +00001011
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001012struct sdp_firmware {
1013 char magic[4];
1014 char more_magic[4];
1015 unsigned int header_length;
1016 unsigned int file_length;
1017} __attribute__ ((packed));
1018
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001019static int parse_sdp_header(struct abis_nm_sw *sw)
1020{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001021 struct sdp_firmware firmware_header;
1022 int rc;
1023 struct stat stat;
1024
1025 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1026 if (rc != sizeof(firmware_header)) {
1027 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1028 return -1;
1029 }
1030
1031 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1032 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1033 return -1;
1034 }
1035
1036 if (firmware_header.more_magic[0] != 0x10 ||
1037 firmware_header.more_magic[1] != 0x02 ||
1038 firmware_header.more_magic[2] != 0x00 ||
1039 firmware_header.more_magic[3] != 0x00) {
1040 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1041 return -1;
1042 }
1043
1044
1045 if (fstat(sw->fd, &stat) == -1) {
1046 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1047 return -1;
1048 }
1049
1050 if (ntohl(firmware_header.file_length) != stat.st_size) {
1051 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1052 return -1;
1053 }
1054
1055 /* go back to the start as we checked the whole filesize.. */
1056 lseek(sw->fd, 0l, SEEK_SET);
1057 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1058 "There might be checksums in the file that are not\n"
1059 "verified and incomplete firmware might be flashed.\n"
1060 "There is absolutely no WARRANTY that flashing will\n"
1061 "work.\n");
1062 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001063}
1064
Harald Welte4724f992009-01-18 18:01:49 +00001065static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1066{
1067 char file_id[12+1];
1068 char file_version[80+1];
1069 int rc;
1070
1071 sw->fd = open(fname, O_RDONLY);
1072 if (sw->fd < 0)
1073 return sw->fd;
1074
1075 switch (sw->bts->type) {
1076 case GSM_BTS_TYPE_BS11:
1077 sw->stream = fdopen(sw->fd, "r");
1078 if (!sw->stream) {
1079 perror("fdopen");
1080 return -1;
1081 }
1082 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001083 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001084 file_id, file_version);
1085 if (rc != 2) {
1086 perror("parsing header line of software file");
1087 return -1;
1088 }
1089 strcpy((char *)sw->file_id, file_id);
1090 sw->file_id_len = strlen(file_id);
1091 strcpy((char *)sw->file_version, file_version);
1092 sw->file_version_len = strlen(file_version);
1093 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001094 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001095 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001096 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001097 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001098 rc = parse_sdp_header(sw);
1099 if (rc < 0) {
1100 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1101 return -1;
1102 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001103
1104 strcpy((char *)sw->file_id, "id");
1105 sw->file_id_len = 3;
1106 strcpy((char *)sw->file_version, "version");
1107 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001108 break;
Harald Welte4724f992009-01-18 18:01:49 +00001109 default:
1110 /* We don't know how to treat them yet */
1111 close(sw->fd);
1112 return -EINVAL;
1113 }
1114
1115 return 0;
1116}
1117
1118static void sw_close_file(struct abis_nm_sw *sw)
1119{
1120 switch (sw->bts->type) {
1121 case GSM_BTS_TYPE_BS11:
1122 fclose(sw->stream);
1123 break;
1124 default:
1125 close(sw->fd);
1126 break;
1127 }
1128}
1129
1130/* Fill the window */
1131static int sw_fill_window(struct abis_nm_sw *sw)
1132{
1133 int rc;
1134
1135 while (sw->seg_in_window < sw->window_size) {
1136 rc = sw_load_segment(sw);
1137 if (rc < 0)
1138 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001139 if (sw->last_seg)
1140 break;
Harald Welte4724f992009-01-18 18:01:49 +00001141 }
1142 return 0;
1143}
1144
1145/* callback function from abis_nm_rcvmsg() handler */
1146static int abis_nm_rcvmsg_sw(struct msgb *mb)
1147{
1148 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1149 int rc = -1;
1150 struct abis_nm_sw *sw = &g_sw;
1151 enum sw_state old_state = sw->state;
1152
Harald Welte3ffd1372009-02-01 22:15:49 +00001153 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001154
1155 switch (sw->state) {
1156 case SW_STATE_WAIT_INITACK:
1157 switch (foh->msg_type) {
1158 case NM_MT_LOAD_INIT_ACK:
1159 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001160 if (sw->cbfn)
1161 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1162 NM_MT_LOAD_INIT_ACK, mb,
1163 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001164 rc = sw_fill_window(sw);
1165 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001166 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001167 break;
1168 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001169 if (sw->forced) {
1170 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1171 "Init NACK\n");
1172 if (sw->cbfn)
1173 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1174 NM_MT_LOAD_INIT_ACK, mb,
1175 sw->cb_data, NULL);
1176 rc = sw_fill_window(sw);
1177 sw->state = SW_STATE_WAIT_SEGACK;
1178 } else {
1179 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001180 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001181 if (sw->cbfn)
1182 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1183 NM_MT_LOAD_INIT_NACK, mb,
1184 sw->cb_data, NULL);
1185 sw->state = SW_STATE_ERROR;
1186 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001187 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001188 break;
1189 }
1190 break;
1191 case SW_STATE_WAIT_SEGACK:
1192 switch (foh->msg_type) {
1193 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001194 if (sw->cbfn)
1195 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1196 NM_MT_LOAD_SEG_ACK, mb,
1197 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001198 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001199 if (!sw->last_seg) {
1200 /* fill window with more segments */
1201 rc = sw_fill_window(sw);
1202 sw->state = SW_STATE_WAIT_SEGACK;
1203 } else {
1204 /* end the transfer */
1205 sw->state = SW_STATE_WAIT_ENDACK;
1206 rc = sw_load_end(sw);
1207 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001208 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001209 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001210 case NM_MT_LOAD_ABORT:
1211 if (sw->cbfn)
1212 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1213 NM_MT_LOAD_ABORT, mb,
1214 sw->cb_data, NULL);
1215 break;
Harald Welte4724f992009-01-18 18:01:49 +00001216 }
1217 break;
1218 case SW_STATE_WAIT_ENDACK:
1219 switch (foh->msg_type) {
1220 case NM_MT_LOAD_END_ACK:
1221 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001222 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1223 sw->bts->nr);
1224 sw->state = SW_STATE_NONE;
1225 if (sw->cbfn)
1226 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1227 NM_MT_LOAD_END_ACK, mb,
1228 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001229 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001230 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001231 break;
1232 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001233 if (sw->forced) {
1234 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1235 "End NACK\n");
1236 sw->state = SW_STATE_NONE;
1237 if (sw->cbfn)
1238 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1239 NM_MT_LOAD_END_ACK, mb,
1240 sw->cb_data, NULL);
1241 } else {
1242 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001243 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001244 sw->state = SW_STATE_ERROR;
1245 if (sw->cbfn)
1246 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1247 NM_MT_LOAD_END_NACK, mb,
1248 sw->cb_data, NULL);
1249 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001250 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001251 break;
1252 }
1253 case SW_STATE_WAIT_ACTACK:
1254 switch (foh->msg_type) {
1255 case NM_MT_ACTIVATE_SW_ACK:
1256 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001257 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001258 sw->state = SW_STATE_NONE;
1259 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001260 if (sw->cbfn)
1261 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1262 NM_MT_ACTIVATE_SW_ACK, mb,
1263 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001264 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001265 break;
1266 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001267 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001268 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001269 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001270 if (sw->cbfn)
1271 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1272 NM_MT_ACTIVATE_SW_NACK, mb,
1273 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001274 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001275 break;
1276 }
1277 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001278 switch (foh->msg_type) {
1279 case NM_MT_ACTIVATE_SW_ACK:
1280 rc = 0;
1281 break;
1282 }
1283 break;
Harald Welte4724f992009-01-18 18:01:49 +00001284 case SW_STATE_ERROR:
1285 break;
1286 }
1287
1288 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001289 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001290 foh->msg_type, old_state, sw->state);
1291
1292 return rc;
1293}
1294
1295/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001296int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001297 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001298 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001299{
1300 struct abis_nm_sw *sw = &g_sw;
1301 int rc;
1302
Harald Welte5e4d1b32009-02-01 13:36:56 +00001303 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1304 bts->nr, fname);
1305
Harald Welte4724f992009-01-18 18:01:49 +00001306 if (sw->state != SW_STATE_NONE)
1307 return -EBUSY;
1308
1309 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001310 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001311
1312 switch (bts->type) {
1313 case GSM_BTS_TYPE_BS11:
1314 sw->obj_class = NM_OC_SITE_MANAGER;
1315 sw->obj_instance[0] = 0xff;
1316 sw->obj_instance[1] = 0xff;
1317 sw->obj_instance[2] = 0xff;
1318 break;
1319 case GSM_BTS_TYPE_NANOBTS:
1320 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001321 sw->obj_instance[0] = sw->bts->nr;
1322 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001323 sw->obj_instance[2] = 0xff;
1324 break;
1325 case GSM_BTS_TYPE_UNKNOWN:
1326 default:
1327 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1328 return -1;
1329 break;
1330 }
Harald Welte4724f992009-01-18 18:01:49 +00001331 sw->window_size = win_size;
1332 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001333 sw->cbfn = cbfn;
1334 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001335 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001336
1337 rc = sw_open_file(sw, fname);
1338 if (rc < 0) {
1339 sw->state = SW_STATE_NONE;
1340 return rc;
1341 }
1342
1343 return sw_load_init(sw);
1344}
Harald Welte52b1f982008-12-23 20:25:15 +00001345
Harald Welte1602ade2009-01-29 21:12:39 +00001346int abis_nm_software_load_status(struct gsm_bts *bts)
1347{
1348 struct abis_nm_sw *sw = &g_sw;
1349 struct stat st;
1350 int rc, percent;
1351
1352 rc = fstat(sw->fd, &st);
1353 if (rc < 0) {
1354 perror("ERROR during stat");
1355 return rc;
1356 }
1357
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001358 if (sw->stream)
1359 percent = (ftell(sw->stream) * 100) / st.st_size;
1360 else
1361 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001362 return percent;
1363}
1364
Harald Welte5e4d1b32009-02-01 13:36:56 +00001365/* Activate the specified software into the BTS */
1366int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1367 gsm_cbfn *cbfn, void *cb_data)
1368{
1369 struct abis_nm_sw *sw = &g_sw;
1370 int rc;
1371
1372 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1373 bts->nr, fname);
1374
1375 if (sw->state != SW_STATE_NONE)
1376 return -EBUSY;
1377
1378 sw->bts = bts;
1379 sw->obj_class = NM_OC_SITE_MANAGER;
1380 sw->obj_instance[0] = 0xff;
1381 sw->obj_instance[1] = 0xff;
1382 sw->obj_instance[2] = 0xff;
1383 sw->state = SW_STATE_WAIT_ACTACK;
1384 sw->cbfn = cbfn;
1385 sw->cb_data = cb_data;
1386
1387 /* Open the file in order to fill some sw struct members */
1388 rc = sw_open_file(sw, fname);
1389 if (rc < 0) {
1390 sw->state = SW_STATE_NONE;
1391 return rc;
1392 }
1393 sw_close_file(sw);
1394
1395 return sw_activate(sw);
1396}
1397
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001398static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1399 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001400{
Harald Welteadaf08b2009-01-18 11:08:10 +00001401 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001402 ch->bts_port = bts_port;
1403 ch->timeslot = ts_nr;
1404 ch->subslot = subslot_nr;
1405}
1406
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001407int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1408 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1409 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001410{
1411 struct abis_om_hdr *oh;
1412 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001413 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001414 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001415
1416 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1417 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1418 bts->bts_nr, trx_nr, 0xff);
1419
Harald Welte8470bf22008-12-25 23:28:35 +00001420 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001421
1422 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1423 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1424
1425 return abis_nm_sendmsg(bts, msg);
1426}
1427
1428/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1429int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001430 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001431{
Harald Welte8470bf22008-12-25 23:28:35 +00001432 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001433 struct abis_om_hdr *oh;
1434 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001435 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001436
1437 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001438 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001439 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1440
1441 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1442 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1443
1444 return abis_nm_sendmsg(bts, msg);
1445}
1446
1447#if 0
1448int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1449 struct abis_nm_abis_channel *chan)
1450{
1451}
1452#endif
1453
1454int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001455 uint8_t e1_port, uint8_t e1_timeslot,
1456 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001457{
1458 struct gsm_bts *bts = ts->trx->bts;
1459 struct abis_om_hdr *oh;
1460 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001461 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001462
1463 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1464 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001465 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001466
1467 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1468 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1469
Harald Weltef325eb42009-02-19 17:07:39 +00001470 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1471 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001472 e1_port, e1_timeslot, e1_subslot);
1473
Harald Welte52b1f982008-12-23 20:25:15 +00001474 return abis_nm_sendmsg(bts, msg);
1475}
1476
1477#if 0
1478int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1479 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001480 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001481{
1482}
1483#endif
1484
Harald Welte22af0db2009-02-14 15:41:08 +00001485/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001486int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001487{
1488 struct abis_om_hdr *oh;
1489 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001490 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001491
1492 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1493
1494 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001495 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 +00001496 cur = msgb_put(msg, attr_len);
1497 memcpy(cur, attr, attr_len);
1498
1499 return abis_nm_sendmsg(bts, msg);
1500}
1501
1502/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001503int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001504{
1505 struct abis_om_hdr *oh;
1506 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001507 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001508
1509 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1510
1511 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1512 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001513 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001514 cur = msgb_put(msg, attr_len);
1515 memcpy(cur, attr, attr_len);
1516
1517 return abis_nm_sendmsg(trx->bts, msg);
1518}
1519
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001520static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001521{
1522 int i;
1523
1524 /* As it turns out, the BS-11 has some very peculiar restrictions
1525 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301526 switch (ts->trx->bts->type) {
1527 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001528 switch (chan_comb) {
1529 case NM_CHANC_TCHHalf:
1530 case NM_CHANC_TCHHalf2:
1531 /* not supported */
1532 return -EINVAL;
1533 case NM_CHANC_SDCCH:
1534 /* only one SDCCH/8 per TRX */
1535 for (i = 0; i < TRX_NR_TS; i++) {
1536 if (i == ts->nr)
1537 continue;
1538 if (ts->trx->ts[i].nm_chan_comb ==
1539 NM_CHANC_SDCCH)
1540 return -EINVAL;
1541 }
1542 /* not allowed for TS0 of BCCH-TRX */
1543 if (ts->trx == ts->trx->bts->c0 &&
1544 ts->nr == 0)
1545 return -EINVAL;
1546 /* not on the same TRX that has a BCCH+SDCCH4
1547 * combination */
1548 if (ts->trx == ts->trx->bts->c0 &&
1549 (ts->trx->ts[0].nm_chan_comb == 5 ||
1550 ts->trx->ts[0].nm_chan_comb == 8))
1551 return -EINVAL;
1552 break;
1553 case NM_CHANC_mainBCCH:
1554 case NM_CHANC_BCCHComb:
1555 /* allowed only for TS0 of C0 */
1556 if (ts->trx != ts->trx->bts->c0 ||
1557 ts->nr != 0)
1558 return -EINVAL;
1559 break;
1560 case NM_CHANC_BCCH:
1561 /* allowed only for TS 2/4/6 of C0 */
1562 if (ts->trx != ts->trx->bts->c0)
1563 return -EINVAL;
1564 if (ts->nr != 2 && ts->nr != 4 &&
1565 ts->nr != 6)
1566 return -EINVAL;
1567 break;
1568 case 8: /* this is not like 08.58, but in fact
1569 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1570 /* FIXME: only one CBCH allowed per cell */
1571 break;
1572 }
Harald Welted6575f92009-12-02 02:45:23 +05301573 break;
1574 case GSM_BTS_TYPE_NANOBTS:
1575 switch (ts->nr) {
1576 case 0:
1577 if (ts->trx->nr == 0) {
1578 /* only on TRX0 */
1579 switch (chan_comb) {
1580 case NM_CHANC_BCCH:
1581 case NM_CHANC_mainBCCH:
1582 case NM_CHANC_BCCHComb:
1583 return 0;
1584 break;
1585 default:
1586 return -EINVAL;
1587 }
1588 } else {
1589 switch (chan_comb) {
1590 case NM_CHANC_TCHFull:
1591 case NM_CHANC_TCHHalf:
1592 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1593 return 0;
1594 default:
1595 return -EINVAL;
1596 }
1597 }
1598 break;
1599 case 1:
1600 if (ts->trx->nr == 0) {
1601 switch (chan_comb) {
1602 case NM_CHANC_SDCCH_CBCH:
1603 if (ts->trx->ts[0].nm_chan_comb ==
1604 NM_CHANC_mainBCCH)
1605 return 0;
1606 return -EINVAL;
1607 case NM_CHANC_SDCCH:
1608 case NM_CHANC_TCHFull:
1609 case NM_CHANC_TCHHalf:
1610 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1611 case NM_CHANC_IPAC_TCHFull_PDCH:
1612 return 0;
1613 }
1614 } else {
1615 switch (chan_comb) {
1616 case NM_CHANC_SDCCH:
1617 case NM_CHANC_TCHFull:
1618 case NM_CHANC_TCHHalf:
1619 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1620 return 0;
1621 default:
1622 return -EINVAL;
1623 }
1624 }
1625 break;
1626 case 2:
1627 case 3:
1628 case 4:
1629 case 5:
1630 case 6:
1631 case 7:
1632 switch (chan_comb) {
1633 case NM_CHANC_TCHFull:
1634 case NM_CHANC_TCHHalf:
1635 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1636 return 0;
1637 case NM_CHANC_IPAC_PDCH:
1638 case NM_CHANC_IPAC_TCHFull_PDCH:
1639 if (ts->trx->nr == 0)
1640 return 0;
1641 else
1642 return -EINVAL;
1643 }
1644 break;
1645 }
1646 return -EINVAL;
1647 default:
1648 /* unknown BTS type */
1649 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001650 }
1651 return 0;
1652}
1653
Harald Welte22af0db2009-02-14 15:41:08 +00001654/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001655int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001656{
1657 struct gsm_bts *bts = ts->trx->bts;
1658 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001659 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001660 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001661 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00001662
1663 if (bts->type == GSM_BTS_TYPE_BS11)
1664 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001665
Harald Weltef325eb42009-02-19 17:07:39 +00001666 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001667 if (verify_chan_comb(ts, chan_comb) < 0) {
1668 msgb_free(msg);
1669 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1670 return -EINVAL;
1671 }
1672 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001673
Harald Welte52b1f982008-12-23 20:25:15 +00001674 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001675 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001676 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001677 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001678 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001679 if (ts->hopping.enabled) {
1680 unsigned int i;
1681 uint8_t *len;
1682
Harald Welte6e0cd042009-09-12 13:05:33 +02001683 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1684 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001685
1686 /* build the ARFCN list */
1687 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1688 len = msgb_put(msg, 1);
1689 *len = 0;
1690 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1691 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1692 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001693 /* At least BS-11 wants a TLV16 here */
1694 if (bts->type == GSM_BTS_TYPE_BS11)
1695 *len += 1;
1696 else
1697 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001698 }
1699 }
Harald Weltee0590df2009-02-15 03:34:15 +00001700 }
Harald Weltee6c22d92009-07-21 20:40:05 +02001701 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001702 if (bts->type == GSM_BTS_TYPE_BS11)
1703 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001704
1705 return abis_nm_sendmsg(bts, msg);
1706}
1707
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001708int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1709 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001710{
1711 struct abis_om_hdr *oh;
1712 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001713 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1714 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001715
1716 if (nack) {
1717 len += 2;
1718 msgtype = NM_MT_SW_ACT_REQ_NACK;
1719 }
Harald Welte34a99682009-02-13 02:41:40 +00001720
1721 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001722 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1723
Harald Welte34a99682009-02-13 02:41:40 +00001724 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001725 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001726 memcpy(ptr, attr, att_len);
1727 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001728 if (nack)
1729 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001730
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001731 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001732}
1733
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001734int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001735{
Harald Welte8470bf22008-12-25 23:28:35 +00001736 struct msgb *msg = nm_msgb_alloc();
1737 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001738 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001739
1740 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1741 fill_om_hdr(oh, len);
1742 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001743 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001744
1745 return abis_nm_sendmsg(bts, msg);
1746}
1747
1748/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001749static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001750{
1751 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001752 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001753
1754 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001755 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001756 0xff, 0xff, 0xff);
1757
1758 return abis_nm_sendmsg(bts, msg);
1759}
1760
Harald Welte34a99682009-02-13 02:41:40 +00001761/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001762int 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 +00001763{
1764 struct abis_om_hdr *oh;
1765 struct msgb *msg = nm_msgb_alloc();
1766
1767 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1768 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1769
Harald Welte15c61722011-05-22 22:45:37 +02001770 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001771 DEBUGPC(DNM, "Sending OPSTART\n");
1772
Harald Welte34a99682009-02-13 02:41:40 +00001773 return abis_nm_sendmsg(bts, msg);
1774}
1775
1776/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001777int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1778 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001779{
1780 struct abis_om_hdr *oh;
1781 struct msgb *msg = nm_msgb_alloc();
1782
1783 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1784 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1785 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1786
1787 return abis_nm_sendmsg(bts, msg);
1788}
1789
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001790int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1791 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001792{
1793 struct abis_om_hdr *oh;
1794 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001795 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001796
1797 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1798 e1_port0, ts0, e1_port1, ts1);
1799
1800 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1801 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1802 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1803
1804 attr = msgb_put(msg, 3);
1805 attr[0] = NM_ATT_MDROP_LINK;
1806 attr[1] = e1_port0;
1807 attr[2] = ts0;
1808
1809 attr = msgb_put(msg, 3);
1810 attr[0] = NM_ATT_MDROP_NEXT;
1811 attr[1] = e1_port1;
1812 attr[2] = ts1;
1813
1814 return abis_nm_sendmsg(bts, msg);
1815}
Harald Welte34a99682009-02-13 02:41:40 +00001816
Harald Weltec7310382009-08-08 00:02:36 +02001817/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001818int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1819 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1820 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001821{
1822 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001823
Harald Welte15c61722011-05-22 22:45:37 +02001824 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001825
1826 if (!msg)
1827 msg = nm_msgb_alloc();
1828
1829 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1830 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1831 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1832 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001833 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001834
1835 return abis_nm_sendmsg(bts, msg);
1836}
1837
Harald Welte52b1f982008-12-23 20:25:15 +00001838int abis_nm_event_reports(struct gsm_bts *bts, int on)
1839{
1840 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001841 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001842 else
Harald Welte227d4072009-01-03 08:16:25 +00001843 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001844}
1845
Harald Welte47d88ae2009-01-04 12:02:08 +00001846/* Siemens (or BS-11) specific commands */
1847
Harald Welte3ffd1372009-02-01 22:15:49 +00001848int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1849{
1850 if (reconnect == 0)
1851 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1852 else
1853 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1854}
1855
Harald Welteb8427972009-02-05 19:27:17 +00001856int abis_nm_bs11_restart(struct gsm_bts *bts)
1857{
1858 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1859}
1860
1861
Harald Welte268bb402009-02-01 19:11:56 +00001862struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001863 uint16_t year;
1864 uint8_t month;
1865 uint8_t day;
1866 uint8_t hour;
1867 uint8_t min;
1868 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001869} __attribute__((packed));
1870
1871
1872void get_bs11_date_time(struct bs11_date_time *aet)
1873{
1874 time_t t;
1875 struct tm *tm;
1876
1877 t = time(NULL);
1878 tm = localtime(&t);
1879 aet->sec = tm->tm_sec;
1880 aet->min = tm->tm_min;
1881 aet->hour = tm->tm_hour;
1882 aet->day = tm->tm_mday;
1883 aet->month = tm->tm_mon;
1884 aet->year = htons(1900 + tm->tm_year);
1885}
1886
Harald Welte05188ee2009-01-18 11:39:08 +00001887int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001888{
Harald Welte4668fda2009-01-03 08:19:29 +00001889 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001890}
1891
Harald Welte05188ee2009-01-18 11:39:08 +00001892int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001893{
1894 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001895 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001896 else
Harald Welte4668fda2009-01-03 08:19:29 +00001897 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001898}
Harald Welte47d88ae2009-01-04 12:02:08 +00001899
Harald Welte05188ee2009-01-18 11:39:08 +00001900int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001901 enum abis_bs11_objtype type, uint8_t idx,
1902 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001903{
1904 struct abis_om_hdr *oh;
1905 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001906 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001907
1908 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001909 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001910 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001911 cur = msgb_put(msg, attr_len);
1912 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001913
1914 return abis_nm_sendmsg(bts, msg);
1915}
1916
Harald Welte78fc0d42009-02-19 02:50:57 +00001917int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001918 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001919{
1920 struct abis_om_hdr *oh;
1921 struct msgb *msg = nm_msgb_alloc();
1922
1923 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1924 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1925 NM_OC_BS11, type, 0, idx);
1926
1927 return abis_nm_sendmsg(bts, msg);
1928}
1929
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001930int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001931{
1932 struct abis_om_hdr *oh;
1933 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001934 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001935
1936 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001937 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001938 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1939 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001940
1941 return abis_nm_sendmsg(bts, msg);
1942}
1943
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001944int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001945{
1946 struct abis_om_hdr *oh;
1947 struct msgb *msg = nm_msgb_alloc();
1948
1949 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1950 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001951 idx, 0xff, 0xff);
1952
1953 return abis_nm_sendmsg(bts, msg);
1954}
1955
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001956int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001957{
1958 struct abis_om_hdr *oh;
1959 struct msgb *msg = nm_msgb_alloc();
1960
1961 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1962 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1963 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001964
1965 return abis_nm_sendmsg(bts, msg);
1966}
Harald Welte05188ee2009-01-18 11:39:08 +00001967
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001968static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001969int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1970{
1971 struct abis_om_hdr *oh;
1972 struct msgb *msg = nm_msgb_alloc();
1973
1974 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1975 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1976 0xff, 0xff, 0xff);
1977 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1978
1979 return abis_nm_sendmsg(bts, msg);
1980}
1981
Harald Welteb6c92ae2009-02-21 20:15:32 +00001982/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001983int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1984 uint8_t e1_timeslot, uint8_t e1_subslot,
1985 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00001986{
1987 struct abis_om_hdr *oh;
1988 struct abis_nm_channel *ch;
1989 struct msgb *msg = nm_msgb_alloc();
1990
1991 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001992 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00001993 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1994
1995 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1996 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00001997 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00001998
1999 return abis_nm_sendmsg(bts, msg);
2000}
2001
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002002int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002003{
2004 struct abis_om_hdr *oh;
2005 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002006
2007 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002008 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002009 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2010 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2011
2012 return abis_nm_sendmsg(trx->bts, msg);
2013}
2014
Harald Welte78fc0d42009-02-19 02:50:57 +00002015int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2016{
2017 struct abis_om_hdr *oh;
2018 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002019 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002020
2021 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2022 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2023 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2024 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2025
2026 return abis_nm_sendmsg(trx->bts, msg);
2027}
2028
Harald Welteaaf02d92009-04-29 13:25:57 +00002029int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2030{
2031 struct abis_om_hdr *oh;
2032 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002033 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002034
2035 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2036 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2037 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002038 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002039
2040 return abis_nm_sendmsg(bts, msg);
2041}
2042
Harald Welteef061952009-05-17 12:43:42 +00002043int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2044{
2045 struct abis_om_hdr *oh;
2046 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002047 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002048 NM_ATT_BS11_CCLK_TYPE };
2049
2050 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2051 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2052 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2053 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2054
2055 return abis_nm_sendmsg(bts, msg);
2056
2057}
Harald Welteaaf02d92009-04-29 13:25:57 +00002058
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002059//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002060
Harald Welte1bc09062009-01-18 14:17:52 +00002061int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002062{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002063 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2064}
2065
Daniel Willmann4b054c82010-01-07 00:46:26 +01002066int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2067{
2068 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2069}
2070
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002071int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002072{
Harald Welte05188ee2009-01-18 11:39:08 +00002073 struct abis_om_hdr *oh;
2074 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002075 struct bs11_date_time bdt;
2076
2077 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002078
2079 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002080 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002081 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002082 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002083 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002084 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002085 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002086 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002087 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002088 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002089 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002090 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002091 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002092 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002093 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002094 }
Harald Welte05188ee2009-01-18 11:39:08 +00002095
2096 return abis_nm_sendmsg(bts, msg);
2097}
Harald Welte1bc09062009-01-18 14:17:52 +00002098
2099int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2100{
2101 struct abis_om_hdr *oh;
2102 struct msgb *msg;
2103
2104 if (strlen(password) != 10)
2105 return -EINVAL;
2106
2107 msg = nm_msgb_alloc();
2108 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002109 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002110 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002111 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002112
2113 return abis_nm_sendmsg(bts, msg);
2114}
2115
Harald Weltee69f5fb2009-04-28 16:31:38 +00002116/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2117int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2118{
2119 struct abis_om_hdr *oh;
2120 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002121 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002122
2123 msg = nm_msgb_alloc();
2124 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2125 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2126 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002127
2128 if (locked)
2129 tlv_value = BS11_LI_PLL_LOCKED;
2130 else
2131 tlv_value = BS11_LI_PLL_STANDALONE;
2132
2133 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002134
2135 return abis_nm_sendmsg(bts, msg);
2136}
2137
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002138/* Set the calibration value of the PLL (work value/set value)
2139 * It depends on the login which one is changed */
2140int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2141{
2142 struct abis_om_hdr *oh;
2143 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002144 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002145
2146 msg = nm_msgb_alloc();
2147 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2148 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2149 BS11_OBJ_TRX1, 0x00, 0x00);
2150
2151 tlv_value[0] = value>>8;
2152 tlv_value[1] = value&0xff;
2153
2154 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2155
2156 return abis_nm_sendmsg(bts, msg);
2157}
2158
Harald Welte1bc09062009-01-18 14:17:52 +00002159int abis_nm_bs11_get_state(struct gsm_bts *bts)
2160{
2161 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2162}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002163
2164/* BS11 SWL */
2165
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002166void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002167
Harald Welte5e4d1b32009-02-01 13:36:56 +00002168struct abis_nm_bs11_sw {
2169 struct gsm_bts *bts;
2170 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002171 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002172 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002173 struct llist_head file_list;
2174 gsm_cbfn *user_cb; /* specified by the user */
2175};
2176static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2177
2178struct file_list_entry {
2179 struct llist_head list;
2180 char fname[PATH_MAX];
2181};
2182
2183struct file_list_entry *fl_dequeue(struct llist_head *queue)
2184{
2185 struct llist_head *lh;
2186
2187 if (llist_empty(queue))
2188 return NULL;
2189
2190 lh = queue->next;
2191 llist_del(lh);
2192
2193 return llist_entry(lh, struct file_list_entry, list);
2194}
2195
2196static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2197{
2198 char linebuf[255];
2199 struct llist_head *lh, *lh2;
2200 FILE *swl;
2201 int rc = 0;
2202
2203 swl = fopen(bs11_sw->swl_fname, "r");
2204 if (!swl)
2205 return -ENODEV;
2206
2207 /* zero the stale file list, if any */
2208 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2209 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002210 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002211 }
2212
2213 while (fgets(linebuf, sizeof(linebuf), swl)) {
2214 char file_id[12+1];
2215 char file_version[80+1];
2216 struct file_list_entry *fle;
2217 static char dir[PATH_MAX];
2218
2219 if (strlen(linebuf) < 4)
2220 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002221
Harald Welte5e4d1b32009-02-01 13:36:56 +00002222 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2223 if (rc < 0) {
2224 perror("ERR parsing SWL file");
2225 rc = -EINVAL;
2226 goto out;
2227 }
2228 if (rc < 2)
2229 continue;
2230
Harald Welte470ec292009-06-26 20:25:23 +02002231 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002232 if (!fle) {
2233 rc = -ENOMEM;
2234 goto out;
2235 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002236
2237 /* construct new filename */
2238 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2239 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2240 strcat(fle->fname, "/");
2241 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002242
2243 llist_add_tail(&fle->list, &bs11_sw->file_list);
2244 }
2245
2246out:
2247 fclose(swl);
2248 return rc;
2249}
2250
2251/* bs11 swload specific callback, passed to abis_nm core swload */
2252static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2253 struct msgb *msg, void *data, void *param)
2254{
2255 struct abis_nm_bs11_sw *bs11_sw = data;
2256 struct file_list_entry *fle;
2257 int rc = 0;
2258
Harald Welte5e4d1b32009-02-01 13:36:56 +00002259 switch (event) {
2260 case NM_MT_LOAD_END_ACK:
2261 fle = fl_dequeue(&bs11_sw->file_list);
2262 if (fle) {
2263 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002264 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002265 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002266 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002267 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002268 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002269 } else {
2270 /* activate the SWL */
2271 rc = abis_nm_software_activate(bs11_sw->bts,
2272 bs11_sw->swl_fname,
2273 bs11_swload_cbfn,
2274 bs11_sw);
2275 }
2276 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002277 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002278 case NM_MT_LOAD_END_NACK:
2279 case NM_MT_LOAD_INIT_ACK:
2280 case NM_MT_LOAD_INIT_NACK:
2281 case NM_MT_ACTIVATE_SW_NACK:
2282 case NM_MT_ACTIVATE_SW_ACK:
2283 default:
2284 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002285 if (bs11_sw->user_cb)
2286 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002287 break;
2288 }
2289
2290 return rc;
2291}
2292
2293/* Siemens provides a SWL file that is a mere listing of all the other
2294 * files that are part of a software release. We need to upload first
2295 * the list file, and then each file that is listed in the list file */
2296int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002297 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002298{
2299 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2300 struct file_list_entry *fle;
2301 int rc = 0;
2302
2303 INIT_LLIST_HEAD(&bs11_sw->file_list);
2304 bs11_sw->bts = bts;
2305 bs11_sw->win_size = win_size;
2306 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002307 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002308
2309 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2310 rc = bs11_read_swl_file(bs11_sw);
2311 if (rc < 0)
2312 return rc;
2313
2314 /* dequeue next item in file list */
2315 fle = fl_dequeue(&bs11_sw->file_list);
2316 if (!fle)
2317 return -EINVAL;
2318
2319 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002320 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002321 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002322 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002323 return rc;
2324}
2325
Harald Welte5083b0b2009-02-02 19:20:52 +00002326#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002327static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002328 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2329 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2330 NM_ATT_BS11_LMT_USER_NAME,
2331
2332 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2333
2334 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2335
2336 NM_ATT_BS11_SW_LOAD_STORED };
2337
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002338static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002339 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2340 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2341 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2342 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002343#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002344
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002345static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002346 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2347 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002348 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002349
2350int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2351{
2352 struct abis_om_hdr *oh;
2353 struct msgb *msg = nm_msgb_alloc();
2354
2355 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2356 /* SiemensHW CCTRL object */
2357 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2358 0x03, 0x00, 0x00);
2359 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2360
2361 return abis_nm_sendmsg(bts, msg);
2362}
Harald Welte268bb402009-02-01 19:11:56 +00002363
2364int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2365{
2366 struct abis_om_hdr *oh;
2367 struct msgb *msg = nm_msgb_alloc();
2368 struct bs11_date_time aet;
2369
2370 get_bs11_date_time(&aet);
2371 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2372 /* SiemensHW CCTRL object */
2373 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2374 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002375 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002376
2377 return abis_nm_sendmsg(bts, msg);
2378}
Harald Welte5c1e4582009-02-15 11:57:29 +00002379
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002380int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002381{
2382 struct abis_om_hdr *oh;
2383 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002384 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002385
2386 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2387 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2388 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2389 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2390
2391 return abis_nm_sendmsg(bts, msg);
2392}
2393
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002394int 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 +02002395{
2396 struct abis_om_hdr *oh;
2397 struct msgb *msg = nm_msgb_alloc();
2398 struct bs11_date_time aet;
2399
2400 get_bs11_date_time(&aet);
2401 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2402 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2403 bport, 0xff, 0x02);
2404 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2405
2406 return abis_nm_sendmsg(bts, msg);
2407}
2408
Harald Welte5c1e4582009-02-15 11:57:29 +00002409/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002410static const char ipaccess_magic[] = "com.ipaccess";
2411
Harald Welte677c21f2009-02-17 13:22:23 +00002412
2413static int abis_nm_rx_ipacc(struct msgb *msg)
2414{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002415 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002416 struct abis_om_hdr *oh = msgb_l2(msg);
2417 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002418 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002419 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002420 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002421
2422 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002423 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002424 return -EINVAL;
2425 }
2426
Harald Welte193fefc2009-04-30 15:16:27 +00002427 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002428 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002429
Harald Welte15c61722011-05-22 22:45:37 +02002430 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002431
Harald Welte746d6092009-10-19 22:11:11 +02002432 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002433
Harald Welte677c21f2009-02-17 13:22:23 +00002434 switch (foh->msg_type) {
2435 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002436 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002437 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2438 memcpy(&addr,
2439 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2440
2441 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2442 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002443 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002444 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002445 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002446 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002447 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2448 DEBUGPC(DNM, "STREAM=0x%02x ",
2449 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002450 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002451 break;
2452 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002453 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002454 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002455 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002456 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002457 else
2458 DEBUGPC(DNM, "\n");
2459 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002460 case NM_MT_IPACC_SET_NVATTR_ACK:
2461 DEBUGPC(DNM, "SET NVATTR ACK\n");
2462 /* FIXME: decode and show the actual attributes */
2463 break;
2464 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002465 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002466 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002467 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002468 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002469 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002470 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002471 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002472 case NM_MT_IPACC_GET_NVATTR_ACK:
2473 DEBUGPC(DNM, "GET NVATTR ACK\n");
2474 /* FIXME: decode and show the actual attributes */
2475 break;
2476 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002477 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002478 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002479 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002480 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002481 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002482 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002483 break;
Harald Welte15c44172009-10-08 20:15:24 +02002484 case NM_MT_IPACC_SET_ATTR_ACK:
2485 DEBUGPC(DNM, "SET ATTR ACK\n");
2486 break;
2487 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002488 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002489 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002490 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002491 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002492 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002493 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002494 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002495 default:
2496 DEBUGPC(DNM, "unknown\n");
2497 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002498 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002499
2500 /* signal handling */
2501 switch (foh->msg_type) {
2502 case NM_MT_IPACC_RSL_CONNECT_NACK:
2503 case NM_MT_IPACC_SET_NVATTR_NACK:
2504 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002505 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002506 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002507 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002508 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002509 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002510 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002511 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002512 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002513 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002514 default:
2515 break;
2516 }
2517
Harald Welte677c21f2009-02-17 13:22:23 +00002518 return 0;
2519}
2520
Harald Welte193fefc2009-04-30 15:16:27 +00002521/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002522int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2523 uint8_t obj_class, uint8_t bts_nr,
2524 uint8_t trx_nr, uint8_t ts_nr,
2525 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002526{
2527 struct msgb *msg = nm_msgb_alloc();
2528 struct abis_om_hdr *oh;
2529 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002530 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002531
2532 /* construct the 12.21 OM header, observe the erroneous length */
2533 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2534 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2535 oh->mdisc = ABIS_OM_MDISC_MANUF;
2536
2537 /* add the ip.access magic */
2538 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2539 *data++ = sizeof(ipaccess_magic);
2540 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2541
2542 /* fill the 12.21 FOM header */
2543 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2544 foh->msg_type = msg_type;
2545 foh->obj_class = obj_class;
2546 foh->obj_inst.bts_nr = bts_nr;
2547 foh->obj_inst.trx_nr = trx_nr;
2548 foh->obj_inst.ts_nr = ts_nr;
2549
2550 if (attr && attr_len) {
2551 data = msgb_put(msg, attr_len);
2552 memcpy(data, attr, attr_len);
2553 }
2554
2555 return abis_nm_sendmsg(bts, msg);
2556}
Harald Welte677c21f2009-02-17 13:22:23 +00002557
Harald Welte193fefc2009-04-30 15:16:27 +00002558/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002559int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002560 int attr_len)
2561{
Harald Welte2ef156d2010-01-07 20:39:42 +01002562 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2563 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002564 attr_len);
2565}
2566
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002567int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002568 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002569{
2570 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002571 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002572 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2573 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2574
2575 int attr_len = sizeof(attr);
2576
2577 ia.s_addr = htonl(ip);
2578 attr[1] = stream;
2579 attr[3] = port >> 8;
2580 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002581 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002582
2583 /* if ip == 0, we use the default IP */
2584 if (ip == 0)
2585 attr_len -= 5;
2586
2587 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002588 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002589
2590 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2591 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2592 trx->nr, 0xff, attr, attr_len);
2593}
2594
Harald Welte193fefc2009-04-30 15:16:27 +00002595/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002596int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002597{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002598 struct abis_om_hdr *oh;
2599 struct msgb *msg = nm_msgb_alloc();
2600
2601 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2602 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2603 trx->bts->nr, trx->nr, 0xff);
2604
2605 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002606}
Harald Weltedaef5212009-10-24 10:20:41 +02002607
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002608int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2609 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2610 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002611{
2612 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2613 obj_class, bts_nr, trx_nr, ts_nr,
2614 attr, attr_len);
2615}
Harald Welte0f255852009-11-12 14:48:42 +01002616
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002617void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002618{
2619 /* we simply reuse the GSM48 function and overwrite the RAC
2620 * with the Cell ID */
2621 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002622 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002623}
2624
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002625void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2626{
2627 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2628
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002629 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002630 if (!trx->bts || !trx->bts->oml_link)
2631 return;
2632
2633 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2634 trx->bts->bts_nr, trx->nr, 0xff,
2635 new_state);
2636}
2637
Harald Welte92b1fe42010-03-25 11:45:30 +08002638static const struct value_string ipacc_testres_names[] = {
2639 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2640 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2641 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2642 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2643 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2644 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002645};
2646
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002647const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002648{
Harald Welte92b1fe42010-03-25 11:45:30 +08002649 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002650}
2651
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002652void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002653{
2654 cid->mcc = (buf[0] & 0xf) * 100;
2655 cid->mcc += (buf[0] >> 4) * 10;
2656 cid->mcc += (buf[1] & 0xf) * 1;
2657
2658 if (buf[1] >> 4 == 0xf) {
2659 cid->mnc = (buf[2] & 0xf) * 10;
2660 cid->mnc += (buf[2] >> 4) * 1;
2661 } else {
2662 cid->mnc = (buf[2] & 0xf) * 100;
2663 cid->mnc += (buf[2] >> 4) * 10;
2664 cid->mnc += (buf[1] >> 4) * 1;
2665 }
2666
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002667 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2668 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002669}
2670
Harald Welte0f255852009-11-12 14:48:42 +01002671/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002672int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002673{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002674 uint8_t *cur = buf;
2675 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01002676
Harald Welteaf109b92010-07-22 18:14:36 +02002677 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002678
2679 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2680 return -EINVAL;
2681 cur++;
2682
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002683 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002684 cur += 2;
2685
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002686 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002687 cur += 2;
2688
2689 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2690 binf->freq_qual = *cur >> 2;
2691
Harald Welteaf109b92010-07-22 18:14:36 +02002692 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002693 binf->arfcn |= *cur++;
2694
2695 if (binf->info_type & IPAC_BINF_RXLEV)
2696 binf->rx_lev = *cur & 0x3f;
2697 cur++;
2698
2699 if (binf->info_type & IPAC_BINF_RXQUAL)
2700 binf->rx_qual = *cur & 0x7;
2701 cur++;
2702
2703 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002704 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002705 cur += 2;
2706
2707 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002708 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002709 cur += 2;
2710
2711 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002712 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002713 cur += 4;
2714
Harald Weltea780a3d2010-07-30 22:34:42 +02002715#if 0
2716 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002717 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002718#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002719 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002720 cur++;
2721
Harald Welteb40a38f2009-11-13 11:56:05 +01002722 ipac_parse_cgi(&binf->cgi, cur);
2723 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002724
2725 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2726 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2727 cur += sizeof(binf->ba_list_si2);
2728 }
2729
2730 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2731 memcpy(binf->ba_list_si2bis, cur,
2732 sizeof(binf->ba_list_si2bis));
2733 cur += sizeof(binf->ba_list_si2bis);
2734 }
2735
2736 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2737 memcpy(binf->ba_list_si2ter, cur,
2738 sizeof(binf->ba_list_si2ter));
2739 cur += sizeof(binf->ba_list_si2ter);
2740 }
2741
2742 return 0;
2743}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002744
2745void abis_nm_clear_queue(struct gsm_bts *bts)
2746{
2747 struct msgb *msg;
2748
2749 while (!llist_empty(&bts->abis_queue)) {
2750 msg = msgb_dequeue(&bts->abis_queue);
2751 msgb_free(msg);
2752 }
2753
2754 bts->abis_nm_pend = 0;
2755}