blob: 5bcc985b2385773eff66ce4043629c7eda1169fa [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 ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200383 get_value_string(abis_nm_adm_state_names,
384 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000385 }
386 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000387
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100388 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
389 new_state.operational != nm_state->operational ||
390 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000391 /* Update the operational state of a given object in our in-memory data
392 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100393 struct nm_statechg_signal_data nsd;
394 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
395 nsd.obj_class = foh->obj_class;
396 nsd.old_state = nm_state;
397 nsd.new_state = &new_state;
398 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100399 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200400 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100401 nm_state->operational = new_state.operational;
402 nm_state->availability = new_state.availability;
403 if (nm_state->administrative == 0)
404 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000405 }
406#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000407 if (op_state == 1) {
408 /* try to enable objects that are disabled */
409 abis_nm_opstart(bts, foh->obj_class,
410 foh->obj_inst.bts_nr,
411 foh->obj_inst.trx_nr,
412 foh->obj_inst.ts_nr);
413 }
Harald Weltee0590df2009-02-15 03:34:15 +0000414#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000415 return 0;
416}
417
Harald Welte0db97b22009-05-01 17:22:47 +0000418static int rx_fail_evt_rep(struct msgb *mb)
419{
420 struct abis_om_hdr *oh = msgb_l2(mb);
421 struct abis_om_fom_hdr *foh = msgb_l3(mb);
422 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100423 const uint8_t *p_val;
424 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000425
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200426 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000427
Harald Welte39315c42010-01-10 18:01:52 +0100428 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000429
430 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200431 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
432 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000433 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200434 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
435 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100436 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
437 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200438 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 +0100439 }
440 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
441 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
442 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
443 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200444 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100445 talloc_free(p_text);
446 }
447 }
Harald Welte0db97b22009-05-01 17:22:47 +0000448
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200449 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000450
451 return 0;
452}
453
Harald Welte97ed1e72009-02-06 13:38:02 +0000454static int abis_nm_rcvmsg_report(struct msgb *mb)
455{
456 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200457 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000458
Harald Welte15c61722011-05-22 22:45:37 +0200459 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000460
Harald Welte97ed1e72009-02-06 13:38:02 +0000461 //nmh->cfg->report_cb(mb, foh);
462
463 switch (mt) {
464 case NM_MT_STATECHG_EVENT_REP:
465 return abis_nm_rx_statechg_rep(mb);
466 break;
Harald Welte34a99682009-02-13 02:41:40 +0000467 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000468 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200469 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000470 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000471 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000472 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200473 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000474 break;
Harald Weltec7310382009-08-08 00:02:36 +0200475 case NM_MT_TEST_REP:
476 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200477 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200478 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000479 default:
Harald Welte23897662009-05-01 14:52:51 +0000480 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000481 break;
482
Harald Welte97ed1e72009-02-06 13:38:02 +0000483 };
484
Harald Welte97ed1e72009-02-06 13:38:02 +0000485 return 0;
486}
487
Harald Welte34a99682009-02-13 02:41:40 +0000488/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200489static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
490 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000491{
492 struct abis_om_hdr *oh;
493 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200494 uint8_t len = swdesc_len;
495 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000496
497 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
498 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
499
500 trailer = msgb_put(msg, swdesc_len);
501 memcpy(trailer, sw_desc, swdesc_len);
502
503 return abis_nm_sendmsg(bts, msg);
504}
505
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200506static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100507{
508 static const struct tlv_definition sw_descr_def = {
509 .def = {
510 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
511 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
512 },
513 };
514
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200515 uint8_t tag;
516 uint16_t tag_len;
517 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100518 int ofs = 0, len;
519
520 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
521 * nested nature and the fact you have to assume it contains only two sub
522 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
523
524 if (sw_descr[0] != NM_ATT_SW_DESCR) {
525 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
526 return -1;
527 }
528 ofs += 1;
529
530 len = tlv_parse_one(&tag, &tag_len, &val,
531 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
532 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
533 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
534 return -2;
535 }
536 ofs += len;
537
538 len = tlv_parse_one(&tag, &tag_len, &val,
539 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
540 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
541 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
542 return -3;
543 }
544 ofs += len;
545
546 return ofs;
547}
548
Harald Welte34a99682009-02-13 02:41:40 +0000549static int abis_nm_rx_sw_act_req(struct msgb *mb)
550{
551 struct abis_om_hdr *oh = msgb_l2(mb);
552 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200553 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200554 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100555 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000556
Harald Welte15c61722011-05-22 22:45:37 +0200557 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200558
559 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000560
Harald Welte97a282b2010-03-14 15:37:43 +0800561 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000562
563 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000564 foh->obj_inst.bts_nr,
565 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800566 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000567 foh->data, oh->length-sizeof(*foh));
568
Harald Welte39315c42010-01-10 18:01:52 +0100569 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200570 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
571 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
572 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
573 DEBUGP(DNM, "SW config not found! Can't continue.\n");
574 return -EINVAL;
575 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200576 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200577 }
578
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100579 /* Use the first SW_DESCR present in SW config */
580 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
581 if (sw_descr_len < 0)
582 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200583
Harald Welte34a99682009-02-13 02:41:40 +0000584 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
585 foh->obj_inst.bts_nr,
586 foh->obj_inst.trx_nr,
587 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100588 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000589}
590
Harald Weltee0590df2009-02-15 03:34:15 +0000591/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
592static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
593{
594 struct abis_om_hdr *oh = msgb_l2(mb);
595 struct abis_om_fom_hdr *foh = msgb_l3(mb);
596 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200597 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000598
Harald Welte39315c42010-01-10 18:01:52 +0100599 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000600 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
601 return -EINVAL;
602
603 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
604
605 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
606}
607
Harald Welteee670472009-02-22 21:58:49 +0000608static int abis_nm_rx_lmt_event(struct msgb *mb)
609{
610 struct abis_om_hdr *oh = msgb_l2(mb);
611 struct abis_om_fom_hdr *foh = msgb_l3(mb);
612 struct tlv_parsed tp;
613
614 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100615 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000616 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
617 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200618 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000619 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
620 }
621 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
622 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200623 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000624 DEBUGPC(DNM, "Level=%u ", level);
625 }
626 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
627 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
628 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
629 DEBUGPC(DNM, "Username=%s ", name);
630 }
631 DEBUGPC(DNM, "\n");
632 /* FIXME: parse LMT LOGON TIME */
633 return 0;
634}
635
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100636static void abis_nm_queue_send_next(struct gsm_bts *bts)
637{
638 int wait = 0;
639 struct msgb *msg;
640 /* the queue is empty */
641 while (!llist_empty(&bts->abis_queue)) {
642 msg = msgb_dequeue(&bts->abis_queue);
643 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100644 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100645
646 if (wait)
647 break;
648 }
649
650 bts->abis_nm_pend = wait;
651}
652
Harald Welte52b1f982008-12-23 20:25:15 +0000653/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000654static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000655{
Harald Welte6c96ba52009-05-01 13:03:40 +0000656 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000657 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200658 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100659 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000660
661 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000662 if (is_report(mt))
663 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000664
Harald Welte15c61722011-05-22 22:45:37 +0200665 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000666 return abis_nm_rcvmsg_sw(mb);
667
Harald Welte15c61722011-05-22 22:45:37 +0200668 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800669 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000670 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200671
Harald Welte15c61722011-05-22 22:45:37 +0200672 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200673
Harald Welte15c61722011-05-22 22:45:37 +0200674 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000675
Harald Welte39315c42010-01-10 18:01:52 +0100676 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000677 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200678 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200679 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000680 else
681 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200682
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800683 nack_data.msg = mb;
684 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200685 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100686 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200687 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000688 }
Harald Weltead384642008-12-26 10:20:07 +0000689#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000690 /* check if last message is to be acked */
691 if (is_ack_nack(nmh->last_msgtype)) {
692 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100693 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000694 /* we got our ACK, continue sending the next msg */
695 } else if (mt == MT_NACK(nmh->last_msgtype)) {
696 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100697 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000698 /* FIXME: somehow signal this to the caller */
699 } else {
700 /* really strange things happen */
701 return -EINVAL;
702 }
703 }
Harald Weltead384642008-12-26 10:20:07 +0000704#endif
705
Harald Welte97ed1e72009-02-06 13:38:02 +0000706 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000707 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100708 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000709 break;
Harald Welte34a99682009-02-13 02:41:40 +0000710 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100711 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000712 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000713 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100714 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000715 break;
Harald Welte1989c082009-08-06 17:58:31 +0200716 case NM_MT_CONN_MDROP_LINK_ACK:
717 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
718 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100719 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200720 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100721 break;
722 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200723 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100724 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100725 case NM_MT_SET_BTS_ATTR_ACK:
726 /* The HSL wants an OPSTART _after_ the SI has been set */
727 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
728 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
729 }
730 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000731 }
732
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100733 abis_nm_queue_send_next(mb->trx->bts);
734 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000735}
736
Harald Welte677c21f2009-02-17 13:22:23 +0000737static int abis_nm_rx_ipacc(struct msgb *mb);
738
739static int abis_nm_rcvmsg_manuf(struct msgb *mb)
740{
741 int rc;
742 int bts_type = mb->trx->bts->type;
743
744 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100745 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000746 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100747 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000748 break;
749 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100750 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
751 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000752 rc = 0;
753 break;
754 }
755
756 return rc;
757}
758
Harald Welte52b1f982008-12-23 20:25:15 +0000759/* High-Level API */
760/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000761int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000762{
Harald Welte52b1f982008-12-23 20:25:15 +0000763 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000764 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000765
766 /* Various consistency checks */
767 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100768 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000769 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200770 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
771 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000772 }
773 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100774 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000775 oh->sequence);
776 return -EINVAL;
777 }
Harald Welte702d8702008-12-26 20:25:35 +0000778#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200779 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000780 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000781 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100782 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000783 oh->length + sizeof(*oh), l2_len);
784 return -EINVAL;
785 }
Harald Welte702d8702008-12-26 20:25:35 +0000786 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100787 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 +0000788#endif
Harald Weltead384642008-12-26 10:20:07 +0000789 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000790
791 switch (oh->mdisc) {
792 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000793 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000794 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000795 case ABIS_OM_MDISC_MANUF:
796 rc = abis_nm_rcvmsg_manuf(msg);
797 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000798 case ABIS_OM_MDISC_MMI:
799 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100800 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000801 oh->mdisc);
802 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000803 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100804 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000805 oh->mdisc);
806 return -EINVAL;
807 }
808
Harald Weltead384642008-12-26 10:20:07 +0000809 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000810 return rc;
811}
812
813#if 0
814/* initialized all resources */
815struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
816{
817 struct abis_nm_h *nmh;
818
819 nmh = malloc(sizeof(*nmh));
820 if (!nmh)
821 return NULL;
822
823 nmh->cfg = cfg;
824
825 return nmh;
826}
827
828/* free all resources */
829void abis_nm_fini(struct abis_nm_h *nmh)
830{
831 free(nmh);
832}
833#endif
834
835/* Here we are trying to define a high-level API that can be used by
836 * the actual BSC implementation. However, the architecture is currently
837 * still under design. Ideally the calls to this API would be synchronous,
838 * while the underlying stack behind the APi runs in a traditional select
839 * based state machine.
840 */
841
Harald Welte4724f992009-01-18 18:01:49 +0000842/* 6.2 Software Load: */
843enum sw_state {
844 SW_STATE_NONE,
845 SW_STATE_WAIT_INITACK,
846 SW_STATE_WAIT_SEGACK,
847 SW_STATE_WAIT_ENDACK,
848 SW_STATE_WAIT_ACTACK,
849 SW_STATE_ERROR,
850};
Harald Welte52b1f982008-12-23 20:25:15 +0000851
Harald Welte52b1f982008-12-23 20:25:15 +0000852struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000853 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800854 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000855 gsm_cbfn *cbfn;
856 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000857 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000858
Harald Welte52b1f982008-12-23 20:25:15 +0000859 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200860 uint8_t obj_class;
861 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000862
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200863 uint8_t file_id[255];
864 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000865
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200866 uint8_t file_version[255];
867 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000868
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200869 uint8_t window_size;
870 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000871
872 int fd;
873 FILE *stream;
874 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000875 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000876};
877
Harald Welte4724f992009-01-18 18:01:49 +0000878static struct abis_nm_sw g_sw;
879
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100880static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
881{
882 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
883 msgb_v_put(msg, NM_ATT_SW_DESCR);
884 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
885 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
886 sw->file_version);
887 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
888 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
889 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
890 sw->file_version);
891 } else {
892 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
893 }
894}
895
Harald Welte4724f992009-01-18 18:01:49 +0000896/* 6.2.1 / 8.3.1: Load Data Initiate */
897static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000898{
Harald Welte4724f992009-01-18 18:01:49 +0000899 struct abis_om_hdr *oh;
900 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200901 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000902
903 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
904 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
905 sw->obj_instance[0], sw->obj_instance[1],
906 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100907
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100908 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000909 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
910
911 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000912}
913
Harald Welte1602ade2009-01-29 21:12:39 +0000914static int is_last_line(FILE *stream)
915{
916 char next_seg_buf[256];
917 long pos;
918
919 /* check if we're sending the last line */
920 pos = ftell(stream);
921 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
922 fseek(stream, pos, SEEK_SET);
923 return 1;
924 }
925
926 fseek(stream, pos, SEEK_SET);
927 return 0;
928}
929
Harald Welte4724f992009-01-18 18:01:49 +0000930/* 6.2.2 / 8.3.2 Load Data Segment */
931static int sw_load_segment(struct abis_nm_sw *sw)
932{
933 struct abis_om_hdr *oh;
934 struct msgb *msg = nm_msgb_alloc();
935 char seg_buf[256];
936 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000937 unsigned char *tlv;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200938 uint8_t len;
Harald Welte4724f992009-01-18 18:01:49 +0000939
940 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000941
942 switch (sw->bts->type) {
943 case GSM_BTS_TYPE_BS11:
944 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
945 perror("fgets reading segment");
946 return -EINVAL;
947 }
948 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000949
950 /* check if we're sending the last line */
951 sw->last_seg = is_last_line(sw->stream);
952 if (sw->last_seg)
953 seg_buf[1] = 0;
954 else
955 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000956
957 len = strlen(line_buf) + 2;
958 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200959 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000960 /* BS11 wants CR + LF in excess of the TLV length !?! */
961 tlv[1] -= 2;
962
963 /* we only now know the exact length for the OM hdr */
964 len = strlen(line_buf)+2;
965 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100966 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200967 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100968 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
969 if (len < 0) {
970 perror("read failed");
971 return -EINVAL;
972 }
973
974 if (len != IPACC_SEGMENT_SIZE)
975 sw->last_seg = 1;
976
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100977 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200978 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100979 len += 3;
980 break;
981 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000982 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100983 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000984 /* FIXME: Other BTS types */
985 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000986 }
Harald Welte4724f992009-01-18 18:01:49 +0000987
Harald Welte4724f992009-01-18 18:01:49 +0000988 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
989 sw->obj_instance[0], sw->obj_instance[1],
990 sw->obj_instance[2]);
991
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100992 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000993}
994
995/* 6.2.4 / 8.3.4 Load Data End */
996static int sw_load_end(struct abis_nm_sw *sw)
997{
998 struct abis_om_hdr *oh;
999 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001000 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001001
1002 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1003 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1004 sw->obj_instance[0], sw->obj_instance[1],
1005 sw->obj_instance[2]);
1006
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001007 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001008 return abis_nm_sendmsg(sw->bts, msg);
1009}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001010
Harald Welte52b1f982008-12-23 20:25:15 +00001011/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001012static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001013{
Harald Welte4724f992009-01-18 18:01:49 +00001014 struct abis_om_hdr *oh;
1015 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001016 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001017
Harald Welte4724f992009-01-18 18:01:49 +00001018 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1019 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1020 sw->obj_instance[0], sw->obj_instance[1],
1021 sw->obj_instance[2]);
1022
1023 /* FIXME: this is BS11 specific format */
1024 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1025 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1026 sw->file_version);
1027
1028 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001029}
Harald Welte4724f992009-01-18 18:01:49 +00001030
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001031struct sdp_firmware {
1032 char magic[4];
1033 char more_magic[4];
1034 unsigned int header_length;
1035 unsigned int file_length;
1036} __attribute__ ((packed));
1037
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001038static int parse_sdp_header(struct abis_nm_sw *sw)
1039{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001040 struct sdp_firmware firmware_header;
1041 int rc;
1042 struct stat stat;
1043
1044 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1045 if (rc != sizeof(firmware_header)) {
1046 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1047 return -1;
1048 }
1049
1050 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1051 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1052 return -1;
1053 }
1054
1055 if (firmware_header.more_magic[0] != 0x10 ||
1056 firmware_header.more_magic[1] != 0x02 ||
1057 firmware_header.more_magic[2] != 0x00 ||
1058 firmware_header.more_magic[3] != 0x00) {
1059 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1060 return -1;
1061 }
1062
1063
1064 if (fstat(sw->fd, &stat) == -1) {
1065 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1066 return -1;
1067 }
1068
1069 if (ntohl(firmware_header.file_length) != stat.st_size) {
1070 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1071 return -1;
1072 }
1073
1074 /* go back to the start as we checked the whole filesize.. */
1075 lseek(sw->fd, 0l, SEEK_SET);
1076 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1077 "There might be checksums in the file that are not\n"
1078 "verified and incomplete firmware might be flashed.\n"
1079 "There is absolutely no WARRANTY that flashing will\n"
1080 "work.\n");
1081 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001082}
1083
Harald Welte4724f992009-01-18 18:01:49 +00001084static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1085{
1086 char file_id[12+1];
1087 char file_version[80+1];
1088 int rc;
1089
1090 sw->fd = open(fname, O_RDONLY);
1091 if (sw->fd < 0)
1092 return sw->fd;
1093
1094 switch (sw->bts->type) {
1095 case GSM_BTS_TYPE_BS11:
1096 sw->stream = fdopen(sw->fd, "r");
1097 if (!sw->stream) {
1098 perror("fdopen");
1099 return -1;
1100 }
1101 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001102 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001103 file_id, file_version);
1104 if (rc != 2) {
1105 perror("parsing header line of software file");
1106 return -1;
1107 }
1108 strcpy((char *)sw->file_id, file_id);
1109 sw->file_id_len = strlen(file_id);
1110 strcpy((char *)sw->file_version, file_version);
1111 sw->file_version_len = strlen(file_version);
1112 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001113 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001114 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001115 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001116 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001117 rc = parse_sdp_header(sw);
1118 if (rc < 0) {
1119 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1120 return -1;
1121 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001122
1123 strcpy((char *)sw->file_id, "id");
1124 sw->file_id_len = 3;
1125 strcpy((char *)sw->file_version, "version");
1126 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001127 break;
Harald Welte4724f992009-01-18 18:01:49 +00001128 default:
1129 /* We don't know how to treat them yet */
1130 close(sw->fd);
1131 return -EINVAL;
1132 }
1133
1134 return 0;
1135}
1136
1137static void sw_close_file(struct abis_nm_sw *sw)
1138{
1139 switch (sw->bts->type) {
1140 case GSM_BTS_TYPE_BS11:
1141 fclose(sw->stream);
1142 break;
1143 default:
1144 close(sw->fd);
1145 break;
1146 }
1147}
1148
1149/* Fill the window */
1150static int sw_fill_window(struct abis_nm_sw *sw)
1151{
1152 int rc;
1153
1154 while (sw->seg_in_window < sw->window_size) {
1155 rc = sw_load_segment(sw);
1156 if (rc < 0)
1157 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001158 if (sw->last_seg)
1159 break;
Harald Welte4724f992009-01-18 18:01:49 +00001160 }
1161 return 0;
1162}
1163
1164/* callback function from abis_nm_rcvmsg() handler */
1165static int abis_nm_rcvmsg_sw(struct msgb *mb)
1166{
1167 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1168 int rc = -1;
1169 struct abis_nm_sw *sw = &g_sw;
1170 enum sw_state old_state = sw->state;
1171
Harald Welte3ffd1372009-02-01 22:15:49 +00001172 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001173
1174 switch (sw->state) {
1175 case SW_STATE_WAIT_INITACK:
1176 switch (foh->msg_type) {
1177 case NM_MT_LOAD_INIT_ACK:
1178 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001179 if (sw->cbfn)
1180 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1181 NM_MT_LOAD_INIT_ACK, mb,
1182 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001183 rc = sw_fill_window(sw);
1184 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001185 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001186 break;
1187 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001188 if (sw->forced) {
1189 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1190 "Init NACK\n");
1191 if (sw->cbfn)
1192 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1193 NM_MT_LOAD_INIT_ACK, mb,
1194 sw->cb_data, NULL);
1195 rc = sw_fill_window(sw);
1196 sw->state = SW_STATE_WAIT_SEGACK;
1197 } else {
1198 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001199 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001200 if (sw->cbfn)
1201 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1202 NM_MT_LOAD_INIT_NACK, mb,
1203 sw->cb_data, NULL);
1204 sw->state = SW_STATE_ERROR;
1205 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001206 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001207 break;
1208 }
1209 break;
1210 case SW_STATE_WAIT_SEGACK:
1211 switch (foh->msg_type) {
1212 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001213 if (sw->cbfn)
1214 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1215 NM_MT_LOAD_SEG_ACK, mb,
1216 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001217 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001218 if (!sw->last_seg) {
1219 /* fill window with more segments */
1220 rc = sw_fill_window(sw);
1221 sw->state = SW_STATE_WAIT_SEGACK;
1222 } else {
1223 /* end the transfer */
1224 sw->state = SW_STATE_WAIT_ENDACK;
1225 rc = sw_load_end(sw);
1226 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001227 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001228 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001229 case NM_MT_LOAD_ABORT:
1230 if (sw->cbfn)
1231 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1232 NM_MT_LOAD_ABORT, mb,
1233 sw->cb_data, NULL);
1234 break;
Harald Welte4724f992009-01-18 18:01:49 +00001235 }
1236 break;
1237 case SW_STATE_WAIT_ENDACK:
1238 switch (foh->msg_type) {
1239 case NM_MT_LOAD_END_ACK:
1240 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001241 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1242 sw->bts->nr);
1243 sw->state = SW_STATE_NONE;
1244 if (sw->cbfn)
1245 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1246 NM_MT_LOAD_END_ACK, mb,
1247 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001248 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001249 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001250 break;
1251 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001252 if (sw->forced) {
1253 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1254 "End NACK\n");
1255 sw->state = SW_STATE_NONE;
1256 if (sw->cbfn)
1257 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1258 NM_MT_LOAD_END_ACK, mb,
1259 sw->cb_data, NULL);
1260 } else {
1261 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001262 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001263 sw->state = SW_STATE_ERROR;
1264 if (sw->cbfn)
1265 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1266 NM_MT_LOAD_END_NACK, mb,
1267 sw->cb_data, NULL);
1268 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001269 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001270 break;
1271 }
1272 case SW_STATE_WAIT_ACTACK:
1273 switch (foh->msg_type) {
1274 case NM_MT_ACTIVATE_SW_ACK:
1275 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001276 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001277 sw->state = SW_STATE_NONE;
1278 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001279 if (sw->cbfn)
1280 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1281 NM_MT_ACTIVATE_SW_ACK, mb,
1282 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001283 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001284 break;
1285 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001286 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001287 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001288 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001289 if (sw->cbfn)
1290 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1291 NM_MT_ACTIVATE_SW_NACK, mb,
1292 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001293 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001294 break;
1295 }
1296 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001297 switch (foh->msg_type) {
1298 case NM_MT_ACTIVATE_SW_ACK:
1299 rc = 0;
1300 break;
1301 }
1302 break;
Harald Welte4724f992009-01-18 18:01:49 +00001303 case SW_STATE_ERROR:
1304 break;
1305 }
1306
1307 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001308 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001309 foh->msg_type, old_state, sw->state);
1310
1311 return rc;
1312}
1313
1314/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001315int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001316 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001317 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001318{
1319 struct abis_nm_sw *sw = &g_sw;
1320 int rc;
1321
Harald Welte5e4d1b32009-02-01 13:36:56 +00001322 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1323 bts->nr, fname);
1324
Harald Welte4724f992009-01-18 18:01:49 +00001325 if (sw->state != SW_STATE_NONE)
1326 return -EBUSY;
1327
1328 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001329 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001330
1331 switch (bts->type) {
1332 case GSM_BTS_TYPE_BS11:
1333 sw->obj_class = NM_OC_SITE_MANAGER;
1334 sw->obj_instance[0] = 0xff;
1335 sw->obj_instance[1] = 0xff;
1336 sw->obj_instance[2] = 0xff;
1337 break;
1338 case GSM_BTS_TYPE_NANOBTS:
1339 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001340 sw->obj_instance[0] = sw->bts->nr;
1341 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001342 sw->obj_instance[2] = 0xff;
1343 break;
1344 case GSM_BTS_TYPE_UNKNOWN:
1345 default:
1346 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1347 return -1;
1348 break;
1349 }
Harald Welte4724f992009-01-18 18:01:49 +00001350 sw->window_size = win_size;
1351 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001352 sw->cbfn = cbfn;
1353 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001354 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001355
1356 rc = sw_open_file(sw, fname);
1357 if (rc < 0) {
1358 sw->state = SW_STATE_NONE;
1359 return rc;
1360 }
1361
1362 return sw_load_init(sw);
1363}
Harald Welte52b1f982008-12-23 20:25:15 +00001364
Harald Welte1602ade2009-01-29 21:12:39 +00001365int abis_nm_software_load_status(struct gsm_bts *bts)
1366{
1367 struct abis_nm_sw *sw = &g_sw;
1368 struct stat st;
1369 int rc, percent;
1370
1371 rc = fstat(sw->fd, &st);
1372 if (rc < 0) {
1373 perror("ERROR during stat");
1374 return rc;
1375 }
1376
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001377 if (sw->stream)
1378 percent = (ftell(sw->stream) * 100) / st.st_size;
1379 else
1380 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001381 return percent;
1382}
1383
Harald Welte5e4d1b32009-02-01 13:36:56 +00001384/* Activate the specified software into the BTS */
1385int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1386 gsm_cbfn *cbfn, void *cb_data)
1387{
1388 struct abis_nm_sw *sw = &g_sw;
1389 int rc;
1390
1391 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1392 bts->nr, fname);
1393
1394 if (sw->state != SW_STATE_NONE)
1395 return -EBUSY;
1396
1397 sw->bts = bts;
1398 sw->obj_class = NM_OC_SITE_MANAGER;
1399 sw->obj_instance[0] = 0xff;
1400 sw->obj_instance[1] = 0xff;
1401 sw->obj_instance[2] = 0xff;
1402 sw->state = SW_STATE_WAIT_ACTACK;
1403 sw->cbfn = cbfn;
1404 sw->cb_data = cb_data;
1405
1406 /* Open the file in order to fill some sw struct members */
1407 rc = sw_open_file(sw, fname);
1408 if (rc < 0) {
1409 sw->state = SW_STATE_NONE;
1410 return rc;
1411 }
1412 sw_close_file(sw);
1413
1414 return sw_activate(sw);
1415}
1416
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001417static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1418 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001419{
Harald Welteadaf08b2009-01-18 11:08:10 +00001420 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001421 ch->bts_port = bts_port;
1422 ch->timeslot = ts_nr;
1423 ch->subslot = subslot_nr;
1424}
1425
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001426int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1427 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1428 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001429{
1430 struct abis_om_hdr *oh;
1431 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001432 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001433 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001434
1435 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1436 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1437 bts->bts_nr, trx_nr, 0xff);
1438
Harald Welte8470bf22008-12-25 23:28:35 +00001439 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001440
1441 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1442 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1443
1444 return abis_nm_sendmsg(bts, msg);
1445}
1446
1447/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1448int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001449 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001450{
Harald Welte8470bf22008-12-25 23:28:35 +00001451 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001452 struct abis_om_hdr *oh;
1453 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001454 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001455
1456 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001457 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001458 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1459
1460 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1461 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1462
1463 return abis_nm_sendmsg(bts, msg);
1464}
1465
1466#if 0
1467int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1468 struct abis_nm_abis_channel *chan)
1469{
1470}
1471#endif
1472
1473int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001474 uint8_t e1_port, uint8_t e1_timeslot,
1475 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001476{
1477 struct gsm_bts *bts = ts->trx->bts;
1478 struct abis_om_hdr *oh;
1479 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001480 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001481
1482 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1483 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001484 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001485
1486 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1487 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1488
Harald Weltef325eb42009-02-19 17:07:39 +00001489 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1490 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001491 e1_port, e1_timeslot, e1_subslot);
1492
Harald Welte52b1f982008-12-23 20:25:15 +00001493 return abis_nm_sendmsg(bts, msg);
1494}
1495
1496#if 0
1497int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1498 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001499 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001500{
1501}
1502#endif
1503
Harald Welte22af0db2009-02-14 15:41:08 +00001504/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001505int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001506{
1507 struct abis_om_hdr *oh;
1508 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001509 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001510
1511 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1512
1513 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001514 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 +00001515 cur = msgb_put(msg, attr_len);
1516 memcpy(cur, attr, attr_len);
1517
1518 return abis_nm_sendmsg(bts, msg);
1519}
1520
1521/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001522int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001523{
1524 struct abis_om_hdr *oh;
1525 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001526 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001527
1528 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1529
1530 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1531 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001532 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001533 cur = msgb_put(msg, attr_len);
1534 memcpy(cur, attr, attr_len);
1535
1536 return abis_nm_sendmsg(trx->bts, msg);
1537}
1538
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001539static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001540{
1541 int i;
1542
1543 /* As it turns out, the BS-11 has some very peculiar restrictions
1544 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301545 switch (ts->trx->bts->type) {
1546 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001547 switch (chan_comb) {
1548 case NM_CHANC_TCHHalf:
1549 case NM_CHANC_TCHHalf2:
1550 /* not supported */
1551 return -EINVAL;
1552 case NM_CHANC_SDCCH:
1553 /* only one SDCCH/8 per TRX */
1554 for (i = 0; i < TRX_NR_TS; i++) {
1555 if (i == ts->nr)
1556 continue;
1557 if (ts->trx->ts[i].nm_chan_comb ==
1558 NM_CHANC_SDCCH)
1559 return -EINVAL;
1560 }
1561 /* not allowed for TS0 of BCCH-TRX */
1562 if (ts->trx == ts->trx->bts->c0 &&
1563 ts->nr == 0)
1564 return -EINVAL;
1565 /* not on the same TRX that has a BCCH+SDCCH4
1566 * combination */
1567 if (ts->trx == ts->trx->bts->c0 &&
1568 (ts->trx->ts[0].nm_chan_comb == 5 ||
1569 ts->trx->ts[0].nm_chan_comb == 8))
1570 return -EINVAL;
1571 break;
1572 case NM_CHANC_mainBCCH:
1573 case NM_CHANC_BCCHComb:
1574 /* allowed only for TS0 of C0 */
1575 if (ts->trx != ts->trx->bts->c0 ||
1576 ts->nr != 0)
1577 return -EINVAL;
1578 break;
1579 case NM_CHANC_BCCH:
1580 /* allowed only for TS 2/4/6 of C0 */
1581 if (ts->trx != ts->trx->bts->c0)
1582 return -EINVAL;
1583 if (ts->nr != 2 && ts->nr != 4 &&
1584 ts->nr != 6)
1585 return -EINVAL;
1586 break;
1587 case 8: /* this is not like 08.58, but in fact
1588 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1589 /* FIXME: only one CBCH allowed per cell */
1590 break;
1591 }
Harald Welted6575f92009-12-02 02:45:23 +05301592 break;
1593 case GSM_BTS_TYPE_NANOBTS:
1594 switch (ts->nr) {
1595 case 0:
1596 if (ts->trx->nr == 0) {
1597 /* only on TRX0 */
1598 switch (chan_comb) {
1599 case NM_CHANC_BCCH:
1600 case NM_CHANC_mainBCCH:
1601 case NM_CHANC_BCCHComb:
1602 return 0;
1603 break;
1604 default:
1605 return -EINVAL;
1606 }
1607 } else {
1608 switch (chan_comb) {
1609 case NM_CHANC_TCHFull:
1610 case NM_CHANC_TCHHalf:
1611 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1612 return 0;
1613 default:
1614 return -EINVAL;
1615 }
1616 }
1617 break;
1618 case 1:
1619 if (ts->trx->nr == 0) {
1620 switch (chan_comb) {
1621 case NM_CHANC_SDCCH_CBCH:
1622 if (ts->trx->ts[0].nm_chan_comb ==
1623 NM_CHANC_mainBCCH)
1624 return 0;
1625 return -EINVAL;
1626 case NM_CHANC_SDCCH:
1627 case NM_CHANC_TCHFull:
1628 case NM_CHANC_TCHHalf:
1629 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1630 case NM_CHANC_IPAC_TCHFull_PDCH:
1631 return 0;
1632 }
1633 } else {
1634 switch (chan_comb) {
1635 case NM_CHANC_SDCCH:
1636 case NM_CHANC_TCHFull:
1637 case NM_CHANC_TCHHalf:
1638 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1639 return 0;
1640 default:
1641 return -EINVAL;
1642 }
1643 }
1644 break;
1645 case 2:
1646 case 3:
1647 case 4:
1648 case 5:
1649 case 6:
1650 case 7:
1651 switch (chan_comb) {
1652 case NM_CHANC_TCHFull:
1653 case NM_CHANC_TCHHalf:
1654 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1655 return 0;
1656 case NM_CHANC_IPAC_PDCH:
1657 case NM_CHANC_IPAC_TCHFull_PDCH:
1658 if (ts->trx->nr == 0)
1659 return 0;
1660 else
1661 return -EINVAL;
1662 }
1663 break;
1664 }
1665 return -EINVAL;
1666 default:
1667 /* unknown BTS type */
1668 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001669 }
1670 return 0;
1671}
1672
Harald Welte22af0db2009-02-14 15:41:08 +00001673/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001674int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001675{
1676 struct gsm_bts *bts = ts->trx->bts;
1677 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001678 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001679 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001680 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00001681
1682 if (bts->type == GSM_BTS_TYPE_BS11)
1683 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001684
Harald Weltef325eb42009-02-19 17:07:39 +00001685 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001686 if (verify_chan_comb(ts, chan_comb) < 0) {
1687 msgb_free(msg);
1688 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1689 return -EINVAL;
1690 }
1691 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001692
Harald Welte52b1f982008-12-23 20:25:15 +00001693 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001694 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001695 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001696 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001697 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001698 if (ts->hopping.enabled) {
1699 unsigned int i;
1700 uint8_t *len;
1701
Harald Welte6e0cd042009-09-12 13:05:33 +02001702 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1703 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001704
1705 /* build the ARFCN list */
1706 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1707 len = msgb_put(msg, 1);
1708 *len = 0;
1709 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1710 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1711 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001712 /* At least BS-11 wants a TLV16 here */
1713 if (bts->type == GSM_BTS_TYPE_BS11)
1714 *len += 1;
1715 else
1716 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001717 }
1718 }
Harald Weltee0590df2009-02-15 03:34:15 +00001719 }
Harald Weltee6c22d92009-07-21 20:40:05 +02001720 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001721 if (bts->type == GSM_BTS_TYPE_BS11)
1722 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001723
1724 return abis_nm_sendmsg(bts, msg);
1725}
1726
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001727int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1728 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001729{
1730 struct abis_om_hdr *oh;
1731 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001732 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1733 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001734
1735 if (nack) {
1736 len += 2;
1737 msgtype = NM_MT_SW_ACT_REQ_NACK;
1738 }
Harald Welte34a99682009-02-13 02:41:40 +00001739
1740 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001741 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1742
Harald Welte34a99682009-02-13 02:41:40 +00001743 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001744 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001745 memcpy(ptr, attr, att_len);
1746 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001747 if (nack)
1748 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001749
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001750 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001751}
1752
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001753int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001754{
Harald Welte8470bf22008-12-25 23:28:35 +00001755 struct msgb *msg = nm_msgb_alloc();
1756 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001757 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001758
1759 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1760 fill_om_hdr(oh, len);
1761 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001762 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001763
1764 return abis_nm_sendmsg(bts, msg);
1765}
1766
1767/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001768static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001769{
1770 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001771 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001772
1773 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001774 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001775 0xff, 0xff, 0xff);
1776
1777 return abis_nm_sendmsg(bts, msg);
1778}
1779
Harald Welte34a99682009-02-13 02:41:40 +00001780/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001781int 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 +00001782{
1783 struct abis_om_hdr *oh;
1784 struct msgb *msg = nm_msgb_alloc();
1785
1786 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1787 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1788
Harald Welte15c61722011-05-22 22:45:37 +02001789 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001790 DEBUGPC(DNM, "Sending OPSTART\n");
1791
Harald Welte34a99682009-02-13 02:41:40 +00001792 return abis_nm_sendmsg(bts, msg);
1793}
1794
1795/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001796int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1797 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001798{
1799 struct abis_om_hdr *oh;
1800 struct msgb *msg = nm_msgb_alloc();
1801
1802 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1803 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1804 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1805
1806 return abis_nm_sendmsg(bts, msg);
1807}
1808
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001809int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1810 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001811{
1812 struct abis_om_hdr *oh;
1813 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001814 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001815
1816 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1817 e1_port0, ts0, e1_port1, ts1);
1818
1819 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1820 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1821 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1822
1823 attr = msgb_put(msg, 3);
1824 attr[0] = NM_ATT_MDROP_LINK;
1825 attr[1] = e1_port0;
1826 attr[2] = ts0;
1827
1828 attr = msgb_put(msg, 3);
1829 attr[0] = NM_ATT_MDROP_NEXT;
1830 attr[1] = e1_port1;
1831 attr[2] = ts1;
1832
1833 return abis_nm_sendmsg(bts, msg);
1834}
Harald Welte34a99682009-02-13 02:41:40 +00001835
Harald Weltec7310382009-08-08 00:02:36 +02001836/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001837int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1838 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1839 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001840{
1841 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001842
Harald Welte15c61722011-05-22 22:45:37 +02001843 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001844
1845 if (!msg)
1846 msg = nm_msgb_alloc();
1847
1848 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1849 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1850 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1851 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001852 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001853
1854 return abis_nm_sendmsg(bts, msg);
1855}
1856
Harald Welte52b1f982008-12-23 20:25:15 +00001857int abis_nm_event_reports(struct gsm_bts *bts, int on)
1858{
1859 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001860 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001861 else
Harald Welte227d4072009-01-03 08:16:25 +00001862 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001863}
1864
Harald Welte47d88ae2009-01-04 12:02:08 +00001865/* Siemens (or BS-11) specific commands */
1866
Harald Welte3ffd1372009-02-01 22:15:49 +00001867int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1868{
1869 if (reconnect == 0)
1870 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1871 else
1872 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1873}
1874
Harald Welteb8427972009-02-05 19:27:17 +00001875int abis_nm_bs11_restart(struct gsm_bts *bts)
1876{
1877 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1878}
1879
1880
Harald Welte268bb402009-02-01 19:11:56 +00001881struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001882 uint16_t year;
1883 uint8_t month;
1884 uint8_t day;
1885 uint8_t hour;
1886 uint8_t min;
1887 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001888} __attribute__((packed));
1889
1890
1891void get_bs11_date_time(struct bs11_date_time *aet)
1892{
1893 time_t t;
1894 struct tm *tm;
1895
1896 t = time(NULL);
1897 tm = localtime(&t);
1898 aet->sec = tm->tm_sec;
1899 aet->min = tm->tm_min;
1900 aet->hour = tm->tm_hour;
1901 aet->day = tm->tm_mday;
1902 aet->month = tm->tm_mon;
1903 aet->year = htons(1900 + tm->tm_year);
1904}
1905
Harald Welte05188ee2009-01-18 11:39:08 +00001906int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001907{
Harald Welte4668fda2009-01-03 08:19:29 +00001908 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001909}
1910
Harald Welte05188ee2009-01-18 11:39:08 +00001911int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001912{
1913 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001914 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001915 else
Harald Welte4668fda2009-01-03 08:19:29 +00001916 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001917}
Harald Welte47d88ae2009-01-04 12:02:08 +00001918
Harald Welte05188ee2009-01-18 11:39:08 +00001919int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001920 enum abis_bs11_objtype type, uint8_t idx,
1921 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001922{
1923 struct abis_om_hdr *oh;
1924 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001925 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001926
1927 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001928 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001929 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001930 cur = msgb_put(msg, attr_len);
1931 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001932
1933 return abis_nm_sendmsg(bts, msg);
1934}
1935
Harald Welte78fc0d42009-02-19 02:50:57 +00001936int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001937 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001938{
1939 struct abis_om_hdr *oh;
1940 struct msgb *msg = nm_msgb_alloc();
1941
1942 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1943 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1944 NM_OC_BS11, type, 0, idx);
1945
1946 return abis_nm_sendmsg(bts, msg);
1947}
1948
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001949int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001950{
1951 struct abis_om_hdr *oh;
1952 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001953 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001954
1955 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001956 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001957 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1958 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001959
1960 return abis_nm_sendmsg(bts, msg);
1961}
1962
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001963int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001964{
1965 struct abis_om_hdr *oh;
1966 struct msgb *msg = nm_msgb_alloc();
1967
1968 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1969 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001970 idx, 0xff, 0xff);
1971
1972 return abis_nm_sendmsg(bts, msg);
1973}
1974
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001975int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001976{
1977 struct abis_om_hdr *oh;
1978 struct msgb *msg = nm_msgb_alloc();
1979
1980 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1981 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1982 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001983
1984 return abis_nm_sendmsg(bts, msg);
1985}
Harald Welte05188ee2009-01-18 11:39:08 +00001986
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001987static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001988int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1989{
1990 struct abis_om_hdr *oh;
1991 struct msgb *msg = nm_msgb_alloc();
1992
1993 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1994 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1995 0xff, 0xff, 0xff);
1996 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1997
1998 return abis_nm_sendmsg(bts, msg);
1999}
2000
Harald Welteb6c92ae2009-02-21 20:15:32 +00002001/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002002int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2003 uint8_t e1_timeslot, uint8_t e1_subslot,
2004 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002005{
2006 struct abis_om_hdr *oh;
2007 struct abis_nm_channel *ch;
2008 struct msgb *msg = nm_msgb_alloc();
2009
2010 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002011 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002012 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2013
2014 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2015 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002016 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002017
2018 return abis_nm_sendmsg(bts, msg);
2019}
2020
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002021int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002022{
2023 struct abis_om_hdr *oh;
2024 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002025
2026 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002027 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002028 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2029 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2030
2031 return abis_nm_sendmsg(trx->bts, msg);
2032}
2033
Harald Welte78fc0d42009-02-19 02:50:57 +00002034int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2035{
2036 struct abis_om_hdr *oh;
2037 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002038 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002039
2040 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2041 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2042 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2043 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2044
2045 return abis_nm_sendmsg(trx->bts, msg);
2046}
2047
Harald Welteaaf02d92009-04-29 13:25:57 +00002048int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2049{
2050 struct abis_om_hdr *oh;
2051 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002052 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002053
2054 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2055 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2056 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002057 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002058
2059 return abis_nm_sendmsg(bts, msg);
2060}
2061
Harald Welteef061952009-05-17 12:43:42 +00002062int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2063{
2064 struct abis_om_hdr *oh;
2065 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002066 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002067 NM_ATT_BS11_CCLK_TYPE };
2068
2069 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2070 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2071 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2072 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2073
2074 return abis_nm_sendmsg(bts, msg);
2075
2076}
Harald Welteaaf02d92009-04-29 13:25:57 +00002077
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002078//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002079
Harald Welte1bc09062009-01-18 14:17:52 +00002080int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002081{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002082 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2083}
2084
Daniel Willmann4b054c82010-01-07 00:46:26 +01002085int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2086{
2087 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2088}
2089
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002090int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002091{
Harald Welte05188ee2009-01-18 11:39:08 +00002092 struct abis_om_hdr *oh;
2093 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002094 struct bs11_date_time bdt;
2095
2096 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002097
2098 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002099 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002100 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002101 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002102 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002103 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002104 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002105 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002106 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002107 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002108 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002109 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002110 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002111 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002112 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002113 }
Harald Welte05188ee2009-01-18 11:39:08 +00002114
2115 return abis_nm_sendmsg(bts, msg);
2116}
Harald Welte1bc09062009-01-18 14:17:52 +00002117
2118int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2119{
2120 struct abis_om_hdr *oh;
2121 struct msgb *msg;
2122
2123 if (strlen(password) != 10)
2124 return -EINVAL;
2125
2126 msg = nm_msgb_alloc();
2127 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002128 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002129 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002130 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002131
2132 return abis_nm_sendmsg(bts, msg);
2133}
2134
Harald Weltee69f5fb2009-04-28 16:31:38 +00002135/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2136int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2137{
2138 struct abis_om_hdr *oh;
2139 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002140 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002141
2142 msg = nm_msgb_alloc();
2143 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2144 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2145 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002146
2147 if (locked)
2148 tlv_value = BS11_LI_PLL_LOCKED;
2149 else
2150 tlv_value = BS11_LI_PLL_STANDALONE;
2151
2152 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002153
2154 return abis_nm_sendmsg(bts, msg);
2155}
2156
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002157/* Set the calibration value of the PLL (work value/set value)
2158 * It depends on the login which one is changed */
2159int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2160{
2161 struct abis_om_hdr *oh;
2162 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002163 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002164
2165 msg = nm_msgb_alloc();
2166 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2167 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2168 BS11_OBJ_TRX1, 0x00, 0x00);
2169
2170 tlv_value[0] = value>>8;
2171 tlv_value[1] = value&0xff;
2172
2173 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2174
2175 return abis_nm_sendmsg(bts, msg);
2176}
2177
Harald Welte1bc09062009-01-18 14:17:52 +00002178int abis_nm_bs11_get_state(struct gsm_bts *bts)
2179{
2180 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2181}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002182
2183/* BS11 SWL */
2184
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002185void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002186
Harald Welte5e4d1b32009-02-01 13:36:56 +00002187struct abis_nm_bs11_sw {
2188 struct gsm_bts *bts;
2189 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002190 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002191 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002192 struct llist_head file_list;
2193 gsm_cbfn *user_cb; /* specified by the user */
2194};
2195static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2196
2197struct file_list_entry {
2198 struct llist_head list;
2199 char fname[PATH_MAX];
2200};
2201
2202struct file_list_entry *fl_dequeue(struct llist_head *queue)
2203{
2204 struct llist_head *lh;
2205
2206 if (llist_empty(queue))
2207 return NULL;
2208
2209 lh = queue->next;
2210 llist_del(lh);
2211
2212 return llist_entry(lh, struct file_list_entry, list);
2213}
2214
2215static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2216{
2217 char linebuf[255];
2218 struct llist_head *lh, *lh2;
2219 FILE *swl;
2220 int rc = 0;
2221
2222 swl = fopen(bs11_sw->swl_fname, "r");
2223 if (!swl)
2224 return -ENODEV;
2225
2226 /* zero the stale file list, if any */
2227 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2228 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002229 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002230 }
2231
2232 while (fgets(linebuf, sizeof(linebuf), swl)) {
2233 char file_id[12+1];
2234 char file_version[80+1];
2235 struct file_list_entry *fle;
2236 static char dir[PATH_MAX];
2237
2238 if (strlen(linebuf) < 4)
2239 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002240
Harald Welte5e4d1b32009-02-01 13:36:56 +00002241 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2242 if (rc < 0) {
2243 perror("ERR parsing SWL file");
2244 rc = -EINVAL;
2245 goto out;
2246 }
2247 if (rc < 2)
2248 continue;
2249
Harald Welte470ec292009-06-26 20:25:23 +02002250 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002251 if (!fle) {
2252 rc = -ENOMEM;
2253 goto out;
2254 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002255
2256 /* construct new filename */
2257 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2258 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2259 strcat(fle->fname, "/");
2260 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002261
2262 llist_add_tail(&fle->list, &bs11_sw->file_list);
2263 }
2264
2265out:
2266 fclose(swl);
2267 return rc;
2268}
2269
2270/* bs11 swload specific callback, passed to abis_nm core swload */
2271static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2272 struct msgb *msg, void *data, void *param)
2273{
2274 struct abis_nm_bs11_sw *bs11_sw = data;
2275 struct file_list_entry *fle;
2276 int rc = 0;
2277
Harald Welte5e4d1b32009-02-01 13:36:56 +00002278 switch (event) {
2279 case NM_MT_LOAD_END_ACK:
2280 fle = fl_dequeue(&bs11_sw->file_list);
2281 if (fle) {
2282 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002283 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002284 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002285 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002286 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002287 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002288 } else {
2289 /* activate the SWL */
2290 rc = abis_nm_software_activate(bs11_sw->bts,
2291 bs11_sw->swl_fname,
2292 bs11_swload_cbfn,
2293 bs11_sw);
2294 }
2295 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002296 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002297 case NM_MT_LOAD_END_NACK:
2298 case NM_MT_LOAD_INIT_ACK:
2299 case NM_MT_LOAD_INIT_NACK:
2300 case NM_MT_ACTIVATE_SW_NACK:
2301 case NM_MT_ACTIVATE_SW_ACK:
2302 default:
2303 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002304 if (bs11_sw->user_cb)
2305 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002306 break;
2307 }
2308
2309 return rc;
2310}
2311
2312/* Siemens provides a SWL file that is a mere listing of all the other
2313 * files that are part of a software release. We need to upload first
2314 * the list file, and then each file that is listed in the list file */
2315int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002316 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002317{
2318 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2319 struct file_list_entry *fle;
2320 int rc = 0;
2321
2322 INIT_LLIST_HEAD(&bs11_sw->file_list);
2323 bs11_sw->bts = bts;
2324 bs11_sw->win_size = win_size;
2325 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002326 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002327
2328 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2329 rc = bs11_read_swl_file(bs11_sw);
2330 if (rc < 0)
2331 return rc;
2332
2333 /* dequeue next item in file list */
2334 fle = fl_dequeue(&bs11_sw->file_list);
2335 if (!fle)
2336 return -EINVAL;
2337
2338 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002339 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002340 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002341 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002342 return rc;
2343}
2344
Harald Welte5083b0b2009-02-02 19:20:52 +00002345#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002346static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002347 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2348 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2349 NM_ATT_BS11_LMT_USER_NAME,
2350
2351 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2352
2353 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2354
2355 NM_ATT_BS11_SW_LOAD_STORED };
2356
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002357static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002358 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2359 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2360 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2361 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002362#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002363
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002364static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002365 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2366 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002367 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002368
2369int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2370{
2371 struct abis_om_hdr *oh;
2372 struct msgb *msg = nm_msgb_alloc();
2373
2374 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2375 /* SiemensHW CCTRL object */
2376 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2377 0x03, 0x00, 0x00);
2378 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2379
2380 return abis_nm_sendmsg(bts, msg);
2381}
Harald Welte268bb402009-02-01 19:11:56 +00002382
2383int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2384{
2385 struct abis_om_hdr *oh;
2386 struct msgb *msg = nm_msgb_alloc();
2387 struct bs11_date_time aet;
2388
2389 get_bs11_date_time(&aet);
2390 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2391 /* SiemensHW CCTRL object */
2392 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2393 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002394 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002395
2396 return abis_nm_sendmsg(bts, msg);
2397}
Harald Welte5c1e4582009-02-15 11:57:29 +00002398
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002399int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002400{
2401 struct abis_om_hdr *oh;
2402 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002403 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002404
2405 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2406 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2407 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2408 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2409
2410 return abis_nm_sendmsg(bts, msg);
2411}
2412
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002413int 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 +02002414{
2415 struct abis_om_hdr *oh;
2416 struct msgb *msg = nm_msgb_alloc();
2417 struct bs11_date_time aet;
2418
2419 get_bs11_date_time(&aet);
2420 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2421 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2422 bport, 0xff, 0x02);
2423 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2424
2425 return abis_nm_sendmsg(bts, msg);
2426}
2427
Harald Welte5c1e4582009-02-15 11:57:29 +00002428/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002429static const char ipaccess_magic[] = "com.ipaccess";
2430
Harald Welte677c21f2009-02-17 13:22:23 +00002431
2432static int abis_nm_rx_ipacc(struct msgb *msg)
2433{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002434 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002435 struct abis_om_hdr *oh = msgb_l2(msg);
2436 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002437 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002438 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002439 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002440
2441 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002442 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002443 return -EINVAL;
2444 }
2445
Harald Welte193fefc2009-04-30 15:16:27 +00002446 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002447 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002448
Harald Welte15c61722011-05-22 22:45:37 +02002449 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002450
Harald Welte746d6092009-10-19 22:11:11 +02002451 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002452
Harald Welte677c21f2009-02-17 13:22:23 +00002453 switch (foh->msg_type) {
2454 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002455 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002456 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2457 memcpy(&addr,
2458 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2459
2460 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2461 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002462 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002463 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002464 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002465 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002466 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2467 DEBUGPC(DNM, "STREAM=0x%02x ",
2468 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002469 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002470 break;
2471 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002472 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002473 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002474 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002475 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002476 else
2477 DEBUGPC(DNM, "\n");
2478 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002479 case NM_MT_IPACC_SET_NVATTR_ACK:
2480 DEBUGPC(DNM, "SET NVATTR ACK\n");
2481 /* FIXME: decode and show the actual attributes */
2482 break;
2483 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002484 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002485 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002486 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002487 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002488 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002489 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002490 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002491 case NM_MT_IPACC_GET_NVATTR_ACK:
2492 DEBUGPC(DNM, "GET NVATTR ACK\n");
2493 /* FIXME: decode and show the actual attributes */
2494 break;
2495 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002496 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002497 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002498 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002499 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002500 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002501 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002502 break;
Harald Welte15c44172009-10-08 20:15:24 +02002503 case NM_MT_IPACC_SET_ATTR_ACK:
2504 DEBUGPC(DNM, "SET ATTR ACK\n");
2505 break;
2506 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002507 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002508 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002509 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002510 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002511 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002512 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002513 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002514 default:
2515 DEBUGPC(DNM, "unknown\n");
2516 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002517 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002518
2519 /* signal handling */
2520 switch (foh->msg_type) {
2521 case NM_MT_IPACC_RSL_CONNECT_NACK:
2522 case NM_MT_IPACC_SET_NVATTR_NACK:
2523 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002524 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002525 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002526 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002527 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002528 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002529 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002530 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002531 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002532 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002533 default:
2534 break;
2535 }
2536
Harald Welte677c21f2009-02-17 13:22:23 +00002537 return 0;
2538}
2539
Harald Welte193fefc2009-04-30 15:16:27 +00002540/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002541int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2542 uint8_t obj_class, uint8_t bts_nr,
2543 uint8_t trx_nr, uint8_t ts_nr,
2544 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002545{
2546 struct msgb *msg = nm_msgb_alloc();
2547 struct abis_om_hdr *oh;
2548 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002549 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002550
2551 /* construct the 12.21 OM header, observe the erroneous length */
2552 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2553 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2554 oh->mdisc = ABIS_OM_MDISC_MANUF;
2555
2556 /* add the ip.access magic */
2557 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2558 *data++ = sizeof(ipaccess_magic);
2559 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2560
2561 /* fill the 12.21 FOM header */
2562 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2563 foh->msg_type = msg_type;
2564 foh->obj_class = obj_class;
2565 foh->obj_inst.bts_nr = bts_nr;
2566 foh->obj_inst.trx_nr = trx_nr;
2567 foh->obj_inst.ts_nr = ts_nr;
2568
2569 if (attr && attr_len) {
2570 data = msgb_put(msg, attr_len);
2571 memcpy(data, attr, attr_len);
2572 }
2573
2574 return abis_nm_sendmsg(bts, msg);
2575}
Harald Welte677c21f2009-02-17 13:22:23 +00002576
Harald Welte193fefc2009-04-30 15:16:27 +00002577/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002578int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002579 int attr_len)
2580{
Harald Welte2ef156d2010-01-07 20:39:42 +01002581 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2582 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002583 attr_len);
2584}
2585
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002586int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002587 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002588{
2589 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002590 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002591 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2592 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2593
2594 int attr_len = sizeof(attr);
2595
2596 ia.s_addr = htonl(ip);
2597 attr[1] = stream;
2598 attr[3] = port >> 8;
2599 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002600 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002601
2602 /* if ip == 0, we use the default IP */
2603 if (ip == 0)
2604 attr_len -= 5;
2605
2606 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002607 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002608
2609 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2610 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2611 trx->nr, 0xff, attr, attr_len);
2612}
2613
Harald Welte193fefc2009-04-30 15:16:27 +00002614/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002615int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002616{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002617 struct abis_om_hdr *oh;
2618 struct msgb *msg = nm_msgb_alloc();
2619
2620 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2621 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2622 trx->bts->nr, trx->nr, 0xff);
2623
2624 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002625}
Harald Weltedaef5212009-10-24 10:20:41 +02002626
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002627int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2628 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2629 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002630{
2631 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2632 obj_class, bts_nr, trx_nr, ts_nr,
2633 attr, attr_len);
2634}
Harald Welte0f255852009-11-12 14:48:42 +01002635
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002636void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002637{
2638 /* we simply reuse the GSM48 function and overwrite the RAC
2639 * with the Cell ID */
2640 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002641 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002642}
2643
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002644void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2645{
2646 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2647
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002648 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002649 if (!trx->bts || !trx->bts->oml_link)
2650 return;
2651
2652 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2653 trx->bts->bts_nr, trx->nr, 0xff,
2654 new_state);
2655}
2656
Harald Welte92b1fe42010-03-25 11:45:30 +08002657static const struct value_string ipacc_testres_names[] = {
2658 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2659 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2660 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2661 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2662 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2663 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002664};
2665
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002666const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002667{
Harald Welte92b1fe42010-03-25 11:45:30 +08002668 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002669}
2670
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002671void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002672{
2673 cid->mcc = (buf[0] & 0xf) * 100;
2674 cid->mcc += (buf[0] >> 4) * 10;
2675 cid->mcc += (buf[1] & 0xf) * 1;
2676
2677 if (buf[1] >> 4 == 0xf) {
2678 cid->mnc = (buf[2] & 0xf) * 10;
2679 cid->mnc += (buf[2] >> 4) * 1;
2680 } else {
2681 cid->mnc = (buf[2] & 0xf) * 100;
2682 cid->mnc += (buf[2] >> 4) * 10;
2683 cid->mnc += (buf[1] >> 4) * 1;
2684 }
2685
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002686 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2687 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002688}
2689
Harald Welte0f255852009-11-12 14:48:42 +01002690/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002691int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002692{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002693 uint8_t *cur = buf;
2694 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01002695
Harald Welteaf109b92010-07-22 18:14:36 +02002696 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002697
2698 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2699 return -EINVAL;
2700 cur++;
2701
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002702 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002703 cur += 2;
2704
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002705 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002706 cur += 2;
2707
2708 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2709 binf->freq_qual = *cur >> 2;
2710
Harald Welteaf109b92010-07-22 18:14:36 +02002711 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002712 binf->arfcn |= *cur++;
2713
2714 if (binf->info_type & IPAC_BINF_RXLEV)
2715 binf->rx_lev = *cur & 0x3f;
2716 cur++;
2717
2718 if (binf->info_type & IPAC_BINF_RXQUAL)
2719 binf->rx_qual = *cur & 0x7;
2720 cur++;
2721
2722 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002723 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002724 cur += 2;
2725
2726 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002727 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002728 cur += 2;
2729
2730 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002731 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002732 cur += 4;
2733
Harald Weltea780a3d2010-07-30 22:34:42 +02002734#if 0
2735 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002736 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002737#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002738 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002739 cur++;
2740
Harald Welteb40a38f2009-11-13 11:56:05 +01002741 ipac_parse_cgi(&binf->cgi, cur);
2742 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002743
2744 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2745 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2746 cur += sizeof(binf->ba_list_si2);
2747 }
2748
2749 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2750 memcpy(binf->ba_list_si2bis, cur,
2751 sizeof(binf->ba_list_si2bis));
2752 cur += sizeof(binf->ba_list_si2bis);
2753 }
2754
2755 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2756 memcpy(binf->ba_list_si2ter, cur,
2757 sizeof(binf->ba_list_si2ter));
2758 cur += sizeof(binf->ba_list_si2ter);
2759 }
2760
2761 return 0;
2762}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002763
2764void abis_nm_clear_queue(struct gsm_bts *bts)
2765{
2766 struct msgb *msg;
2767
2768 while (!llist_empty(&bts->abis_queue)) {
2769 msg = msgb_dequeue(&bts->abis_queue);
2770 msgb_free(msg);
2771 }
2772
2773 bts->abis_nm_pend = 0;
2774}