blob: c9062d52675e98c3c03e4c104c2fe043a55b4d7d [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
Harald Welte21bd3a52009-08-10 12:21:22 +020051static const enum abis_nm_chan_comb chcomb4pchan[] = {
52 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
53 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
54 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
55 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
56 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +020057 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
58 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +020059 /* FIXME: bounds check */
60};
61
62int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
63{
64 if (pchan < ARRAY_SIZE(chcomb4pchan))
65 return chcomb4pchan[pchan];
66
67 return -EINVAL;
68}
69
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020070int 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 +000071{
Harald Welte39315c42010-01-10 18:01:52 +010072 if (!bts->model)
73 return -EIO;
74 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000075}
Harald Weltee0590df2009-02-15 03:34:15 +000076
Harald Welte52b1f982008-12-23 20:25:15 +000077static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
78{
79 int i;
80
81 for (i = 0; i < size; i++) {
82 if (arr[i] == mt)
83 return 1;
84 }
85
86 return 0;
87}
88
Holger Freytherca362a62009-01-04 21:05:01 +000089#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000090/* is this msgtype the usual ACK/NACK type ? */
91static int is_ack_nack(enum abis_nm_msgtype mt)
92{
93 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
94}
Holger Freytherca362a62009-01-04 21:05:01 +000095#endif
Harald Welte52b1f982008-12-23 20:25:15 +000096
97/* is this msgtype a report ? */
98static int is_report(enum abis_nm_msgtype mt)
99{
Harald Welte15c61722011-05-22 22:45:37 +0200100 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000101}
102
103#define MT_ACK(x) (x+1)
104#define MT_NACK(x) (x+2)
105
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200106static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +0000107{
108 oh->mdisc = ABIS_OM_MDISC_FOM;
109 oh->placement = ABIS_OM_PLACEMENT_ONLY;
110 oh->sequence = 0;
111 oh->length = len;
112}
113
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200114static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
115 uint8_t msg_type, uint8_t obj_class,
116 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000117{
118 struct abis_om_fom_hdr *foh =
119 (struct abis_om_fom_hdr *) oh->data;
120
Harald Welte702d8702008-12-26 20:25:35 +0000121 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000122 foh->msg_type = msg_type;
123 foh->obj_class = obj_class;
124 foh->obj_inst.bts_nr = bts_nr;
125 foh->obj_inst.trx_nr = trx_nr;
126 foh->obj_inst.ts_nr = ts_nr;
127}
128
Harald Welte8470bf22008-12-25 23:28:35 +0000129static struct msgb *nm_msgb_alloc(void)
130{
Harald Welte966636f2009-06-26 19:39:35 +0200131 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
132 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000133}
134
Harald Welte52b1f982008-12-23 20:25:15 +0000135/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100136static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000137{
Holger Freyther59639e82009-02-09 23:09:55 +0000138 msg->trx = bts->c0;
139
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100140 /* queue OML messages */
141 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
142 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100143 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100144 } else {
145 msgb_enqueue(&bts->abis_queue, msg);
146 return 0;
147 }
148
149}
150
151int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
152{
153 OBSC_NM_W_ACK_CB(msg) = 1;
154 return abis_nm_queue_msg(bts, msg);
155}
156
157static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
158{
159 OBSC_NM_W_ACK_CB(msg) = 0;
160 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000161}
162
Harald Welte4724f992009-01-18 18:01:49 +0000163static int abis_nm_rcvmsg_sw(struct msgb *mb);
164
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100165int nm_is_running(struct gsm_nm_state *s) {
166 return (s->operational == NM_OPSTATE_ENABLED) && (
167 (s->availability == NM_AVSTATE_OK) ||
168 (s->availability == 0xff)
169 );
170}
171
Harald Weltee0590df2009-02-15 03:34:15 +0000172/* obtain the gsm_nm_state data structure for a given object instance */
173static struct gsm_nm_state *
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200174objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
Harald Weltee0590df2009-02-15 03:34:15 +0000175 struct abis_om_obj_inst *obj_inst)
176{
177 struct gsm_bts_trx *trx;
178 struct gsm_nm_state *nm_state = NULL;
179
180 switch (obj_class) {
181 case NM_OC_BTS:
182 nm_state = &bts->nm_state;
183 break;
184 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100185 if (obj_inst->trx_nr >= bts->num_trx) {
186 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000187 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100188 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200189 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000190 nm_state = &trx->nm_state;
191 break;
192 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100193 if (obj_inst->trx_nr >= bts->num_trx) {
194 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000195 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100196 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200197 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000198 nm_state = &trx->bb_transc.nm_state;
199 break;
200 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100201 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100202 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000203 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100204 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200205 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000206 if (obj_inst->ts_nr >= TRX_NR_TS)
207 return NULL;
208 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
209 break;
210 case NM_OC_SITE_MANAGER:
211 nm_state = &bts->site_mgr.nm_state;
212 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000213 case NM_OC_BS11:
214 switch (obj_inst->bts_nr) {
215 case BS11_OBJ_CCLK:
216 nm_state = &bts->bs11.cclk.nm_state;
217 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000218 case BS11_OBJ_BBSIG:
219 if (obj_inst->ts_nr > bts->num_trx)
220 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200221 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000222 nm_state = &trx->bs11.bbsig.nm_state;
223 break;
224 case BS11_OBJ_PA:
225 if (obj_inst->ts_nr > bts->num_trx)
226 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200227 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000228 nm_state = &trx->bs11.pa.nm_state;
229 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000230 default:
231 return NULL;
232 }
233 case NM_OC_BS11_RACK:
234 nm_state = &bts->bs11.rack.nm_state;
235 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000236 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100237 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000238 return NULL;
239 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
240 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200241 case NM_OC_GPRS_NSE:
242 nm_state = &bts->gprs.nse.nm_state;
243 break;
244 case NM_OC_GPRS_CELL:
245 nm_state = &bts->gprs.cell.nm_state;
246 break;
247 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100248 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200249 return NULL;
250 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
251 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000252 }
253 return nm_state;
254}
255
256/* obtain the in-memory data structure of a given object instance */
257static void *
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200258objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
Harald Weltee0590df2009-02-15 03:34:15 +0000259 struct abis_om_obj_inst *obj_inst)
260{
261 struct gsm_bts_trx *trx;
262 void *obj = NULL;
263
264 switch (obj_class) {
265 case NM_OC_BTS:
266 obj = bts;
267 break;
268 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100269 if (obj_inst->trx_nr >= bts->num_trx) {
270 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000271 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100272 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200273 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000274 obj = trx;
275 break;
276 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100277 if (obj_inst->trx_nr >= bts->num_trx) {
278 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000279 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100280 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200281 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000282 obj = &trx->bb_transc;
283 break;
284 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100285 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100286 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000287 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100288 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200289 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000290 if (obj_inst->ts_nr >= TRX_NR_TS)
291 return NULL;
292 obj = &trx->ts[obj_inst->ts_nr];
293 break;
294 case NM_OC_SITE_MANAGER:
295 obj = &bts->site_mgr;
296 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200297 case NM_OC_GPRS_NSE:
298 obj = &bts->gprs.nse;
299 break;
300 case NM_OC_GPRS_CELL:
301 obj = &bts->gprs.cell;
302 break;
303 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100304 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200305 return NULL;
306 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
307 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000308 }
309 return obj;
310}
311
312/* Update the administrative state of a given object in our in-memory data
313 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200314static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
315 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000316{
Harald Welteaeedeb42009-05-01 13:08:14 +0000317 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100318 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000319
Harald Welteaf9b8102011-03-06 21:20:38 +0100320 memset(&nsd, 0, sizeof(nsd));
321
Harald Weltef338a032011-01-14 15:55:42 +0100322 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
323 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100324 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000325 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
326 if (!nm_state)
327 return -1;
328
329 new_state = *nm_state;
330 new_state.administrative = adm_state;
331
Harald Weltef38ca9a2011-03-06 22:11:32 +0100332 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100333 nsd.obj_class = obj_class;
334 nsd.old_state = nm_state;
335 nsd.new_state = &new_state;
336 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200337 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000338
339 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000340
Harald Weltef338a032011-01-14 15:55:42 +0100341 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000342}
343
Harald Welte97ed1e72009-02-06 13:38:02 +0000344static int abis_nm_rx_statechg_rep(struct msgb *mb)
345{
Harald Weltee0590df2009-02-15 03:34:15 +0000346 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000347 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000348 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000349 struct tlv_parsed tp;
350 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000351
Harald Welte23897662009-05-01 14:52:51 +0000352 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000353
Harald Welte8b697c72009-06-05 19:18:45 +0000354 memset(&new_state, 0, sizeof(new_state));
355
Harald Weltee0590df2009-02-15 03:34:15 +0000356 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
357 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100358 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000359 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000360 }
Harald Weltee0590df2009-02-15 03:34:15 +0000361
362 new_state = *nm_state;
363
Harald Welte39315c42010-01-10 18:01:52 +0100364 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000365 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
366 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200367 DEBUGPC(DNM, "OP_STATE=%s ",
368 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000369 }
370 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000371 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
372 new_state.availability = 0xff;
373 else
374 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200375 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
376 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000377 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100378 } else
379 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000380 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
381 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200382 DEBUGPC(DNM, "ADM=%2s ",
383 abis_nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000384 }
385 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000386
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100387 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
388 new_state.operational != nm_state->operational ||
389 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000390 /* Update the operational state of a given object in our in-memory data
391 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100392 struct nm_statechg_signal_data nsd;
393 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
394 nsd.obj_class = foh->obj_class;
395 nsd.old_state = nm_state;
396 nsd.new_state = &new_state;
397 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100398 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200399 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100400 nm_state->operational = new_state.operational;
401 nm_state->availability = new_state.availability;
402 if (nm_state->administrative == 0)
403 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000404 }
405#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000406 if (op_state == 1) {
407 /* try to enable objects that are disabled */
408 abis_nm_opstart(bts, foh->obj_class,
409 foh->obj_inst.bts_nr,
410 foh->obj_inst.trx_nr,
411 foh->obj_inst.ts_nr);
412 }
Harald Weltee0590df2009-02-15 03:34:15 +0000413#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000414 return 0;
415}
416
Harald Welte0db97b22009-05-01 17:22:47 +0000417static int rx_fail_evt_rep(struct msgb *mb)
418{
419 struct abis_om_hdr *oh = msgb_l2(mb);
420 struct abis_om_fom_hdr *foh = msgb_l3(mb);
421 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100422 const uint8_t *p_val;
423 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000424
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200425 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000426
Harald Welte39315c42010-01-10 18:01:52 +0100427 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000428
429 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200430 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
431 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000432 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200433 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
434 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100435 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
436 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200437 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 +0100438 }
439 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
440 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
441 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
442 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200443 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100444 talloc_free(p_text);
445 }
446 }
Harald Welte0db97b22009-05-01 17:22:47 +0000447
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200448 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000449
450 return 0;
451}
452
Harald Welte97ed1e72009-02-06 13:38:02 +0000453static int abis_nm_rcvmsg_report(struct msgb *mb)
454{
455 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200456 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000457
Harald Welte15c61722011-05-22 22:45:37 +0200458 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000459
Harald Welte97ed1e72009-02-06 13:38:02 +0000460 //nmh->cfg->report_cb(mb, foh);
461
462 switch (mt) {
463 case NM_MT_STATECHG_EVENT_REP:
464 return abis_nm_rx_statechg_rep(mb);
465 break;
Harald Welte34a99682009-02-13 02:41:40 +0000466 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000467 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200468 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000469 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000470 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000471 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200472 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000473 break;
Harald Weltec7310382009-08-08 00:02:36 +0200474 case NM_MT_TEST_REP:
475 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200476 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200477 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000478 default:
Harald Welte23897662009-05-01 14:52:51 +0000479 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000480 break;
481
Harald Welte97ed1e72009-02-06 13:38:02 +0000482 };
483
Harald Welte97ed1e72009-02-06 13:38:02 +0000484 return 0;
485}
486
Harald Welte34a99682009-02-13 02:41:40 +0000487/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200488static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
489 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000490{
491 struct abis_om_hdr *oh;
492 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200493 uint8_t len = swdesc_len;
494 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000495
496 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
497 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
498
499 trailer = msgb_put(msg, swdesc_len);
500 memcpy(trailer, sw_desc, swdesc_len);
501
502 return abis_nm_sendmsg(bts, msg);
503}
504
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200505static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100506{
507 static const struct tlv_definition sw_descr_def = {
508 .def = {
509 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
510 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
511 },
512 };
513
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200514 uint8_t tag;
515 uint16_t tag_len;
516 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100517 int ofs = 0, len;
518
519 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
520 * nested nature and the fact you have to assume it contains only two sub
521 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
522
523 if (sw_descr[0] != NM_ATT_SW_DESCR) {
524 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
525 return -1;
526 }
527 ofs += 1;
528
529 len = tlv_parse_one(&tag, &tag_len, &val,
530 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
531 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
532 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
533 return -2;
534 }
535 ofs += len;
536
537 len = tlv_parse_one(&tag, &tag_len, &val,
538 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
539 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
540 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
541 return -3;
542 }
543 ofs += len;
544
545 return ofs;
546}
547
Harald Welte34a99682009-02-13 02:41:40 +0000548static int abis_nm_rx_sw_act_req(struct msgb *mb)
549{
550 struct abis_om_hdr *oh = msgb_l2(mb);
551 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200552 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200553 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100554 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000555
Harald Welte15c61722011-05-22 22:45:37 +0200556 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200557
558 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000559
Harald Welte97a282b2010-03-14 15:37:43 +0800560 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000561
562 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000563 foh->obj_inst.bts_nr,
564 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800565 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000566 foh->data, oh->length-sizeof(*foh));
567
Harald Welte39315c42010-01-10 18:01:52 +0100568 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200569 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
570 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
571 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
572 DEBUGP(DNM, "SW config not found! Can't continue.\n");
573 return -EINVAL;
574 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200575 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200576 }
577
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100578 /* Use the first SW_DESCR present in SW config */
579 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
580 if (sw_descr_len < 0)
581 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200582
Harald Welte34a99682009-02-13 02:41:40 +0000583 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
584 foh->obj_inst.bts_nr,
585 foh->obj_inst.trx_nr,
586 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100587 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000588}
589
Harald Weltee0590df2009-02-15 03:34:15 +0000590/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
591static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
592{
593 struct abis_om_hdr *oh = msgb_l2(mb);
594 struct abis_om_fom_hdr *foh = msgb_l3(mb);
595 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200596 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000597
Harald Welte39315c42010-01-10 18:01:52 +0100598 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000599 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
600 return -EINVAL;
601
602 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
603
604 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
605}
606
Harald Welteee670472009-02-22 21:58:49 +0000607static int abis_nm_rx_lmt_event(struct msgb *mb)
608{
609 struct abis_om_hdr *oh = msgb_l2(mb);
610 struct abis_om_fom_hdr *foh = msgb_l3(mb);
611 struct tlv_parsed tp;
612
613 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100614 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000615 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
616 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200617 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000618 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
619 }
620 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
621 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200622 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000623 DEBUGPC(DNM, "Level=%u ", level);
624 }
625 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
626 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
627 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
628 DEBUGPC(DNM, "Username=%s ", name);
629 }
630 DEBUGPC(DNM, "\n");
631 /* FIXME: parse LMT LOGON TIME */
632 return 0;
633}
634
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100635static void abis_nm_queue_send_next(struct gsm_bts *bts)
636{
637 int wait = 0;
638 struct msgb *msg;
639 /* the queue is empty */
640 while (!llist_empty(&bts->abis_queue)) {
641 msg = msgb_dequeue(&bts->abis_queue);
642 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100643 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100644
645 if (wait)
646 break;
647 }
648
649 bts->abis_nm_pend = wait;
650}
651
Harald Welte52b1f982008-12-23 20:25:15 +0000652/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000653static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000654{
Harald Welte6c96ba52009-05-01 13:03:40 +0000655 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000656 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200657 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100658 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000659
660 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000661 if (is_report(mt))
662 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000663
Harald Welte15c61722011-05-22 22:45:37 +0200664 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000665 return abis_nm_rcvmsg_sw(mb);
666
Harald Welte15c61722011-05-22 22:45:37 +0200667 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800668 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000669 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200670
Harald Welte15c61722011-05-22 22:45:37 +0200671 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200672
Harald Welte15c61722011-05-22 22:45:37 +0200673 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000674
Harald Welte39315c42010-01-10 18:01:52 +0100675 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000676 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200677 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200678 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000679 else
680 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200681
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800682 nack_data.msg = mb;
683 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200684 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100685 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200686 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000687 }
Harald Weltead384642008-12-26 10:20:07 +0000688#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000689 /* check if last message is to be acked */
690 if (is_ack_nack(nmh->last_msgtype)) {
691 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100692 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000693 /* we got our ACK, continue sending the next msg */
694 } else if (mt == MT_NACK(nmh->last_msgtype)) {
695 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100696 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000697 /* FIXME: somehow signal this to the caller */
698 } else {
699 /* really strange things happen */
700 return -EINVAL;
701 }
702 }
Harald Weltead384642008-12-26 10:20:07 +0000703#endif
704
Harald Welte97ed1e72009-02-06 13:38:02 +0000705 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000706 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100707 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000708 break;
Harald Welte34a99682009-02-13 02:41:40 +0000709 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100710 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000711 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000712 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100713 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000714 break;
Harald Welte1989c082009-08-06 17:58:31 +0200715 case NM_MT_CONN_MDROP_LINK_ACK:
716 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
717 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100718 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200719 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100720 break;
721 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200722 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100723 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100724 case NM_MT_SET_BTS_ATTR_ACK:
725 /* The HSL wants an OPSTART _after_ the SI has been set */
726 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
727 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
728 }
729 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000730 }
731
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100732 abis_nm_queue_send_next(mb->trx->bts);
733 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000734}
735
Harald Welte677c21f2009-02-17 13:22:23 +0000736static int abis_nm_rx_ipacc(struct msgb *mb);
737
738static int abis_nm_rcvmsg_manuf(struct msgb *mb)
739{
740 int rc;
741 int bts_type = mb->trx->bts->type;
742
743 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100744 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000745 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100746 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000747 break;
748 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100749 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
750 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000751 rc = 0;
752 break;
753 }
754
755 return rc;
756}
757
Harald Welte52b1f982008-12-23 20:25:15 +0000758/* High-Level API */
759/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000760int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000761{
Harald Welte52b1f982008-12-23 20:25:15 +0000762 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000763 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000764
765 /* Various consistency checks */
766 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100767 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000768 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200769 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
770 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000771 }
772 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100773 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000774 oh->sequence);
775 return -EINVAL;
776 }
Harald Welte702d8702008-12-26 20:25:35 +0000777#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200778 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000779 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000780 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100781 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000782 oh->length + sizeof(*oh), l2_len);
783 return -EINVAL;
784 }
Harald Welte702d8702008-12-26 20:25:35 +0000785 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100786 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 +0000787#endif
Harald Weltead384642008-12-26 10:20:07 +0000788 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000789
790 switch (oh->mdisc) {
791 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000792 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000793 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000794 case ABIS_OM_MDISC_MANUF:
795 rc = abis_nm_rcvmsg_manuf(msg);
796 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000797 case ABIS_OM_MDISC_MMI:
798 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100799 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000800 oh->mdisc);
801 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000802 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100803 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000804 oh->mdisc);
805 return -EINVAL;
806 }
807
Harald Weltead384642008-12-26 10:20:07 +0000808 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000809 return rc;
810}
811
812#if 0
813/* initialized all resources */
814struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
815{
816 struct abis_nm_h *nmh;
817
818 nmh = malloc(sizeof(*nmh));
819 if (!nmh)
820 return NULL;
821
822 nmh->cfg = cfg;
823
824 return nmh;
825}
826
827/* free all resources */
828void abis_nm_fini(struct abis_nm_h *nmh)
829{
830 free(nmh);
831}
832#endif
833
834/* Here we are trying to define a high-level API that can be used by
835 * the actual BSC implementation. However, the architecture is currently
836 * still under design. Ideally the calls to this API would be synchronous,
837 * while the underlying stack behind the APi runs in a traditional select
838 * based state machine.
839 */
840
Harald Welte4724f992009-01-18 18:01:49 +0000841/* 6.2 Software Load: */
842enum sw_state {
843 SW_STATE_NONE,
844 SW_STATE_WAIT_INITACK,
845 SW_STATE_WAIT_SEGACK,
846 SW_STATE_WAIT_ENDACK,
847 SW_STATE_WAIT_ACTACK,
848 SW_STATE_ERROR,
849};
Harald Welte52b1f982008-12-23 20:25:15 +0000850
Harald Welte52b1f982008-12-23 20:25:15 +0000851struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000852 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800853 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000854 gsm_cbfn *cbfn;
855 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000856 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000857
Harald Welte52b1f982008-12-23 20:25:15 +0000858 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200859 uint8_t obj_class;
860 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000861
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200862 uint8_t file_id[255];
863 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000864
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200865 uint8_t file_version[255];
866 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000867
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200868 uint8_t window_size;
869 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000870
871 int fd;
872 FILE *stream;
873 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000874 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000875};
876
Harald Welte4724f992009-01-18 18:01:49 +0000877static struct abis_nm_sw g_sw;
878
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100879static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
880{
881 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
882 msgb_v_put(msg, NM_ATT_SW_DESCR);
883 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
884 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
885 sw->file_version);
886 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
887 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
888 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
889 sw->file_version);
890 } else {
891 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
892 }
893}
894
Harald Welte4724f992009-01-18 18:01:49 +0000895/* 6.2.1 / 8.3.1: Load Data Initiate */
896static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000897{
Harald Welte4724f992009-01-18 18:01:49 +0000898 struct abis_om_hdr *oh;
899 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200900 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000901
902 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
903 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
904 sw->obj_instance[0], sw->obj_instance[1],
905 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100906
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100907 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000908 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
909
910 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000911}
912
Harald Welte1602ade2009-01-29 21:12:39 +0000913static int is_last_line(FILE *stream)
914{
915 char next_seg_buf[256];
916 long pos;
917
918 /* check if we're sending the last line */
919 pos = ftell(stream);
920 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
921 fseek(stream, pos, SEEK_SET);
922 return 1;
923 }
924
925 fseek(stream, pos, SEEK_SET);
926 return 0;
927}
928
Harald Welte4724f992009-01-18 18:01:49 +0000929/* 6.2.2 / 8.3.2 Load Data Segment */
930static int sw_load_segment(struct abis_nm_sw *sw)
931{
932 struct abis_om_hdr *oh;
933 struct msgb *msg = nm_msgb_alloc();
934 char seg_buf[256];
935 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000936 unsigned char *tlv;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200937 uint8_t len;
Harald Welte4724f992009-01-18 18:01:49 +0000938
939 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000940
941 switch (sw->bts->type) {
942 case GSM_BTS_TYPE_BS11:
943 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
944 perror("fgets reading segment");
945 return -EINVAL;
946 }
947 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000948
949 /* check if we're sending the last line */
950 sw->last_seg = is_last_line(sw->stream);
951 if (sw->last_seg)
952 seg_buf[1] = 0;
953 else
954 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000955
956 len = strlen(line_buf) + 2;
957 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200958 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000959 /* BS11 wants CR + LF in excess of the TLV length !?! */
960 tlv[1] -= 2;
961
962 /* we only now know the exact length for the OM hdr */
963 len = strlen(line_buf)+2;
964 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100965 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200966 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100967 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
968 if (len < 0) {
969 perror("read failed");
970 return -EINVAL;
971 }
972
973 if (len != IPACC_SEGMENT_SIZE)
974 sw->last_seg = 1;
975
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100976 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200977 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100978 len += 3;
979 break;
980 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000981 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100982 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000983 /* FIXME: Other BTS types */
984 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000985 }
Harald Welte4724f992009-01-18 18:01:49 +0000986
Harald Welte4724f992009-01-18 18:01:49 +0000987 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
988 sw->obj_instance[0], sw->obj_instance[1],
989 sw->obj_instance[2]);
990
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100991 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000992}
993
994/* 6.2.4 / 8.3.4 Load Data End */
995static int sw_load_end(struct abis_nm_sw *sw)
996{
997 struct abis_om_hdr *oh;
998 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200999 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001000
1001 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1002 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1003 sw->obj_instance[0], sw->obj_instance[1],
1004 sw->obj_instance[2]);
1005
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001006 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001007 return abis_nm_sendmsg(sw->bts, msg);
1008}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001009
Harald Welte52b1f982008-12-23 20:25:15 +00001010/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001011static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001012{
Harald Welte4724f992009-01-18 18:01:49 +00001013 struct abis_om_hdr *oh;
1014 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001015 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001016
Harald Welte4724f992009-01-18 18:01:49 +00001017 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1018 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1019 sw->obj_instance[0], sw->obj_instance[1],
1020 sw->obj_instance[2]);
1021
1022 /* FIXME: this is BS11 specific format */
1023 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1024 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1025 sw->file_version);
1026
1027 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001028}
Harald Welte4724f992009-01-18 18:01:49 +00001029
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001030struct sdp_firmware {
1031 char magic[4];
1032 char more_magic[4];
1033 unsigned int header_length;
1034 unsigned int file_length;
1035} __attribute__ ((packed));
1036
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001037static int parse_sdp_header(struct abis_nm_sw *sw)
1038{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001039 struct sdp_firmware firmware_header;
1040 int rc;
1041 struct stat stat;
1042
1043 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1044 if (rc != sizeof(firmware_header)) {
1045 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1046 return -1;
1047 }
1048
1049 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1050 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1051 return -1;
1052 }
1053
1054 if (firmware_header.more_magic[0] != 0x10 ||
1055 firmware_header.more_magic[1] != 0x02 ||
1056 firmware_header.more_magic[2] != 0x00 ||
1057 firmware_header.more_magic[3] != 0x00) {
1058 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1059 return -1;
1060 }
1061
1062
1063 if (fstat(sw->fd, &stat) == -1) {
1064 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1065 return -1;
1066 }
1067
1068 if (ntohl(firmware_header.file_length) != stat.st_size) {
1069 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1070 return -1;
1071 }
1072
1073 /* go back to the start as we checked the whole filesize.. */
1074 lseek(sw->fd, 0l, SEEK_SET);
1075 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1076 "There might be checksums in the file that are not\n"
1077 "verified and incomplete firmware might be flashed.\n"
1078 "There is absolutely no WARRANTY that flashing will\n"
1079 "work.\n");
1080 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001081}
1082
Harald Welte4724f992009-01-18 18:01:49 +00001083static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1084{
1085 char file_id[12+1];
1086 char file_version[80+1];
1087 int rc;
1088
1089 sw->fd = open(fname, O_RDONLY);
1090 if (sw->fd < 0)
1091 return sw->fd;
1092
1093 switch (sw->bts->type) {
1094 case GSM_BTS_TYPE_BS11:
1095 sw->stream = fdopen(sw->fd, "r");
1096 if (!sw->stream) {
1097 perror("fdopen");
1098 return -1;
1099 }
1100 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001101 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001102 file_id, file_version);
1103 if (rc != 2) {
1104 perror("parsing header line of software file");
1105 return -1;
1106 }
1107 strcpy((char *)sw->file_id, file_id);
1108 sw->file_id_len = strlen(file_id);
1109 strcpy((char *)sw->file_version, file_version);
1110 sw->file_version_len = strlen(file_version);
1111 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001112 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001113 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001114 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001115 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001116 rc = parse_sdp_header(sw);
1117 if (rc < 0) {
1118 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1119 return -1;
1120 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001121
1122 strcpy((char *)sw->file_id, "id");
1123 sw->file_id_len = 3;
1124 strcpy((char *)sw->file_version, "version");
1125 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001126 break;
Harald Welte4724f992009-01-18 18:01:49 +00001127 default:
1128 /* We don't know how to treat them yet */
1129 close(sw->fd);
1130 return -EINVAL;
1131 }
1132
1133 return 0;
1134}
1135
1136static void sw_close_file(struct abis_nm_sw *sw)
1137{
1138 switch (sw->bts->type) {
1139 case GSM_BTS_TYPE_BS11:
1140 fclose(sw->stream);
1141 break;
1142 default:
1143 close(sw->fd);
1144 break;
1145 }
1146}
1147
1148/* Fill the window */
1149static int sw_fill_window(struct abis_nm_sw *sw)
1150{
1151 int rc;
1152
1153 while (sw->seg_in_window < sw->window_size) {
1154 rc = sw_load_segment(sw);
1155 if (rc < 0)
1156 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001157 if (sw->last_seg)
1158 break;
Harald Welte4724f992009-01-18 18:01:49 +00001159 }
1160 return 0;
1161}
1162
1163/* callback function from abis_nm_rcvmsg() handler */
1164static int abis_nm_rcvmsg_sw(struct msgb *mb)
1165{
1166 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1167 int rc = -1;
1168 struct abis_nm_sw *sw = &g_sw;
1169 enum sw_state old_state = sw->state;
1170
Harald Welte3ffd1372009-02-01 22:15:49 +00001171 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001172
1173 switch (sw->state) {
1174 case SW_STATE_WAIT_INITACK:
1175 switch (foh->msg_type) {
1176 case NM_MT_LOAD_INIT_ACK:
1177 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001178 if (sw->cbfn)
1179 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1180 NM_MT_LOAD_INIT_ACK, mb,
1181 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001182 rc = sw_fill_window(sw);
1183 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001184 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001185 break;
1186 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001187 if (sw->forced) {
1188 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1189 "Init NACK\n");
1190 if (sw->cbfn)
1191 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1192 NM_MT_LOAD_INIT_ACK, mb,
1193 sw->cb_data, NULL);
1194 rc = sw_fill_window(sw);
1195 sw->state = SW_STATE_WAIT_SEGACK;
1196 } else {
1197 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001198 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001199 if (sw->cbfn)
1200 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1201 NM_MT_LOAD_INIT_NACK, mb,
1202 sw->cb_data, NULL);
1203 sw->state = SW_STATE_ERROR;
1204 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001205 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001206 break;
1207 }
1208 break;
1209 case SW_STATE_WAIT_SEGACK:
1210 switch (foh->msg_type) {
1211 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001212 if (sw->cbfn)
1213 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1214 NM_MT_LOAD_SEG_ACK, mb,
1215 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001216 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001217 if (!sw->last_seg) {
1218 /* fill window with more segments */
1219 rc = sw_fill_window(sw);
1220 sw->state = SW_STATE_WAIT_SEGACK;
1221 } else {
1222 /* end the transfer */
1223 sw->state = SW_STATE_WAIT_ENDACK;
1224 rc = sw_load_end(sw);
1225 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001226 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001227 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001228 case NM_MT_LOAD_ABORT:
1229 if (sw->cbfn)
1230 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1231 NM_MT_LOAD_ABORT, mb,
1232 sw->cb_data, NULL);
1233 break;
Harald Welte4724f992009-01-18 18:01:49 +00001234 }
1235 break;
1236 case SW_STATE_WAIT_ENDACK:
1237 switch (foh->msg_type) {
1238 case NM_MT_LOAD_END_ACK:
1239 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001240 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1241 sw->bts->nr);
1242 sw->state = SW_STATE_NONE;
1243 if (sw->cbfn)
1244 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1245 NM_MT_LOAD_END_ACK, mb,
1246 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001247 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001248 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001249 break;
1250 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001251 if (sw->forced) {
1252 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1253 "End NACK\n");
1254 sw->state = SW_STATE_NONE;
1255 if (sw->cbfn)
1256 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1257 NM_MT_LOAD_END_ACK, mb,
1258 sw->cb_data, NULL);
1259 } else {
1260 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001261 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001262 sw->state = SW_STATE_ERROR;
1263 if (sw->cbfn)
1264 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1265 NM_MT_LOAD_END_NACK, mb,
1266 sw->cb_data, NULL);
1267 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001268 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001269 break;
1270 }
1271 case SW_STATE_WAIT_ACTACK:
1272 switch (foh->msg_type) {
1273 case NM_MT_ACTIVATE_SW_ACK:
1274 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001275 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001276 sw->state = SW_STATE_NONE;
1277 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001278 if (sw->cbfn)
1279 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1280 NM_MT_ACTIVATE_SW_ACK, mb,
1281 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001282 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001283 break;
1284 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001285 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001286 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001287 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001288 if (sw->cbfn)
1289 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1290 NM_MT_ACTIVATE_SW_NACK, mb,
1291 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001292 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001293 break;
1294 }
1295 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001296 switch (foh->msg_type) {
1297 case NM_MT_ACTIVATE_SW_ACK:
1298 rc = 0;
1299 break;
1300 }
1301 break;
Harald Welte4724f992009-01-18 18:01:49 +00001302 case SW_STATE_ERROR:
1303 break;
1304 }
1305
1306 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001307 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001308 foh->msg_type, old_state, sw->state);
1309
1310 return rc;
1311}
1312
1313/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001314int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001315 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001316 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001317{
1318 struct abis_nm_sw *sw = &g_sw;
1319 int rc;
1320
Harald Welte5e4d1b32009-02-01 13:36:56 +00001321 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1322 bts->nr, fname);
1323
Harald Welte4724f992009-01-18 18:01:49 +00001324 if (sw->state != SW_STATE_NONE)
1325 return -EBUSY;
1326
1327 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001328 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001329
1330 switch (bts->type) {
1331 case GSM_BTS_TYPE_BS11:
1332 sw->obj_class = NM_OC_SITE_MANAGER;
1333 sw->obj_instance[0] = 0xff;
1334 sw->obj_instance[1] = 0xff;
1335 sw->obj_instance[2] = 0xff;
1336 break;
1337 case GSM_BTS_TYPE_NANOBTS:
1338 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001339 sw->obj_instance[0] = sw->bts->nr;
1340 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001341 sw->obj_instance[2] = 0xff;
1342 break;
1343 case GSM_BTS_TYPE_UNKNOWN:
1344 default:
1345 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1346 return -1;
1347 break;
1348 }
Harald Welte4724f992009-01-18 18:01:49 +00001349 sw->window_size = win_size;
1350 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001351 sw->cbfn = cbfn;
1352 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001353 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001354
1355 rc = sw_open_file(sw, fname);
1356 if (rc < 0) {
1357 sw->state = SW_STATE_NONE;
1358 return rc;
1359 }
1360
1361 return sw_load_init(sw);
1362}
Harald Welte52b1f982008-12-23 20:25:15 +00001363
Harald Welte1602ade2009-01-29 21:12:39 +00001364int abis_nm_software_load_status(struct gsm_bts *bts)
1365{
1366 struct abis_nm_sw *sw = &g_sw;
1367 struct stat st;
1368 int rc, percent;
1369
1370 rc = fstat(sw->fd, &st);
1371 if (rc < 0) {
1372 perror("ERROR during stat");
1373 return rc;
1374 }
1375
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001376 if (sw->stream)
1377 percent = (ftell(sw->stream) * 100) / st.st_size;
1378 else
1379 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001380 return percent;
1381}
1382
Harald Welte5e4d1b32009-02-01 13:36:56 +00001383/* Activate the specified software into the BTS */
1384int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1385 gsm_cbfn *cbfn, void *cb_data)
1386{
1387 struct abis_nm_sw *sw = &g_sw;
1388 int rc;
1389
1390 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1391 bts->nr, fname);
1392
1393 if (sw->state != SW_STATE_NONE)
1394 return -EBUSY;
1395
1396 sw->bts = bts;
1397 sw->obj_class = NM_OC_SITE_MANAGER;
1398 sw->obj_instance[0] = 0xff;
1399 sw->obj_instance[1] = 0xff;
1400 sw->obj_instance[2] = 0xff;
1401 sw->state = SW_STATE_WAIT_ACTACK;
1402 sw->cbfn = cbfn;
1403 sw->cb_data = cb_data;
1404
1405 /* Open the file in order to fill some sw struct members */
1406 rc = sw_open_file(sw, fname);
1407 if (rc < 0) {
1408 sw->state = SW_STATE_NONE;
1409 return rc;
1410 }
1411 sw_close_file(sw);
1412
1413 return sw_activate(sw);
1414}
1415
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001416static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1417 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001418{
Harald Welteadaf08b2009-01-18 11:08:10 +00001419 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001420 ch->bts_port = bts_port;
1421 ch->timeslot = ts_nr;
1422 ch->subslot = subslot_nr;
1423}
1424
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001425int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1426 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1427 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001428{
1429 struct abis_om_hdr *oh;
1430 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001431 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001432 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001433
1434 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1435 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1436 bts->bts_nr, trx_nr, 0xff);
1437
Harald Welte8470bf22008-12-25 23:28:35 +00001438 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001439
1440 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1441 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1442
1443 return abis_nm_sendmsg(bts, msg);
1444}
1445
1446/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1447int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001448 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001449{
Harald Welte8470bf22008-12-25 23:28:35 +00001450 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001451 struct abis_om_hdr *oh;
1452 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001453 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001454
1455 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001456 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001457 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1458
1459 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1460 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1461
1462 return abis_nm_sendmsg(bts, msg);
1463}
1464
1465#if 0
1466int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1467 struct abis_nm_abis_channel *chan)
1468{
1469}
1470#endif
1471
1472int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001473 uint8_t e1_port, uint8_t e1_timeslot,
1474 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001475{
1476 struct gsm_bts *bts = ts->trx->bts;
1477 struct abis_om_hdr *oh;
1478 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001479 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001480
1481 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1482 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001483 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001484
1485 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1486 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1487
Harald Weltef325eb42009-02-19 17:07:39 +00001488 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1489 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001490 e1_port, e1_timeslot, e1_subslot);
1491
Harald Welte52b1f982008-12-23 20:25:15 +00001492 return abis_nm_sendmsg(bts, msg);
1493}
1494
1495#if 0
1496int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1497 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001498 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001499{
1500}
1501#endif
1502
Harald Welte22af0db2009-02-14 15:41:08 +00001503/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001504int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001505{
1506 struct abis_om_hdr *oh;
1507 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001508 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001509
1510 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1511
1512 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001513 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 +00001514 cur = msgb_put(msg, attr_len);
1515 memcpy(cur, attr, attr_len);
1516
1517 return abis_nm_sendmsg(bts, msg);
1518}
1519
1520/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001521int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001522{
1523 struct abis_om_hdr *oh;
1524 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001525 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001526
1527 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1528
1529 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1530 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001531 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001532 cur = msgb_put(msg, attr_len);
1533 memcpy(cur, attr, attr_len);
1534
1535 return abis_nm_sendmsg(trx->bts, msg);
1536}
1537
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001538static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001539{
1540 int i;
1541
1542 /* As it turns out, the BS-11 has some very peculiar restrictions
1543 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301544 switch (ts->trx->bts->type) {
1545 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001546 switch (chan_comb) {
1547 case NM_CHANC_TCHHalf:
1548 case NM_CHANC_TCHHalf2:
1549 /* not supported */
1550 return -EINVAL;
1551 case NM_CHANC_SDCCH:
1552 /* only one SDCCH/8 per TRX */
1553 for (i = 0; i < TRX_NR_TS; i++) {
1554 if (i == ts->nr)
1555 continue;
1556 if (ts->trx->ts[i].nm_chan_comb ==
1557 NM_CHANC_SDCCH)
1558 return -EINVAL;
1559 }
1560 /* not allowed for TS0 of BCCH-TRX */
1561 if (ts->trx == ts->trx->bts->c0 &&
1562 ts->nr == 0)
1563 return -EINVAL;
1564 /* not on the same TRX that has a BCCH+SDCCH4
1565 * combination */
1566 if (ts->trx == ts->trx->bts->c0 &&
1567 (ts->trx->ts[0].nm_chan_comb == 5 ||
1568 ts->trx->ts[0].nm_chan_comb == 8))
1569 return -EINVAL;
1570 break;
1571 case NM_CHANC_mainBCCH:
1572 case NM_CHANC_BCCHComb:
1573 /* allowed only for TS0 of C0 */
1574 if (ts->trx != ts->trx->bts->c0 ||
1575 ts->nr != 0)
1576 return -EINVAL;
1577 break;
1578 case NM_CHANC_BCCH:
1579 /* allowed only for TS 2/4/6 of C0 */
1580 if (ts->trx != ts->trx->bts->c0)
1581 return -EINVAL;
1582 if (ts->nr != 2 && ts->nr != 4 &&
1583 ts->nr != 6)
1584 return -EINVAL;
1585 break;
1586 case 8: /* this is not like 08.58, but in fact
1587 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1588 /* FIXME: only one CBCH allowed per cell */
1589 break;
1590 }
Harald Welted6575f92009-12-02 02:45:23 +05301591 break;
1592 case GSM_BTS_TYPE_NANOBTS:
1593 switch (ts->nr) {
1594 case 0:
1595 if (ts->trx->nr == 0) {
1596 /* only on TRX0 */
1597 switch (chan_comb) {
1598 case NM_CHANC_BCCH:
1599 case NM_CHANC_mainBCCH:
1600 case NM_CHANC_BCCHComb:
1601 return 0;
1602 break;
1603 default:
1604 return -EINVAL;
1605 }
1606 } else {
1607 switch (chan_comb) {
1608 case NM_CHANC_TCHFull:
1609 case NM_CHANC_TCHHalf:
1610 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1611 return 0;
1612 default:
1613 return -EINVAL;
1614 }
1615 }
1616 break;
1617 case 1:
1618 if (ts->trx->nr == 0) {
1619 switch (chan_comb) {
1620 case NM_CHANC_SDCCH_CBCH:
1621 if (ts->trx->ts[0].nm_chan_comb ==
1622 NM_CHANC_mainBCCH)
1623 return 0;
1624 return -EINVAL;
1625 case NM_CHANC_SDCCH:
1626 case NM_CHANC_TCHFull:
1627 case NM_CHANC_TCHHalf:
1628 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1629 case NM_CHANC_IPAC_TCHFull_PDCH:
1630 return 0;
1631 }
1632 } else {
1633 switch (chan_comb) {
1634 case NM_CHANC_SDCCH:
1635 case NM_CHANC_TCHFull:
1636 case NM_CHANC_TCHHalf:
1637 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1638 return 0;
1639 default:
1640 return -EINVAL;
1641 }
1642 }
1643 break;
1644 case 2:
1645 case 3:
1646 case 4:
1647 case 5:
1648 case 6:
1649 case 7:
1650 switch (chan_comb) {
1651 case NM_CHANC_TCHFull:
1652 case NM_CHANC_TCHHalf:
1653 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1654 return 0;
1655 case NM_CHANC_IPAC_PDCH:
1656 case NM_CHANC_IPAC_TCHFull_PDCH:
1657 if (ts->trx->nr == 0)
1658 return 0;
1659 else
1660 return -EINVAL;
1661 }
1662 break;
1663 }
1664 return -EINVAL;
1665 default:
1666 /* unknown BTS type */
1667 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001668 }
1669 return 0;
1670}
1671
Harald Welte22af0db2009-02-14 15:41:08 +00001672/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001673int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001674{
1675 struct gsm_bts *bts = ts->trx->bts;
1676 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001677 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001678 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001679 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00001680
1681 if (bts->type == GSM_BTS_TYPE_BS11)
1682 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001683
Harald Weltef325eb42009-02-19 17:07:39 +00001684 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001685 if (verify_chan_comb(ts, chan_comb) < 0) {
1686 msgb_free(msg);
1687 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1688 return -EINVAL;
1689 }
1690 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001691
Harald Welte52b1f982008-12-23 20:25:15 +00001692 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001693 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001694 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001695 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001696 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001697 if (ts->hopping.enabled) {
1698 unsigned int i;
1699 uint8_t *len;
1700
Harald Welte6e0cd042009-09-12 13:05:33 +02001701 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1702 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001703
1704 /* build the ARFCN list */
1705 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1706 len = msgb_put(msg, 1);
1707 *len = 0;
1708 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1709 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1710 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001711 /* At least BS-11 wants a TLV16 here */
1712 if (bts->type == GSM_BTS_TYPE_BS11)
1713 *len += 1;
1714 else
1715 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001716 }
1717 }
Harald Weltee0590df2009-02-15 03:34:15 +00001718 }
Harald Weltee6c22d92009-07-21 20:40:05 +02001719 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001720 if (bts->type == GSM_BTS_TYPE_BS11)
1721 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001722
1723 return abis_nm_sendmsg(bts, msg);
1724}
1725
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001726int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1727 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001728{
1729 struct abis_om_hdr *oh;
1730 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001731 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1732 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001733
1734 if (nack) {
1735 len += 2;
1736 msgtype = NM_MT_SW_ACT_REQ_NACK;
1737 }
Harald Welte34a99682009-02-13 02:41:40 +00001738
1739 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001740 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1741
Harald Welte34a99682009-02-13 02:41:40 +00001742 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001743 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001744 memcpy(ptr, attr, att_len);
1745 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001746 if (nack)
1747 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001748
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001749 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001750}
1751
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001752int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001753{
Harald Welte8470bf22008-12-25 23:28:35 +00001754 struct msgb *msg = nm_msgb_alloc();
1755 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001756 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001757
1758 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1759 fill_om_hdr(oh, len);
1760 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001761 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001762
1763 return abis_nm_sendmsg(bts, msg);
1764}
1765
1766/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001767static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001768{
1769 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001770 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001771
1772 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001773 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001774 0xff, 0xff, 0xff);
1775
1776 return abis_nm_sendmsg(bts, msg);
1777}
1778
Harald Welte34a99682009-02-13 02:41:40 +00001779/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001780int 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 +00001781{
1782 struct abis_om_hdr *oh;
1783 struct msgb *msg = nm_msgb_alloc();
1784
1785 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1786 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1787
Harald Welte15c61722011-05-22 22:45:37 +02001788 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001789 DEBUGPC(DNM, "Sending OPSTART\n");
1790
Harald Welte34a99682009-02-13 02:41:40 +00001791 return abis_nm_sendmsg(bts, msg);
1792}
1793
1794/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001795int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1796 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001797{
1798 struct abis_om_hdr *oh;
1799 struct msgb *msg = nm_msgb_alloc();
1800
1801 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1802 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1803 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1804
1805 return abis_nm_sendmsg(bts, msg);
1806}
1807
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001808int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1809 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001810{
1811 struct abis_om_hdr *oh;
1812 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001813 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001814
1815 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1816 e1_port0, ts0, e1_port1, ts1);
1817
1818 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1819 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1820 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1821
1822 attr = msgb_put(msg, 3);
1823 attr[0] = NM_ATT_MDROP_LINK;
1824 attr[1] = e1_port0;
1825 attr[2] = ts0;
1826
1827 attr = msgb_put(msg, 3);
1828 attr[0] = NM_ATT_MDROP_NEXT;
1829 attr[1] = e1_port1;
1830 attr[2] = ts1;
1831
1832 return abis_nm_sendmsg(bts, msg);
1833}
Harald Welte34a99682009-02-13 02:41:40 +00001834
Harald Weltec7310382009-08-08 00:02:36 +02001835/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001836int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1837 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1838 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001839{
1840 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001841
Harald Welte15c61722011-05-22 22:45:37 +02001842 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001843
1844 if (!msg)
1845 msg = nm_msgb_alloc();
1846
1847 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1848 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1849 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1850 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001851 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001852
1853 return abis_nm_sendmsg(bts, msg);
1854}
1855
Harald Welte52b1f982008-12-23 20:25:15 +00001856int abis_nm_event_reports(struct gsm_bts *bts, int on)
1857{
1858 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001859 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001860 else
Harald Welte227d4072009-01-03 08:16:25 +00001861 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001862}
1863
Harald Welte47d88ae2009-01-04 12:02:08 +00001864/* Siemens (or BS-11) specific commands */
1865
Harald Welte3ffd1372009-02-01 22:15:49 +00001866int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1867{
1868 if (reconnect == 0)
1869 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1870 else
1871 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1872}
1873
Harald Welteb8427972009-02-05 19:27:17 +00001874int abis_nm_bs11_restart(struct gsm_bts *bts)
1875{
1876 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1877}
1878
1879
Harald Welte268bb402009-02-01 19:11:56 +00001880struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001881 uint16_t year;
1882 uint8_t month;
1883 uint8_t day;
1884 uint8_t hour;
1885 uint8_t min;
1886 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001887} __attribute__((packed));
1888
1889
1890void get_bs11_date_time(struct bs11_date_time *aet)
1891{
1892 time_t t;
1893 struct tm *tm;
1894
1895 t = time(NULL);
1896 tm = localtime(&t);
1897 aet->sec = tm->tm_sec;
1898 aet->min = tm->tm_min;
1899 aet->hour = tm->tm_hour;
1900 aet->day = tm->tm_mday;
1901 aet->month = tm->tm_mon;
1902 aet->year = htons(1900 + tm->tm_year);
1903}
1904
Harald Welte05188ee2009-01-18 11:39:08 +00001905int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001906{
Harald Welte4668fda2009-01-03 08:19:29 +00001907 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001908}
1909
Harald Welte05188ee2009-01-18 11:39:08 +00001910int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001911{
1912 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001913 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001914 else
Harald Welte4668fda2009-01-03 08:19:29 +00001915 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001916}
Harald Welte47d88ae2009-01-04 12:02:08 +00001917
Harald Welte05188ee2009-01-18 11:39:08 +00001918int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001919 enum abis_bs11_objtype type, uint8_t idx,
1920 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001921{
1922 struct abis_om_hdr *oh;
1923 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001924 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001925
1926 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001927 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001928 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001929 cur = msgb_put(msg, attr_len);
1930 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001931
1932 return abis_nm_sendmsg(bts, msg);
1933}
1934
Harald Welte78fc0d42009-02-19 02:50:57 +00001935int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001936 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001937{
1938 struct abis_om_hdr *oh;
1939 struct msgb *msg = nm_msgb_alloc();
1940
1941 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1942 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1943 NM_OC_BS11, type, 0, idx);
1944
1945 return abis_nm_sendmsg(bts, msg);
1946}
1947
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001948int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001949{
1950 struct abis_om_hdr *oh;
1951 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001952 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001953
1954 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001955 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001956 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1957 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001958
1959 return abis_nm_sendmsg(bts, msg);
1960}
1961
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001962int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001963{
1964 struct abis_om_hdr *oh;
1965 struct msgb *msg = nm_msgb_alloc();
1966
1967 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1968 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001969 idx, 0xff, 0xff);
1970
1971 return abis_nm_sendmsg(bts, msg);
1972}
1973
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001974int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001975{
1976 struct abis_om_hdr *oh;
1977 struct msgb *msg = nm_msgb_alloc();
1978
1979 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1980 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1981 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001982
1983 return abis_nm_sendmsg(bts, msg);
1984}
Harald Welte05188ee2009-01-18 11:39:08 +00001985
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001986static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001987int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1988{
1989 struct abis_om_hdr *oh;
1990 struct msgb *msg = nm_msgb_alloc();
1991
1992 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1993 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1994 0xff, 0xff, 0xff);
1995 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1996
1997 return abis_nm_sendmsg(bts, msg);
1998}
1999
Harald Welteb6c92ae2009-02-21 20:15:32 +00002000/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002001int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2002 uint8_t e1_timeslot, uint8_t e1_subslot,
2003 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002004{
2005 struct abis_om_hdr *oh;
2006 struct abis_nm_channel *ch;
2007 struct msgb *msg = nm_msgb_alloc();
2008
2009 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002010 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002011 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2012
2013 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2014 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002015 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002016
2017 return abis_nm_sendmsg(bts, msg);
2018}
2019
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002020int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002021{
2022 struct abis_om_hdr *oh;
2023 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002024
2025 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002026 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002027 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2028 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2029
2030 return abis_nm_sendmsg(trx->bts, msg);
2031}
2032
Harald Welte78fc0d42009-02-19 02:50:57 +00002033int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2034{
2035 struct abis_om_hdr *oh;
2036 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002037 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002038
2039 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2040 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2041 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2042 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2043
2044 return abis_nm_sendmsg(trx->bts, msg);
2045}
2046
Harald Welteaaf02d92009-04-29 13:25:57 +00002047int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2048{
2049 struct abis_om_hdr *oh;
2050 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002051 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002052
2053 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2054 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2055 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002056 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002057
2058 return abis_nm_sendmsg(bts, msg);
2059}
2060
Harald Welteef061952009-05-17 12:43:42 +00002061int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2062{
2063 struct abis_om_hdr *oh;
2064 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002065 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002066 NM_ATT_BS11_CCLK_TYPE };
2067
2068 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2069 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2070 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2071 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2072
2073 return abis_nm_sendmsg(bts, msg);
2074
2075}
Harald Welteaaf02d92009-04-29 13:25:57 +00002076
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002077//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002078
Harald Welte1bc09062009-01-18 14:17:52 +00002079int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002080{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002081 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2082}
2083
Daniel Willmann4b054c82010-01-07 00:46:26 +01002084int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2085{
2086 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2087}
2088
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002089int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002090{
Harald Welte05188ee2009-01-18 11:39:08 +00002091 struct abis_om_hdr *oh;
2092 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002093 struct bs11_date_time bdt;
2094
2095 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002096
2097 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002098 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002099 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002100 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002101 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002102 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002103 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002104 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002105 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002106 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002107 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002108 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002109 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002110 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002111 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002112 }
Harald Welte05188ee2009-01-18 11:39:08 +00002113
2114 return abis_nm_sendmsg(bts, msg);
2115}
Harald Welte1bc09062009-01-18 14:17:52 +00002116
2117int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2118{
2119 struct abis_om_hdr *oh;
2120 struct msgb *msg;
2121
2122 if (strlen(password) != 10)
2123 return -EINVAL;
2124
2125 msg = nm_msgb_alloc();
2126 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002127 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002128 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002129 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002130
2131 return abis_nm_sendmsg(bts, msg);
2132}
2133
Harald Weltee69f5fb2009-04-28 16:31:38 +00002134/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2135int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2136{
2137 struct abis_om_hdr *oh;
2138 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002139 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002140
2141 msg = nm_msgb_alloc();
2142 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2143 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2144 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002145
2146 if (locked)
2147 tlv_value = BS11_LI_PLL_LOCKED;
2148 else
2149 tlv_value = BS11_LI_PLL_STANDALONE;
2150
2151 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002152
2153 return abis_nm_sendmsg(bts, msg);
2154}
2155
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002156/* Set the calibration value of the PLL (work value/set value)
2157 * It depends on the login which one is changed */
2158int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2159{
2160 struct abis_om_hdr *oh;
2161 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002162 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002163
2164 msg = nm_msgb_alloc();
2165 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2166 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2167 BS11_OBJ_TRX1, 0x00, 0x00);
2168
2169 tlv_value[0] = value>>8;
2170 tlv_value[1] = value&0xff;
2171
2172 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2173
2174 return abis_nm_sendmsg(bts, msg);
2175}
2176
Harald Welte1bc09062009-01-18 14:17:52 +00002177int abis_nm_bs11_get_state(struct gsm_bts *bts)
2178{
2179 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2180}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002181
2182/* BS11 SWL */
2183
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002184void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002185
Harald Welte5e4d1b32009-02-01 13:36:56 +00002186struct abis_nm_bs11_sw {
2187 struct gsm_bts *bts;
2188 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002189 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002190 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002191 struct llist_head file_list;
2192 gsm_cbfn *user_cb; /* specified by the user */
2193};
2194static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2195
2196struct file_list_entry {
2197 struct llist_head list;
2198 char fname[PATH_MAX];
2199};
2200
2201struct file_list_entry *fl_dequeue(struct llist_head *queue)
2202{
2203 struct llist_head *lh;
2204
2205 if (llist_empty(queue))
2206 return NULL;
2207
2208 lh = queue->next;
2209 llist_del(lh);
2210
2211 return llist_entry(lh, struct file_list_entry, list);
2212}
2213
2214static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2215{
2216 char linebuf[255];
2217 struct llist_head *lh, *lh2;
2218 FILE *swl;
2219 int rc = 0;
2220
2221 swl = fopen(bs11_sw->swl_fname, "r");
2222 if (!swl)
2223 return -ENODEV;
2224
2225 /* zero the stale file list, if any */
2226 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2227 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002228 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002229 }
2230
2231 while (fgets(linebuf, sizeof(linebuf), swl)) {
2232 char file_id[12+1];
2233 char file_version[80+1];
2234 struct file_list_entry *fle;
2235 static char dir[PATH_MAX];
2236
2237 if (strlen(linebuf) < 4)
2238 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002239
Harald Welte5e4d1b32009-02-01 13:36:56 +00002240 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2241 if (rc < 0) {
2242 perror("ERR parsing SWL file");
2243 rc = -EINVAL;
2244 goto out;
2245 }
2246 if (rc < 2)
2247 continue;
2248
Harald Welte470ec292009-06-26 20:25:23 +02002249 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002250 if (!fle) {
2251 rc = -ENOMEM;
2252 goto out;
2253 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002254
2255 /* construct new filename */
2256 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2257 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2258 strcat(fle->fname, "/");
2259 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002260
2261 llist_add_tail(&fle->list, &bs11_sw->file_list);
2262 }
2263
2264out:
2265 fclose(swl);
2266 return rc;
2267}
2268
2269/* bs11 swload specific callback, passed to abis_nm core swload */
2270static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2271 struct msgb *msg, void *data, void *param)
2272{
2273 struct abis_nm_bs11_sw *bs11_sw = data;
2274 struct file_list_entry *fle;
2275 int rc = 0;
2276
Harald Welte5e4d1b32009-02-01 13:36:56 +00002277 switch (event) {
2278 case NM_MT_LOAD_END_ACK:
2279 fle = fl_dequeue(&bs11_sw->file_list);
2280 if (fle) {
2281 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002282 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002283 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002284 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002285 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002286 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002287 } else {
2288 /* activate the SWL */
2289 rc = abis_nm_software_activate(bs11_sw->bts,
2290 bs11_sw->swl_fname,
2291 bs11_swload_cbfn,
2292 bs11_sw);
2293 }
2294 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002295 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002296 case NM_MT_LOAD_END_NACK:
2297 case NM_MT_LOAD_INIT_ACK:
2298 case NM_MT_LOAD_INIT_NACK:
2299 case NM_MT_ACTIVATE_SW_NACK:
2300 case NM_MT_ACTIVATE_SW_ACK:
2301 default:
2302 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002303 if (bs11_sw->user_cb)
2304 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002305 break;
2306 }
2307
2308 return rc;
2309}
2310
2311/* Siemens provides a SWL file that is a mere listing of all the other
2312 * files that are part of a software release. We need to upload first
2313 * the list file, and then each file that is listed in the list file */
2314int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002315 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002316{
2317 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2318 struct file_list_entry *fle;
2319 int rc = 0;
2320
2321 INIT_LLIST_HEAD(&bs11_sw->file_list);
2322 bs11_sw->bts = bts;
2323 bs11_sw->win_size = win_size;
2324 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002325 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002326
2327 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2328 rc = bs11_read_swl_file(bs11_sw);
2329 if (rc < 0)
2330 return rc;
2331
2332 /* dequeue next item in file list */
2333 fle = fl_dequeue(&bs11_sw->file_list);
2334 if (!fle)
2335 return -EINVAL;
2336
2337 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002338 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002339 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002340 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002341 return rc;
2342}
2343
Harald Welte5083b0b2009-02-02 19:20:52 +00002344#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002345static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002346 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2347 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2348 NM_ATT_BS11_LMT_USER_NAME,
2349
2350 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2351
2352 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2353
2354 NM_ATT_BS11_SW_LOAD_STORED };
2355
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002356static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002357 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2358 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2359 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2360 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002361#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002362
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002363static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002364 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2365 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002366 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002367
2368int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2369{
2370 struct abis_om_hdr *oh;
2371 struct msgb *msg = nm_msgb_alloc();
2372
2373 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2374 /* SiemensHW CCTRL object */
2375 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2376 0x03, 0x00, 0x00);
2377 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2378
2379 return abis_nm_sendmsg(bts, msg);
2380}
Harald Welte268bb402009-02-01 19:11:56 +00002381
2382int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2383{
2384 struct abis_om_hdr *oh;
2385 struct msgb *msg = nm_msgb_alloc();
2386 struct bs11_date_time aet;
2387
2388 get_bs11_date_time(&aet);
2389 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2390 /* SiemensHW CCTRL object */
2391 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2392 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002393 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002394
2395 return abis_nm_sendmsg(bts, msg);
2396}
Harald Welte5c1e4582009-02-15 11:57:29 +00002397
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002398int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002399{
2400 struct abis_om_hdr *oh;
2401 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002402 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002403
2404 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2405 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2406 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2407 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2408
2409 return abis_nm_sendmsg(bts, msg);
2410}
2411
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002412int 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 +02002413{
2414 struct abis_om_hdr *oh;
2415 struct msgb *msg = nm_msgb_alloc();
2416 struct bs11_date_time aet;
2417
2418 get_bs11_date_time(&aet);
2419 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2420 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2421 bport, 0xff, 0x02);
2422 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2423
2424 return abis_nm_sendmsg(bts, msg);
2425}
2426
Harald Welte5c1e4582009-02-15 11:57:29 +00002427/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002428static const char ipaccess_magic[] = "com.ipaccess";
2429
Harald Welte677c21f2009-02-17 13:22:23 +00002430
2431static int abis_nm_rx_ipacc(struct msgb *msg)
2432{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002433 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002434 struct abis_om_hdr *oh = msgb_l2(msg);
2435 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002436 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002437 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002438 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002439
2440 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002441 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002442 return -EINVAL;
2443 }
2444
Harald Welte193fefc2009-04-30 15:16:27 +00002445 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002446 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002447
Harald Welte15c61722011-05-22 22:45:37 +02002448 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002449
Harald Welte746d6092009-10-19 22:11:11 +02002450 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002451
Harald Welte677c21f2009-02-17 13:22:23 +00002452 switch (foh->msg_type) {
2453 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002454 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002455 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2456 memcpy(&addr,
2457 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2458
2459 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2460 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002461 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002462 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002463 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002464 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002465 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2466 DEBUGPC(DNM, "STREAM=0x%02x ",
2467 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002468 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002469 break;
2470 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002471 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002472 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002473 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002474 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002475 else
2476 DEBUGPC(DNM, "\n");
2477 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002478 case NM_MT_IPACC_SET_NVATTR_ACK:
2479 DEBUGPC(DNM, "SET NVATTR ACK\n");
2480 /* FIXME: decode and show the actual attributes */
2481 break;
2482 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002483 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002484 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002485 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002486 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002487 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002488 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002489 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002490 case NM_MT_IPACC_GET_NVATTR_ACK:
2491 DEBUGPC(DNM, "GET NVATTR ACK\n");
2492 /* FIXME: decode and show the actual attributes */
2493 break;
2494 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002495 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002496 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002497 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002498 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002499 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002500 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002501 break;
Harald Welte15c44172009-10-08 20:15:24 +02002502 case NM_MT_IPACC_SET_ATTR_ACK:
2503 DEBUGPC(DNM, "SET ATTR ACK\n");
2504 break;
2505 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002506 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002507 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002508 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002509 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002510 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002511 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002512 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002513 default:
2514 DEBUGPC(DNM, "unknown\n");
2515 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002516 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002517
2518 /* signal handling */
2519 switch (foh->msg_type) {
2520 case NM_MT_IPACC_RSL_CONNECT_NACK:
2521 case NM_MT_IPACC_SET_NVATTR_NACK:
2522 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002523 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002524 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002525 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002526 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002527 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002528 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002529 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002530 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002531 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002532 default:
2533 break;
2534 }
2535
Harald Welte677c21f2009-02-17 13:22:23 +00002536 return 0;
2537}
2538
Harald Welte193fefc2009-04-30 15:16:27 +00002539/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002540int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2541 uint8_t obj_class, uint8_t bts_nr,
2542 uint8_t trx_nr, uint8_t ts_nr,
2543 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002544{
2545 struct msgb *msg = nm_msgb_alloc();
2546 struct abis_om_hdr *oh;
2547 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002548 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002549
2550 /* construct the 12.21 OM header, observe the erroneous length */
2551 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2552 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2553 oh->mdisc = ABIS_OM_MDISC_MANUF;
2554
2555 /* add the ip.access magic */
2556 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2557 *data++ = sizeof(ipaccess_magic);
2558 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2559
2560 /* fill the 12.21 FOM header */
2561 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2562 foh->msg_type = msg_type;
2563 foh->obj_class = obj_class;
2564 foh->obj_inst.bts_nr = bts_nr;
2565 foh->obj_inst.trx_nr = trx_nr;
2566 foh->obj_inst.ts_nr = ts_nr;
2567
2568 if (attr && attr_len) {
2569 data = msgb_put(msg, attr_len);
2570 memcpy(data, attr, attr_len);
2571 }
2572
2573 return abis_nm_sendmsg(bts, msg);
2574}
Harald Welte677c21f2009-02-17 13:22:23 +00002575
Harald Welte193fefc2009-04-30 15:16:27 +00002576/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002577int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002578 int attr_len)
2579{
Harald Welte2ef156d2010-01-07 20:39:42 +01002580 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2581 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002582 attr_len);
2583}
2584
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002585int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002586 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002587{
2588 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002589 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002590 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2591 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2592
2593 int attr_len = sizeof(attr);
2594
2595 ia.s_addr = htonl(ip);
2596 attr[1] = stream;
2597 attr[3] = port >> 8;
2598 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002599 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002600
2601 /* if ip == 0, we use the default IP */
2602 if (ip == 0)
2603 attr_len -= 5;
2604
2605 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002606 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002607
2608 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2609 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2610 trx->nr, 0xff, attr, attr_len);
2611}
2612
Harald Welte193fefc2009-04-30 15:16:27 +00002613/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002614int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002615{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002616 struct abis_om_hdr *oh;
2617 struct msgb *msg = nm_msgb_alloc();
2618
2619 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2620 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2621 trx->bts->nr, trx->nr, 0xff);
2622
2623 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002624}
Harald Weltedaef5212009-10-24 10:20:41 +02002625
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002626int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2627 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2628 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002629{
2630 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2631 obj_class, bts_nr, trx_nr, ts_nr,
2632 attr, attr_len);
2633}
Harald Welte0f255852009-11-12 14:48:42 +01002634
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002635void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002636{
2637 /* we simply reuse the GSM48 function and overwrite the RAC
2638 * with the Cell ID */
2639 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002640 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002641}
2642
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002643void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2644{
2645 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2646
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002647 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002648 if (!trx->bts || !trx->bts->oml_link)
2649 return;
2650
2651 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2652 trx->bts->bts_nr, trx->nr, 0xff,
2653 new_state);
2654}
2655
Harald Welte92b1fe42010-03-25 11:45:30 +08002656static const struct value_string ipacc_testres_names[] = {
2657 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2658 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2659 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2660 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2661 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2662 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002663};
2664
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002665const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002666{
Harald Welte92b1fe42010-03-25 11:45:30 +08002667 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002668}
2669
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002670void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002671{
2672 cid->mcc = (buf[0] & 0xf) * 100;
2673 cid->mcc += (buf[0] >> 4) * 10;
2674 cid->mcc += (buf[1] & 0xf) * 1;
2675
2676 if (buf[1] >> 4 == 0xf) {
2677 cid->mnc = (buf[2] & 0xf) * 10;
2678 cid->mnc += (buf[2] >> 4) * 1;
2679 } else {
2680 cid->mnc = (buf[2] & 0xf) * 100;
2681 cid->mnc += (buf[2] >> 4) * 10;
2682 cid->mnc += (buf[1] >> 4) * 1;
2683 }
2684
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002685 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2686 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002687}
2688
Harald Welte0f255852009-11-12 14:48:42 +01002689/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002690int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002691{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002692 uint8_t *cur = buf;
2693 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01002694
Harald Welteaf109b92010-07-22 18:14:36 +02002695 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002696
2697 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2698 return -EINVAL;
2699 cur++;
2700
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002701 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002702 cur += 2;
2703
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002704 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002705 cur += 2;
2706
2707 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2708 binf->freq_qual = *cur >> 2;
2709
Harald Welteaf109b92010-07-22 18:14:36 +02002710 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002711 binf->arfcn |= *cur++;
2712
2713 if (binf->info_type & IPAC_BINF_RXLEV)
2714 binf->rx_lev = *cur & 0x3f;
2715 cur++;
2716
2717 if (binf->info_type & IPAC_BINF_RXQUAL)
2718 binf->rx_qual = *cur & 0x7;
2719 cur++;
2720
2721 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002722 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002723 cur += 2;
2724
2725 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002726 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002727 cur += 2;
2728
2729 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002730 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002731 cur += 4;
2732
Harald Weltea780a3d2010-07-30 22:34:42 +02002733#if 0
2734 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002735 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002736#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002737 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002738 cur++;
2739
Harald Welteb40a38f2009-11-13 11:56:05 +01002740 ipac_parse_cgi(&binf->cgi, cur);
2741 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002742
2743 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2744 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2745 cur += sizeof(binf->ba_list_si2);
2746 }
2747
2748 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2749 memcpy(binf->ba_list_si2bis, cur,
2750 sizeof(binf->ba_list_si2bis));
2751 cur += sizeof(binf->ba_list_si2bis);
2752 }
2753
2754 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2755 memcpy(binf->ba_list_si2ter, cur,
2756 sizeof(binf->ba_list_si2ter));
2757 cur += sizeof(binf->ba_list_si2ter);
2758 }
2759
2760 return 0;
2761}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002762
2763void abis_nm_clear_queue(struct gsm_bts *bts)
2764{
2765 struct msgb *msg;
2766
2767 while (!llist_empty(&bts->abis_queue)) {
2768 msg = msgb_dequeue(&bts->abis_queue);
2769 msgb_free(msg);
2770 }
2771
2772 bts->abis_nm_pend = 0;
2773}