blob: e6111f5880d35fe32ad35a076cd45e9cda5db7a0 [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000043#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Harald Welte52b1f982008-12-23 20:25:15 +000046
Harald Welte8470bf22008-12-25 23:28:35 +000047#define OM_ALLOC_SIZE 1024
48#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010049#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000050
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020051int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +000052{
Harald Welte39315c42010-01-10 18:01:52 +010053 if (!bts->model)
54 return -EIO;
55 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000056}
Harald Weltee0590df2009-02-15 03:34:15 +000057
Harald Welte52b1f982008-12-23 20:25:15 +000058static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
59{
60 int i;
61
62 for (i = 0; i < size; i++) {
63 if (arr[i] == mt)
64 return 1;
65 }
66
67 return 0;
68}
69
Holger Freytherca362a62009-01-04 21:05:01 +000070#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000071/* is this msgtype the usual ACK/NACK type ? */
72static int is_ack_nack(enum abis_nm_msgtype mt)
73{
74 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
75}
Holger Freytherca362a62009-01-04 21:05:01 +000076#endif
Harald Welte52b1f982008-12-23 20:25:15 +000077
78/* is this msgtype a report ? */
79static int is_report(enum abis_nm_msgtype mt)
80{
Harald Welte15c61722011-05-22 22:45:37 +020081 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000082}
83
84#define MT_ACK(x) (x+1)
85#define MT_NACK(x) (x+2)
86
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020087static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000088{
89 oh->mdisc = ABIS_OM_MDISC_FOM;
90 oh->placement = ABIS_OM_PLACEMENT_ONLY;
91 oh->sequence = 0;
92 oh->length = len;
93}
94
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020095static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
96 uint8_t msg_type, uint8_t obj_class,
97 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +000098{
99 struct abis_om_fom_hdr *foh =
100 (struct abis_om_fom_hdr *) oh->data;
101
Harald Welte702d8702008-12-26 20:25:35 +0000102 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000103 foh->msg_type = msg_type;
104 foh->obj_class = obj_class;
105 foh->obj_inst.bts_nr = bts_nr;
106 foh->obj_inst.trx_nr = trx_nr;
107 foh->obj_inst.ts_nr = ts_nr;
108}
109
Harald Welte8470bf22008-12-25 23:28:35 +0000110static struct msgb *nm_msgb_alloc(void)
111{
Harald Welte966636f2009-06-26 19:39:35 +0200112 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
113 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000114}
115
Harald Welte52b1f982008-12-23 20:25:15 +0000116/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100117static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000118{
Holger Freyther59639e82009-02-09 23:09:55 +0000119 msg->trx = bts->c0;
120
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100121 /* queue OML messages */
122 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
123 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100124 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100125 } else {
126 msgb_enqueue(&bts->abis_queue, msg);
127 return 0;
128 }
129
130}
131
132int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
133{
134 OBSC_NM_W_ACK_CB(msg) = 1;
135 return abis_nm_queue_msg(bts, msg);
136}
137
138static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
139{
140 OBSC_NM_W_ACK_CB(msg) = 0;
141 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000142}
143
Harald Welte4724f992009-01-18 18:01:49 +0000144static int abis_nm_rcvmsg_sw(struct msgb *mb);
145
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100146int nm_is_running(struct gsm_nm_state *s) {
147 return (s->operational == NM_OPSTATE_ENABLED) && (
148 (s->availability == NM_AVSTATE_OK) ||
149 (s->availability == 0xff)
150 );
151}
152
Harald Welted64c0bc2011-05-30 12:07:53 +0200153/* obtain the MO structure for a given object instance */
154static struct gsm_abis_mo *
155objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
156 struct abis_om_obj_inst *obj_inst)
Harald Weltee0590df2009-02-15 03:34:15 +0000157{
158 struct gsm_bts_trx *trx;
Harald Welted64c0bc2011-05-30 12:07:53 +0200159 struct gsm_abis_mo *mo = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +0000160
161 switch (obj_class) {
162 case NM_OC_BTS:
Harald Welted64c0bc2011-05-30 12:07:53 +0200163 mo = &bts->mo;
Harald Weltee0590df2009-02-15 03:34:15 +0000164 break;
165 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100166 if (obj_inst->trx_nr >= bts->num_trx) {
167 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000168 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100169 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200170 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welted64c0bc2011-05-30 12:07:53 +0200171 mo = &trx->mo;
Harald Weltee0590df2009-02-15 03:34:15 +0000172 break;
173 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100174 if (obj_inst->trx_nr >= bts->num_trx) {
175 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000176 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100177 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200178 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welted64c0bc2011-05-30 12:07:53 +0200179 mo = &trx->bb_transc.mo;
Harald Weltee0590df2009-02-15 03:34:15 +0000180 break;
181 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100182 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100183 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000184 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100185 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200186 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000187 if (obj_inst->ts_nr >= TRX_NR_TS)
188 return NULL;
Harald Welted64c0bc2011-05-30 12:07:53 +0200189 mo = &trx->ts[obj_inst->ts_nr].mo;
Harald Weltee0590df2009-02-15 03:34:15 +0000190 break;
191 case NM_OC_SITE_MANAGER:
Harald Welted64c0bc2011-05-30 12:07:53 +0200192 mo = &bts->site_mgr.mo;
Harald Weltee0590df2009-02-15 03:34:15 +0000193 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000194 case NM_OC_BS11:
195 switch (obj_inst->bts_nr) {
196 case BS11_OBJ_CCLK:
Harald Welted64c0bc2011-05-30 12:07:53 +0200197 mo = &bts->bs11.cclk.mo;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000198 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000199 case BS11_OBJ_BBSIG:
200 if (obj_inst->ts_nr > bts->num_trx)
201 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200202 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welted64c0bc2011-05-30 12:07:53 +0200203 mo = &trx->bs11.bbsig.mo;
Harald Welte8b697c72009-06-05 19:18:45 +0000204 break;
205 case BS11_OBJ_PA:
206 if (obj_inst->ts_nr > bts->num_trx)
207 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200208 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welted64c0bc2011-05-30 12:07:53 +0200209 mo = &trx->bs11.pa.mo;
Harald Welte8b697c72009-06-05 19:18:45 +0000210 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000211 default:
212 return NULL;
213 }
214 case NM_OC_BS11_RACK:
Harald Welted64c0bc2011-05-30 12:07:53 +0200215 mo = &bts->bs11.rack.mo;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000216 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000217 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100218 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000219 return NULL;
Harald Welted64c0bc2011-05-30 12:07:53 +0200220 mo = &bts->bs11.envabtse[obj_inst->trx_nr].mo;
Harald Welte8b697c72009-06-05 19:18:45 +0000221 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200222 case NM_OC_GPRS_NSE:
Harald Welted64c0bc2011-05-30 12:07:53 +0200223 mo = &bts->gprs.nse.mo;
Harald Welte55dd4432009-10-24 10:19:14 +0200224 break;
225 case NM_OC_GPRS_CELL:
Harald Welted64c0bc2011-05-30 12:07:53 +0200226 mo = &bts->gprs.cell.mo;
Harald Welte55dd4432009-10-24 10:19:14 +0200227 break;
228 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100229 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200230 return NULL;
Harald Welted64c0bc2011-05-30 12:07:53 +0200231 mo = &bts->gprs.nsvc[obj_inst->trx_nr].mo;
Harald Welte55dd4432009-10-24 10:19:14 +0200232 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000233 }
Harald Welted64c0bc2011-05-30 12:07:53 +0200234 return mo;
235}
236
237/* obtain the gsm_nm_state data structure for a given object instance */
238static struct gsm_nm_state *
239objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
240 struct abis_om_obj_inst *obj_inst)
241{
242 struct gsm_abis_mo *mo;
243
244 mo = objclass2mo(bts, obj_class, obj_inst);
245 if (!mo)
246 return NULL;
247
248 return &mo->nm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000249}
250
251/* obtain the in-memory data structure of a given object instance */
252static void *
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200253objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
Harald Weltee0590df2009-02-15 03:34:15 +0000254 struct abis_om_obj_inst *obj_inst)
255{
256 struct gsm_bts_trx *trx;
257 void *obj = NULL;
258
259 switch (obj_class) {
260 case NM_OC_BTS:
261 obj = bts;
262 break;
263 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100264 if (obj_inst->trx_nr >= bts->num_trx) {
265 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000266 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100267 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200268 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000269 obj = trx;
270 break;
271 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100272 if (obj_inst->trx_nr >= bts->num_trx) {
273 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000274 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100275 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200276 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000277 obj = &trx->bb_transc;
278 break;
279 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100280 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100281 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000282 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100283 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200284 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000285 if (obj_inst->ts_nr >= TRX_NR_TS)
286 return NULL;
287 obj = &trx->ts[obj_inst->ts_nr];
288 break;
289 case NM_OC_SITE_MANAGER:
290 obj = &bts->site_mgr;
291 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200292 case NM_OC_GPRS_NSE:
293 obj = &bts->gprs.nse;
294 break;
295 case NM_OC_GPRS_CELL:
296 obj = &bts->gprs.cell;
297 break;
298 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100299 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200300 return NULL;
301 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
302 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000303 }
304 return obj;
305}
306
307/* Update the administrative state of a given object in our in-memory data
308 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200309static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
310 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000311{
Harald Welteaeedeb42009-05-01 13:08:14 +0000312 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100313 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000314
Harald Welteaf9b8102011-03-06 21:20:38 +0100315 memset(&nsd, 0, sizeof(nsd));
316
Harald Weltef338a032011-01-14 15:55:42 +0100317 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
318 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100319 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000320 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
321 if (!nm_state)
322 return -1;
323
324 new_state = *nm_state;
325 new_state.administrative = adm_state;
326
Harald Weltef38ca9a2011-03-06 22:11:32 +0100327 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100328 nsd.obj_class = obj_class;
329 nsd.old_state = nm_state;
330 nsd.new_state = &new_state;
331 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200332 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000333
334 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000335
Harald Weltef338a032011-01-14 15:55:42 +0100336 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000337}
338
Harald Welte97ed1e72009-02-06 13:38:02 +0000339static int abis_nm_rx_statechg_rep(struct msgb *mb)
340{
Harald Weltee0590df2009-02-15 03:34:15 +0000341 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000342 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000343 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000344 struct tlv_parsed tp;
345 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000346
Harald Welte23897662009-05-01 14:52:51 +0000347 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000348
Harald Welte8b697c72009-06-05 19:18:45 +0000349 memset(&new_state, 0, sizeof(new_state));
350
Harald Weltee0590df2009-02-15 03:34:15 +0000351 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
352 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100353 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000354 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000355 }
Harald Weltee0590df2009-02-15 03:34:15 +0000356
357 new_state = *nm_state;
358
Harald Welte39315c42010-01-10 18:01:52 +0100359 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000360 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
361 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200362 DEBUGPC(DNM, "OP_STATE=%s ",
363 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000364 }
365 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000366 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
367 new_state.availability = 0xff;
368 else
369 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200370 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
371 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000372 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100373 } else
374 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000375 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
376 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200377 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200378 get_value_string(abis_nm_adm_state_names,
379 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000380 }
381 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000382
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100383 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
384 new_state.operational != nm_state->operational ||
385 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000386 /* Update the operational state of a given object in our in-memory data
387 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100388 struct nm_statechg_signal_data nsd;
389 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
390 nsd.obj_class = foh->obj_class;
391 nsd.old_state = nm_state;
392 nsd.new_state = &new_state;
393 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100394 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200395 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100396 nm_state->operational = new_state.operational;
397 nm_state->availability = new_state.availability;
398 if (nm_state->administrative == 0)
399 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000400 }
401#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000402 if (op_state == 1) {
403 /* try to enable objects that are disabled */
404 abis_nm_opstart(bts, foh->obj_class,
405 foh->obj_inst.bts_nr,
406 foh->obj_inst.trx_nr,
407 foh->obj_inst.ts_nr);
408 }
Harald Weltee0590df2009-02-15 03:34:15 +0000409#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000410 return 0;
411}
412
Harald Welte0db97b22009-05-01 17:22:47 +0000413static int rx_fail_evt_rep(struct msgb *mb)
414{
415 struct abis_om_hdr *oh = msgb_l2(mb);
416 struct abis_om_fom_hdr *foh = msgb_l3(mb);
417 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100418 const uint8_t *p_val;
419 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000420
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200421 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000422
Harald Welte39315c42010-01-10 18:01:52 +0100423 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000424
425 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Welte15c61722011-05-22 22:45:37 +0200426 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
427 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000428 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Welte15c61722011-05-22 22:45:37 +0200429 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
430 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100431 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
432 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200433 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 +0100434 }
435 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
436 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
437 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
438 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200439 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100440 talloc_free(p_text);
441 }
442 }
Harald Welte0db97b22009-05-01 17:22:47 +0000443
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200444 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000445
446 return 0;
447}
448
Harald Welte97ed1e72009-02-06 13:38:02 +0000449static int abis_nm_rcvmsg_report(struct msgb *mb)
450{
451 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200452 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000453
Harald Welte15c61722011-05-22 22:45:37 +0200454 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000455
Harald Welte97ed1e72009-02-06 13:38:02 +0000456 //nmh->cfg->report_cb(mb, foh);
457
458 switch (mt) {
459 case NM_MT_STATECHG_EVENT_REP:
460 return abis_nm_rx_statechg_rep(mb);
461 break;
Harald Welte34a99682009-02-13 02:41:40 +0000462 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000463 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200464 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000465 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000466 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000467 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200468 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000469 break;
Harald Weltec7310382009-08-08 00:02:36 +0200470 case NM_MT_TEST_REP:
471 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200472 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200473 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000474 default:
Harald Welte23897662009-05-01 14:52:51 +0000475 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000476 break;
477
Harald Welte97ed1e72009-02-06 13:38:02 +0000478 };
479
Harald Welte97ed1e72009-02-06 13:38:02 +0000480 return 0;
481}
482
Harald Welte34a99682009-02-13 02:41:40 +0000483/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200484static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
485 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000486{
487 struct abis_om_hdr *oh;
488 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200489 uint8_t len = swdesc_len;
490 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000491
492 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
493 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
494
495 trailer = msgb_put(msg, swdesc_len);
496 memcpy(trailer, sw_desc, swdesc_len);
497
498 return abis_nm_sendmsg(bts, msg);
499}
500
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200501static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100502{
503 static const struct tlv_definition sw_descr_def = {
504 .def = {
505 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
506 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
507 },
508 };
509
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200510 uint8_t tag;
511 uint16_t tag_len;
512 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100513 int ofs = 0, len;
514
515 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
516 * nested nature and the fact you have to assume it contains only two sub
517 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
518
519 if (sw_descr[0] != NM_ATT_SW_DESCR) {
520 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
521 return -1;
522 }
523 ofs += 1;
524
525 len = tlv_parse_one(&tag, &tag_len, &val,
526 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
527 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
528 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
529 return -2;
530 }
531 ofs += len;
532
533 len = tlv_parse_one(&tag, &tag_len, &val,
534 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
535 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
536 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
537 return -3;
538 }
539 ofs += len;
540
541 return ofs;
542}
543
Harald Welte34a99682009-02-13 02:41:40 +0000544static int abis_nm_rx_sw_act_req(struct msgb *mb)
545{
546 struct abis_om_hdr *oh = msgb_l2(mb);
547 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200548 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200549 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100550 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000551
Harald Welte15c61722011-05-22 22:45:37 +0200552 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200553
554 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000555
Harald Welte97a282b2010-03-14 15:37:43 +0800556 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000557
558 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000559 foh->obj_inst.bts_nr,
560 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800561 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000562 foh->data, oh->length-sizeof(*foh));
563
Harald Welte39315c42010-01-10 18:01:52 +0100564 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200565 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
566 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
567 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
568 DEBUGP(DNM, "SW config not found! Can't continue.\n");
569 return -EINVAL;
570 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200571 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200572 }
573
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100574 /* Use the first SW_DESCR present in SW config */
575 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
576 if (sw_descr_len < 0)
577 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200578
Harald Welte34a99682009-02-13 02:41:40 +0000579 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
580 foh->obj_inst.bts_nr,
581 foh->obj_inst.trx_nr,
582 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100583 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000584}
585
Harald Weltee0590df2009-02-15 03:34:15 +0000586/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
587static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
588{
589 struct abis_om_hdr *oh = msgb_l2(mb);
590 struct abis_om_fom_hdr *foh = msgb_l3(mb);
591 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200592 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000593
Harald Welte39315c42010-01-10 18:01:52 +0100594 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000595 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
596 return -EINVAL;
597
598 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
599
600 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
601}
602
Harald Welteee670472009-02-22 21:58:49 +0000603static int abis_nm_rx_lmt_event(struct msgb *mb)
604{
605 struct abis_om_hdr *oh = msgb_l2(mb);
606 struct abis_om_fom_hdr *foh = msgb_l3(mb);
607 struct tlv_parsed tp;
608
609 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100610 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000611 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
612 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200613 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000614 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
615 }
616 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
617 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200618 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000619 DEBUGPC(DNM, "Level=%u ", level);
620 }
621 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
622 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
623 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
624 DEBUGPC(DNM, "Username=%s ", name);
625 }
626 DEBUGPC(DNM, "\n");
627 /* FIXME: parse LMT LOGON TIME */
628 return 0;
629}
630
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100631static void abis_nm_queue_send_next(struct gsm_bts *bts)
632{
633 int wait = 0;
634 struct msgb *msg;
635 /* the queue is empty */
636 while (!llist_empty(&bts->abis_queue)) {
637 msg = msgb_dequeue(&bts->abis_queue);
638 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100639 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100640
641 if (wait)
642 break;
643 }
644
645 bts->abis_nm_pend = wait;
646}
647
Harald Welte52b1f982008-12-23 20:25:15 +0000648/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000649static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000650{
Harald Welte6c96ba52009-05-01 13:03:40 +0000651 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000652 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200653 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100654 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000655
656 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000657 if (is_report(mt))
658 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000659
Harald Welte15c61722011-05-22 22:45:37 +0200660 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000661 return abis_nm_rcvmsg_sw(mb);
662
Harald Welte15c61722011-05-22 22:45:37 +0200663 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800664 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000665 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200666
Harald Welte15c61722011-05-22 22:45:37 +0200667 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200668
Harald Welte15c61722011-05-22 22:45:37 +0200669 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000670
Harald Welte39315c42010-01-10 18:01:52 +0100671 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000672 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200673 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200674 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000675 else
676 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200677
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800678 nack_data.msg = mb;
679 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200680 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100681 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200682 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000683 }
Harald Weltead384642008-12-26 10:20:07 +0000684#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000685 /* check if last message is to be acked */
686 if (is_ack_nack(nmh->last_msgtype)) {
687 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100688 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000689 /* we got our ACK, continue sending the next msg */
690 } else if (mt == MT_NACK(nmh->last_msgtype)) {
691 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100692 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000693 /* FIXME: somehow signal this to the caller */
694 } else {
695 /* really strange things happen */
696 return -EINVAL;
697 }
698 }
Harald Weltead384642008-12-26 10:20:07 +0000699#endif
700
Harald Welte97ed1e72009-02-06 13:38:02 +0000701 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000702 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100703 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000704 break;
Harald Welte34a99682009-02-13 02:41:40 +0000705 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100706 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000707 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000708 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100709 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000710 break;
Harald Welte1989c082009-08-06 17:58:31 +0200711 case NM_MT_CONN_MDROP_LINK_ACK:
712 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
713 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100714 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200715 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100716 break;
717 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200718 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100719 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100720 case NM_MT_SET_BTS_ATTR_ACK:
721 /* The HSL wants an OPSTART _after_ the SI has been set */
722 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
723 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
724 }
725 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000726 }
727
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100728 abis_nm_queue_send_next(mb->trx->bts);
729 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000730}
731
Harald Welte677c21f2009-02-17 13:22:23 +0000732static int abis_nm_rx_ipacc(struct msgb *mb);
733
734static int abis_nm_rcvmsg_manuf(struct msgb *mb)
735{
736 int rc;
737 int bts_type = mb->trx->bts->type;
738
739 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100740 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000741 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100742 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000743 break;
744 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100745 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
746 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000747 rc = 0;
748 break;
749 }
750
751 return rc;
752}
753
Harald Welte52b1f982008-12-23 20:25:15 +0000754/* High-Level API */
755/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000756int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000757{
Harald Welte52b1f982008-12-23 20:25:15 +0000758 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000759 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000760
761 /* Various consistency checks */
762 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100763 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000764 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +0200765 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
766 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +0000767 }
768 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100769 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000770 oh->sequence);
771 return -EINVAL;
772 }
Harald Welte702d8702008-12-26 20:25:35 +0000773#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200774 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000775 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000776 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100777 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000778 oh->length + sizeof(*oh), l2_len);
779 return -EINVAL;
780 }
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 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 +0000783#endif
Harald Weltead384642008-12-26 10:20:07 +0000784 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000785
786 switch (oh->mdisc) {
787 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000788 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000789 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000790 case ABIS_OM_MDISC_MANUF:
791 rc = abis_nm_rcvmsg_manuf(msg);
792 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000793 case ABIS_OM_MDISC_MMI:
794 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100795 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000796 oh->mdisc);
797 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000798 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100799 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000800 oh->mdisc);
801 return -EINVAL;
802 }
803
Harald Weltead384642008-12-26 10:20:07 +0000804 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000805 return rc;
806}
807
808#if 0
809/* initialized all resources */
810struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
811{
812 struct abis_nm_h *nmh;
813
814 nmh = malloc(sizeof(*nmh));
815 if (!nmh)
816 return NULL;
817
818 nmh->cfg = cfg;
819
820 return nmh;
821}
822
823/* free all resources */
824void abis_nm_fini(struct abis_nm_h *nmh)
825{
826 free(nmh);
827}
828#endif
829
830/* Here we are trying to define a high-level API that can be used by
831 * the actual BSC implementation. However, the architecture is currently
832 * still under design. Ideally the calls to this API would be synchronous,
833 * while the underlying stack behind the APi runs in a traditional select
834 * based state machine.
835 */
836
Harald Welte4724f992009-01-18 18:01:49 +0000837/* 6.2 Software Load: */
838enum sw_state {
839 SW_STATE_NONE,
840 SW_STATE_WAIT_INITACK,
841 SW_STATE_WAIT_SEGACK,
842 SW_STATE_WAIT_ENDACK,
843 SW_STATE_WAIT_ACTACK,
844 SW_STATE_ERROR,
845};
Harald Welte52b1f982008-12-23 20:25:15 +0000846
Harald Welte52b1f982008-12-23 20:25:15 +0000847struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000848 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800849 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000850 gsm_cbfn *cbfn;
851 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000852 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000853
Harald Welte52b1f982008-12-23 20:25:15 +0000854 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200855 uint8_t obj_class;
856 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000857
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200858 uint8_t file_id[255];
859 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000860
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200861 uint8_t file_version[255];
862 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000863
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200864 uint8_t window_size;
865 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000866
867 int fd;
868 FILE *stream;
869 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000870 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000871};
872
Harald Welte4724f992009-01-18 18:01:49 +0000873static struct abis_nm_sw g_sw;
874
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100875static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
876{
877 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
878 msgb_v_put(msg, NM_ATT_SW_DESCR);
879 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
880 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
881 sw->file_version);
882 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
883 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
884 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
885 sw->file_version);
886 } else {
887 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
888 }
889}
890
Harald Welte4724f992009-01-18 18:01:49 +0000891/* 6.2.1 / 8.3.1: Load Data Initiate */
892static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000893{
Harald Welte4724f992009-01-18 18:01:49 +0000894 struct abis_om_hdr *oh;
895 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200896 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000897
898 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
899 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
900 sw->obj_instance[0], sw->obj_instance[1],
901 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100902
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100903 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000904 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
905
906 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000907}
908
Harald Welte1602ade2009-01-29 21:12:39 +0000909static int is_last_line(FILE *stream)
910{
911 char next_seg_buf[256];
912 long pos;
913
914 /* check if we're sending the last line */
915 pos = ftell(stream);
916 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
917 fseek(stream, pos, SEEK_SET);
918 return 1;
919 }
920
921 fseek(stream, pos, SEEK_SET);
922 return 0;
923}
924
Harald Welte4724f992009-01-18 18:01:49 +0000925/* 6.2.2 / 8.3.2 Load Data Segment */
926static int sw_load_segment(struct abis_nm_sw *sw)
927{
928 struct abis_om_hdr *oh;
929 struct msgb *msg = nm_msgb_alloc();
930 char seg_buf[256];
931 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000932 unsigned char *tlv;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200933 uint8_t len;
Harald Welte4724f992009-01-18 18:01:49 +0000934
935 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000936
937 switch (sw->bts->type) {
938 case GSM_BTS_TYPE_BS11:
939 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
940 perror("fgets reading segment");
941 return -EINVAL;
942 }
943 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000944
945 /* check if we're sending the last line */
946 sw->last_seg = is_last_line(sw->stream);
947 if (sw->last_seg)
948 seg_buf[1] = 0;
949 else
950 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000951
952 len = strlen(line_buf) + 2;
953 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200954 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000955 /* BS11 wants CR + LF in excess of the TLV length !?! */
956 tlv[1] -= 2;
957
958 /* we only now know the exact length for the OM hdr */
959 len = strlen(line_buf)+2;
960 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100961 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200962 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100963 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
964 if (len < 0) {
965 perror("read failed");
966 return -EINVAL;
967 }
968
969 if (len != IPACC_SEGMENT_SIZE)
970 sw->last_seg = 1;
971
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100972 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200973 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100974 len += 3;
975 break;
976 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000977 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100978 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000979 /* FIXME: Other BTS types */
980 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000981 }
Harald Welte4724f992009-01-18 18:01:49 +0000982
Harald Welte4724f992009-01-18 18:01:49 +0000983 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
984 sw->obj_instance[0], sw->obj_instance[1],
985 sw->obj_instance[2]);
986
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100987 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000988}
989
990/* 6.2.4 / 8.3.4 Load Data End */
991static int sw_load_end(struct abis_nm_sw *sw)
992{
993 struct abis_om_hdr *oh;
994 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200995 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000996
997 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
998 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
999 sw->obj_instance[0], sw->obj_instance[1],
1000 sw->obj_instance[2]);
1001
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001002 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001003 return abis_nm_sendmsg(sw->bts, msg);
1004}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001005
Harald Welte52b1f982008-12-23 20:25:15 +00001006/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001007static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001008{
Harald Welte4724f992009-01-18 18:01:49 +00001009 struct abis_om_hdr *oh;
1010 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001011 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001012
Harald Welte4724f992009-01-18 18:01:49 +00001013 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1014 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1015 sw->obj_instance[0], sw->obj_instance[1],
1016 sw->obj_instance[2]);
1017
1018 /* FIXME: this is BS11 specific format */
1019 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1020 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1021 sw->file_version);
1022
1023 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001024}
Harald Welte4724f992009-01-18 18:01:49 +00001025
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001026struct sdp_firmware {
1027 char magic[4];
1028 char more_magic[4];
1029 unsigned int header_length;
1030 unsigned int file_length;
1031} __attribute__ ((packed));
1032
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001033static int parse_sdp_header(struct abis_nm_sw *sw)
1034{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001035 struct sdp_firmware firmware_header;
1036 int rc;
1037 struct stat stat;
1038
1039 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1040 if (rc != sizeof(firmware_header)) {
1041 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1042 return -1;
1043 }
1044
1045 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1046 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1047 return -1;
1048 }
1049
1050 if (firmware_header.more_magic[0] != 0x10 ||
1051 firmware_header.more_magic[1] != 0x02 ||
1052 firmware_header.more_magic[2] != 0x00 ||
1053 firmware_header.more_magic[3] != 0x00) {
1054 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1055 return -1;
1056 }
1057
1058
1059 if (fstat(sw->fd, &stat) == -1) {
1060 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1061 return -1;
1062 }
1063
1064 if (ntohl(firmware_header.file_length) != stat.st_size) {
1065 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1066 return -1;
1067 }
1068
1069 /* go back to the start as we checked the whole filesize.. */
1070 lseek(sw->fd, 0l, SEEK_SET);
1071 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1072 "There might be checksums in the file that are not\n"
1073 "verified and incomplete firmware might be flashed.\n"
1074 "There is absolutely no WARRANTY that flashing will\n"
1075 "work.\n");
1076 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001077}
1078
Harald Welte4724f992009-01-18 18:01:49 +00001079static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1080{
1081 char file_id[12+1];
1082 char file_version[80+1];
1083 int rc;
1084
1085 sw->fd = open(fname, O_RDONLY);
1086 if (sw->fd < 0)
1087 return sw->fd;
1088
1089 switch (sw->bts->type) {
1090 case GSM_BTS_TYPE_BS11:
1091 sw->stream = fdopen(sw->fd, "r");
1092 if (!sw->stream) {
1093 perror("fdopen");
1094 return -1;
1095 }
1096 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001097 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001098 file_id, file_version);
1099 if (rc != 2) {
1100 perror("parsing header line of software file");
1101 return -1;
1102 }
1103 strcpy((char *)sw->file_id, file_id);
1104 sw->file_id_len = strlen(file_id);
1105 strcpy((char *)sw->file_version, file_version);
1106 sw->file_version_len = strlen(file_version);
1107 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001108 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001109 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001110 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001111 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001112 rc = parse_sdp_header(sw);
1113 if (rc < 0) {
1114 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1115 return -1;
1116 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001117
1118 strcpy((char *)sw->file_id, "id");
1119 sw->file_id_len = 3;
1120 strcpy((char *)sw->file_version, "version");
1121 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001122 break;
Harald Welte4724f992009-01-18 18:01:49 +00001123 default:
1124 /* We don't know how to treat them yet */
1125 close(sw->fd);
1126 return -EINVAL;
1127 }
1128
1129 return 0;
1130}
1131
1132static void sw_close_file(struct abis_nm_sw *sw)
1133{
1134 switch (sw->bts->type) {
1135 case GSM_BTS_TYPE_BS11:
1136 fclose(sw->stream);
1137 break;
1138 default:
1139 close(sw->fd);
1140 break;
1141 }
1142}
1143
1144/* Fill the window */
1145static int sw_fill_window(struct abis_nm_sw *sw)
1146{
1147 int rc;
1148
1149 while (sw->seg_in_window < sw->window_size) {
1150 rc = sw_load_segment(sw);
1151 if (rc < 0)
1152 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001153 if (sw->last_seg)
1154 break;
Harald Welte4724f992009-01-18 18:01:49 +00001155 }
1156 return 0;
1157}
1158
1159/* callback function from abis_nm_rcvmsg() handler */
1160static int abis_nm_rcvmsg_sw(struct msgb *mb)
1161{
1162 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1163 int rc = -1;
1164 struct abis_nm_sw *sw = &g_sw;
1165 enum sw_state old_state = sw->state;
1166
Harald Welte3ffd1372009-02-01 22:15:49 +00001167 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001168
1169 switch (sw->state) {
1170 case SW_STATE_WAIT_INITACK:
1171 switch (foh->msg_type) {
1172 case NM_MT_LOAD_INIT_ACK:
1173 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001174 if (sw->cbfn)
1175 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1176 NM_MT_LOAD_INIT_ACK, mb,
1177 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001178 rc = sw_fill_window(sw);
1179 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001180 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001181 break;
1182 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001183 if (sw->forced) {
1184 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1185 "Init NACK\n");
1186 if (sw->cbfn)
1187 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1188 NM_MT_LOAD_INIT_ACK, mb,
1189 sw->cb_data, NULL);
1190 rc = sw_fill_window(sw);
1191 sw->state = SW_STATE_WAIT_SEGACK;
1192 } else {
1193 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001194 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001195 if (sw->cbfn)
1196 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1197 NM_MT_LOAD_INIT_NACK, mb,
1198 sw->cb_data, NULL);
1199 sw->state = SW_STATE_ERROR;
1200 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001201 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001202 break;
1203 }
1204 break;
1205 case SW_STATE_WAIT_SEGACK:
1206 switch (foh->msg_type) {
1207 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001208 if (sw->cbfn)
1209 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1210 NM_MT_LOAD_SEG_ACK, mb,
1211 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001212 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001213 if (!sw->last_seg) {
1214 /* fill window with more segments */
1215 rc = sw_fill_window(sw);
1216 sw->state = SW_STATE_WAIT_SEGACK;
1217 } else {
1218 /* end the transfer */
1219 sw->state = SW_STATE_WAIT_ENDACK;
1220 rc = sw_load_end(sw);
1221 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001222 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001223 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001224 case NM_MT_LOAD_ABORT:
1225 if (sw->cbfn)
1226 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1227 NM_MT_LOAD_ABORT, mb,
1228 sw->cb_data, NULL);
1229 break;
Harald Welte4724f992009-01-18 18:01:49 +00001230 }
1231 break;
1232 case SW_STATE_WAIT_ENDACK:
1233 switch (foh->msg_type) {
1234 case NM_MT_LOAD_END_ACK:
1235 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001236 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1237 sw->bts->nr);
1238 sw->state = SW_STATE_NONE;
1239 if (sw->cbfn)
1240 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1241 NM_MT_LOAD_END_ACK, mb,
1242 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001243 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001244 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001245 break;
1246 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001247 if (sw->forced) {
1248 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1249 "End NACK\n");
1250 sw->state = SW_STATE_NONE;
1251 if (sw->cbfn)
1252 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1253 NM_MT_LOAD_END_ACK, mb,
1254 sw->cb_data, NULL);
1255 } else {
1256 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001257 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001258 sw->state = SW_STATE_ERROR;
1259 if (sw->cbfn)
1260 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1261 NM_MT_LOAD_END_NACK, mb,
1262 sw->cb_data, NULL);
1263 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001264 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001265 break;
1266 }
1267 case SW_STATE_WAIT_ACTACK:
1268 switch (foh->msg_type) {
1269 case NM_MT_ACTIVATE_SW_ACK:
1270 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001271 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001272 sw->state = SW_STATE_NONE;
1273 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001274 if (sw->cbfn)
1275 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1276 NM_MT_ACTIVATE_SW_ACK, mb,
1277 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001278 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001279 break;
1280 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001281 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001282 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001283 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001284 if (sw->cbfn)
1285 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1286 NM_MT_ACTIVATE_SW_NACK, mb,
1287 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001288 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001289 break;
1290 }
1291 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001292 switch (foh->msg_type) {
1293 case NM_MT_ACTIVATE_SW_ACK:
1294 rc = 0;
1295 break;
1296 }
1297 break;
Harald Welte4724f992009-01-18 18:01:49 +00001298 case SW_STATE_ERROR:
1299 break;
1300 }
1301
1302 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001303 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001304 foh->msg_type, old_state, sw->state);
1305
1306 return rc;
1307}
1308
1309/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001310int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001311 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001312 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001313{
1314 struct abis_nm_sw *sw = &g_sw;
1315 int rc;
1316
Harald Welte5e4d1b32009-02-01 13:36:56 +00001317 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1318 bts->nr, fname);
1319
Harald Welte4724f992009-01-18 18:01:49 +00001320 if (sw->state != SW_STATE_NONE)
1321 return -EBUSY;
1322
1323 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001324 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001325
1326 switch (bts->type) {
1327 case GSM_BTS_TYPE_BS11:
1328 sw->obj_class = NM_OC_SITE_MANAGER;
1329 sw->obj_instance[0] = 0xff;
1330 sw->obj_instance[1] = 0xff;
1331 sw->obj_instance[2] = 0xff;
1332 break;
1333 case GSM_BTS_TYPE_NANOBTS:
1334 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001335 sw->obj_instance[0] = sw->bts->nr;
1336 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001337 sw->obj_instance[2] = 0xff;
1338 break;
1339 case GSM_BTS_TYPE_UNKNOWN:
1340 default:
1341 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1342 return -1;
1343 break;
1344 }
Harald Welte4724f992009-01-18 18:01:49 +00001345 sw->window_size = win_size;
1346 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001347 sw->cbfn = cbfn;
1348 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001349 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001350
1351 rc = sw_open_file(sw, fname);
1352 if (rc < 0) {
1353 sw->state = SW_STATE_NONE;
1354 return rc;
1355 }
1356
1357 return sw_load_init(sw);
1358}
Harald Welte52b1f982008-12-23 20:25:15 +00001359
Harald Welte1602ade2009-01-29 21:12:39 +00001360int abis_nm_software_load_status(struct gsm_bts *bts)
1361{
1362 struct abis_nm_sw *sw = &g_sw;
1363 struct stat st;
1364 int rc, percent;
1365
1366 rc = fstat(sw->fd, &st);
1367 if (rc < 0) {
1368 perror("ERROR during stat");
1369 return rc;
1370 }
1371
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001372 if (sw->stream)
1373 percent = (ftell(sw->stream) * 100) / st.st_size;
1374 else
1375 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001376 return percent;
1377}
1378
Harald Welte5e4d1b32009-02-01 13:36:56 +00001379/* Activate the specified software into the BTS */
1380int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1381 gsm_cbfn *cbfn, void *cb_data)
1382{
1383 struct abis_nm_sw *sw = &g_sw;
1384 int rc;
1385
1386 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1387 bts->nr, fname);
1388
1389 if (sw->state != SW_STATE_NONE)
1390 return -EBUSY;
1391
1392 sw->bts = bts;
1393 sw->obj_class = NM_OC_SITE_MANAGER;
1394 sw->obj_instance[0] = 0xff;
1395 sw->obj_instance[1] = 0xff;
1396 sw->obj_instance[2] = 0xff;
1397 sw->state = SW_STATE_WAIT_ACTACK;
1398 sw->cbfn = cbfn;
1399 sw->cb_data = cb_data;
1400
1401 /* Open the file in order to fill some sw struct members */
1402 rc = sw_open_file(sw, fname);
1403 if (rc < 0) {
1404 sw->state = SW_STATE_NONE;
1405 return rc;
1406 }
1407 sw_close_file(sw);
1408
1409 return sw_activate(sw);
1410}
1411
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001412static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1413 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001414{
Harald Welteadaf08b2009-01-18 11:08:10 +00001415 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001416 ch->bts_port = bts_port;
1417 ch->timeslot = ts_nr;
1418 ch->subslot = subslot_nr;
1419}
1420
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001421int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1422 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1423 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001424{
1425 struct abis_om_hdr *oh;
1426 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001427 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001428 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001429
1430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1431 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1432 bts->bts_nr, trx_nr, 0xff);
1433
Harald Welte8470bf22008-12-25 23:28:35 +00001434 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001435
1436 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1437 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1438
1439 return abis_nm_sendmsg(bts, msg);
1440}
1441
1442/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1443int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001444 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001445{
Harald Welte8470bf22008-12-25 23:28:35 +00001446 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001447 struct abis_om_hdr *oh;
1448 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001449 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001450
1451 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001452 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001453 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1454
1455 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1456 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1457
1458 return abis_nm_sendmsg(bts, msg);
1459}
1460
1461#if 0
1462int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1463 struct abis_nm_abis_channel *chan)
1464{
1465}
1466#endif
1467
1468int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001469 uint8_t e1_port, uint8_t e1_timeslot,
1470 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001471{
1472 struct gsm_bts *bts = ts->trx->bts;
1473 struct abis_om_hdr *oh;
1474 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001475 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001476
1477 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1478 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001479 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001480
1481 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1482 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1483
Harald Weltef325eb42009-02-19 17:07:39 +00001484 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1485 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001486 e1_port, e1_timeslot, e1_subslot);
1487
Harald Welte52b1f982008-12-23 20:25:15 +00001488 return abis_nm_sendmsg(bts, msg);
1489}
1490
1491#if 0
1492int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1493 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001494 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001495{
1496}
1497#endif
1498
Harald Welte22af0db2009-02-14 15:41:08 +00001499/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001500int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001501{
1502 struct abis_om_hdr *oh;
1503 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001504 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001505
1506 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1507
1508 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001509 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 +00001510 cur = msgb_put(msg, attr_len);
1511 memcpy(cur, attr, attr_len);
1512
1513 return abis_nm_sendmsg(bts, msg);
1514}
1515
1516/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001517int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001518{
1519 struct abis_om_hdr *oh;
1520 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001521 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001522
1523 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1524
1525 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1526 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001527 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001528 cur = msgb_put(msg, attr_len);
1529 memcpy(cur, attr, attr_len);
1530
1531 return abis_nm_sendmsg(trx->bts, msg);
1532}
1533
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001534static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001535{
1536 int i;
1537
1538 /* As it turns out, the BS-11 has some very peculiar restrictions
1539 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301540 switch (ts->trx->bts->type) {
1541 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001542 switch (chan_comb) {
1543 case NM_CHANC_TCHHalf:
1544 case NM_CHANC_TCHHalf2:
1545 /* not supported */
1546 return -EINVAL;
1547 case NM_CHANC_SDCCH:
1548 /* only one SDCCH/8 per TRX */
1549 for (i = 0; i < TRX_NR_TS; i++) {
1550 if (i == ts->nr)
1551 continue;
1552 if (ts->trx->ts[i].nm_chan_comb ==
1553 NM_CHANC_SDCCH)
1554 return -EINVAL;
1555 }
1556 /* not allowed for TS0 of BCCH-TRX */
1557 if (ts->trx == ts->trx->bts->c0 &&
1558 ts->nr == 0)
1559 return -EINVAL;
1560 /* not on the same TRX that has a BCCH+SDCCH4
1561 * combination */
1562 if (ts->trx == ts->trx->bts->c0 &&
1563 (ts->trx->ts[0].nm_chan_comb == 5 ||
1564 ts->trx->ts[0].nm_chan_comb == 8))
1565 return -EINVAL;
1566 break;
1567 case NM_CHANC_mainBCCH:
1568 case NM_CHANC_BCCHComb:
1569 /* allowed only for TS0 of C0 */
1570 if (ts->trx != ts->trx->bts->c0 ||
1571 ts->nr != 0)
1572 return -EINVAL;
1573 break;
1574 case NM_CHANC_BCCH:
1575 /* allowed only for TS 2/4/6 of C0 */
1576 if (ts->trx != ts->trx->bts->c0)
1577 return -EINVAL;
1578 if (ts->nr != 2 && ts->nr != 4 &&
1579 ts->nr != 6)
1580 return -EINVAL;
1581 break;
1582 case 8: /* this is not like 08.58, but in fact
1583 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1584 /* FIXME: only one CBCH allowed per cell */
1585 break;
1586 }
Harald Welted6575f92009-12-02 02:45:23 +05301587 break;
1588 case GSM_BTS_TYPE_NANOBTS:
1589 switch (ts->nr) {
1590 case 0:
1591 if (ts->trx->nr == 0) {
1592 /* only on TRX0 */
1593 switch (chan_comb) {
1594 case NM_CHANC_BCCH:
1595 case NM_CHANC_mainBCCH:
1596 case NM_CHANC_BCCHComb:
1597 return 0;
1598 break;
1599 default:
1600 return -EINVAL;
1601 }
1602 } else {
1603 switch (chan_comb) {
1604 case NM_CHANC_TCHFull:
1605 case NM_CHANC_TCHHalf:
1606 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1607 return 0;
1608 default:
1609 return -EINVAL;
1610 }
1611 }
1612 break;
1613 case 1:
1614 if (ts->trx->nr == 0) {
1615 switch (chan_comb) {
1616 case NM_CHANC_SDCCH_CBCH:
1617 if (ts->trx->ts[0].nm_chan_comb ==
1618 NM_CHANC_mainBCCH)
1619 return 0;
1620 return -EINVAL;
1621 case NM_CHANC_SDCCH:
1622 case NM_CHANC_TCHFull:
1623 case NM_CHANC_TCHHalf:
1624 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1625 case NM_CHANC_IPAC_TCHFull_PDCH:
1626 return 0;
1627 }
1628 } else {
1629 switch (chan_comb) {
1630 case NM_CHANC_SDCCH:
1631 case NM_CHANC_TCHFull:
1632 case NM_CHANC_TCHHalf:
1633 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1634 return 0;
1635 default:
1636 return -EINVAL;
1637 }
1638 }
1639 break;
1640 case 2:
1641 case 3:
1642 case 4:
1643 case 5:
1644 case 6:
1645 case 7:
1646 switch (chan_comb) {
1647 case NM_CHANC_TCHFull:
1648 case NM_CHANC_TCHHalf:
1649 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1650 return 0;
1651 case NM_CHANC_IPAC_PDCH:
1652 case NM_CHANC_IPAC_TCHFull_PDCH:
1653 if (ts->trx->nr == 0)
1654 return 0;
1655 else
1656 return -EINVAL;
1657 }
1658 break;
1659 }
1660 return -EINVAL;
1661 default:
1662 /* unknown BTS type */
1663 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001664 }
1665 return 0;
1666}
1667
Harald Welte22af0db2009-02-14 15:41:08 +00001668/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001669int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001670{
1671 struct gsm_bts *bts = ts->trx->bts;
1672 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001673 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001674 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001675 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00001676
1677 if (bts->type == GSM_BTS_TYPE_BS11)
1678 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001679
Harald Weltef325eb42009-02-19 17:07:39 +00001680 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001681 if (verify_chan_comb(ts, chan_comb) < 0) {
1682 msgb_free(msg);
1683 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1684 return -EINVAL;
1685 }
1686 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001687
Harald Welte52b1f982008-12-23 20:25:15 +00001688 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001689 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001690 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001691 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001692 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001693 if (ts->hopping.enabled) {
1694 unsigned int i;
1695 uint8_t *len;
1696
Harald Welte6e0cd042009-09-12 13:05:33 +02001697 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1698 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001699
1700 /* build the ARFCN list */
1701 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1702 len = msgb_put(msg, 1);
1703 *len = 0;
1704 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1705 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1706 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001707 /* At least BS-11 wants a TLV16 here */
1708 if (bts->type == GSM_BTS_TYPE_BS11)
1709 *len += 1;
1710 else
1711 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001712 }
1713 }
Harald Weltee0590df2009-02-15 03:34:15 +00001714 }
Harald Welte135a6482011-05-30 12:09:13 +02001715 if (ts->tsc == -1)
1716 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1717 else
1718 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001719 if (bts->type == GSM_BTS_TYPE_BS11)
1720 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001721
1722 return abis_nm_sendmsg(bts, msg);
1723}
1724
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001725int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1726 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001727{
1728 struct abis_om_hdr *oh;
1729 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001730 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1731 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001732
1733 if (nack) {
1734 len += 2;
1735 msgtype = NM_MT_SW_ACT_REQ_NACK;
1736 }
Harald Welte34a99682009-02-13 02:41:40 +00001737
1738 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001739 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1740
Harald Welte34a99682009-02-13 02:41:40 +00001741 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001742 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001743 memcpy(ptr, attr, att_len);
1744 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001745 if (nack)
1746 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001747
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001748 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001749}
1750
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001751int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001752{
Harald Welte8470bf22008-12-25 23:28:35 +00001753 struct msgb *msg = nm_msgb_alloc();
1754 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001755 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001756
1757 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1758 fill_om_hdr(oh, len);
1759 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001760 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001761
1762 return abis_nm_sendmsg(bts, msg);
1763}
1764
1765/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001766static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001767{
1768 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001769 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001770
1771 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001772 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001773 0xff, 0xff, 0xff);
1774
1775 return abis_nm_sendmsg(bts, msg);
1776}
1777
Harald Welte34a99682009-02-13 02:41:40 +00001778/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001779int 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 +00001780{
1781 struct abis_om_hdr *oh;
1782 struct msgb *msg = nm_msgb_alloc();
1783
1784 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1785 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1786
Harald Welte15c61722011-05-22 22:45:37 +02001787 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001788 DEBUGPC(DNM, "Sending OPSTART\n");
1789
Harald Welte34a99682009-02-13 02:41:40 +00001790 return abis_nm_sendmsg(bts, msg);
1791}
1792
1793/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001794int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1795 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001796{
1797 struct abis_om_hdr *oh;
1798 struct msgb *msg = nm_msgb_alloc();
1799
1800 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1801 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1802 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1803
1804 return abis_nm_sendmsg(bts, msg);
1805}
1806
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001807int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1808 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001809{
1810 struct abis_om_hdr *oh;
1811 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001812 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001813
1814 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1815 e1_port0, ts0, e1_port1, ts1);
1816
1817 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1818 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1819 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1820
1821 attr = msgb_put(msg, 3);
1822 attr[0] = NM_ATT_MDROP_LINK;
1823 attr[1] = e1_port0;
1824 attr[2] = ts0;
1825
1826 attr = msgb_put(msg, 3);
1827 attr[0] = NM_ATT_MDROP_NEXT;
1828 attr[1] = e1_port1;
1829 attr[2] = ts1;
1830
1831 return abis_nm_sendmsg(bts, msg);
1832}
Harald Welte34a99682009-02-13 02:41:40 +00001833
Harald Weltec7310382009-08-08 00:02:36 +02001834/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001835int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1836 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1837 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001838{
1839 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001840
Harald Welte15c61722011-05-22 22:45:37 +02001841 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001842
1843 if (!msg)
1844 msg = nm_msgb_alloc();
1845
1846 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1847 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1848 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1849 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001850 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001851
1852 return abis_nm_sendmsg(bts, msg);
1853}
1854
Harald Welte52b1f982008-12-23 20:25:15 +00001855int abis_nm_event_reports(struct gsm_bts *bts, int on)
1856{
1857 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001858 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001859 else
Harald Welte227d4072009-01-03 08:16:25 +00001860 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001861}
1862
Harald Welte47d88ae2009-01-04 12:02:08 +00001863/* Siemens (or BS-11) specific commands */
1864
Harald Welte3ffd1372009-02-01 22:15:49 +00001865int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1866{
1867 if (reconnect == 0)
1868 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1869 else
1870 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1871}
1872
Harald Welteb8427972009-02-05 19:27:17 +00001873int abis_nm_bs11_restart(struct gsm_bts *bts)
1874{
1875 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1876}
1877
1878
Harald Welte268bb402009-02-01 19:11:56 +00001879struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001880 uint16_t year;
1881 uint8_t month;
1882 uint8_t day;
1883 uint8_t hour;
1884 uint8_t min;
1885 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001886} __attribute__((packed));
1887
1888
1889void get_bs11_date_time(struct bs11_date_time *aet)
1890{
1891 time_t t;
1892 struct tm *tm;
1893
1894 t = time(NULL);
1895 tm = localtime(&t);
1896 aet->sec = tm->tm_sec;
1897 aet->min = tm->tm_min;
1898 aet->hour = tm->tm_hour;
1899 aet->day = tm->tm_mday;
1900 aet->month = tm->tm_mon;
1901 aet->year = htons(1900 + tm->tm_year);
1902}
1903
Harald Welte05188ee2009-01-18 11:39:08 +00001904int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001905{
Harald Welte4668fda2009-01-03 08:19:29 +00001906 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001907}
1908
Harald Welte05188ee2009-01-18 11:39:08 +00001909int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001910{
1911 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001912 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001913 else
Harald Welte4668fda2009-01-03 08:19:29 +00001914 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001915}
Harald Welte47d88ae2009-01-04 12:02:08 +00001916
Harald Welte05188ee2009-01-18 11:39:08 +00001917int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001918 enum abis_bs11_objtype type, uint8_t idx,
1919 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001920{
1921 struct abis_om_hdr *oh;
1922 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001923 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001924
1925 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001926 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001927 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001928 cur = msgb_put(msg, attr_len);
1929 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001930
1931 return abis_nm_sendmsg(bts, msg);
1932}
1933
Harald Welte78fc0d42009-02-19 02:50:57 +00001934int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001935 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001936{
1937 struct abis_om_hdr *oh;
1938 struct msgb *msg = nm_msgb_alloc();
1939
1940 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1941 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1942 NM_OC_BS11, type, 0, idx);
1943
1944 return abis_nm_sendmsg(bts, msg);
1945}
1946
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001947int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001948{
1949 struct abis_om_hdr *oh;
1950 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001951 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001952
1953 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001954 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001955 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1956 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001957
1958 return abis_nm_sendmsg(bts, msg);
1959}
1960
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001961int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001962{
1963 struct abis_om_hdr *oh;
1964 struct msgb *msg = nm_msgb_alloc();
1965
1966 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1967 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001968 idx, 0xff, 0xff);
1969
1970 return abis_nm_sendmsg(bts, msg);
1971}
1972
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001973int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001974{
1975 struct abis_om_hdr *oh;
1976 struct msgb *msg = nm_msgb_alloc();
1977
1978 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1979 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1980 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001981
1982 return abis_nm_sendmsg(bts, msg);
1983}
Harald Welte05188ee2009-01-18 11:39:08 +00001984
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001985static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001986int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1987{
1988 struct abis_om_hdr *oh;
1989 struct msgb *msg = nm_msgb_alloc();
1990
1991 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1992 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1993 0xff, 0xff, 0xff);
1994 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1995
1996 return abis_nm_sendmsg(bts, msg);
1997}
1998
Harald Welteb6c92ae2009-02-21 20:15:32 +00001999/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002000int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2001 uint8_t e1_timeslot, uint8_t e1_subslot,
2002 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002003{
2004 struct abis_om_hdr *oh;
2005 struct abis_nm_channel *ch;
2006 struct msgb *msg = nm_msgb_alloc();
2007
2008 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002009 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002010 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2011
2012 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2013 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002014 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002015
2016 return abis_nm_sendmsg(bts, msg);
2017}
2018
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002019int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002020{
2021 struct abis_om_hdr *oh;
2022 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002023
2024 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002025 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002026 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2027 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2028
2029 return abis_nm_sendmsg(trx->bts, msg);
2030}
2031
Harald Welte78fc0d42009-02-19 02:50:57 +00002032int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2033{
2034 struct abis_om_hdr *oh;
2035 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002036 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002037
2038 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2039 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2040 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2041 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2042
2043 return abis_nm_sendmsg(trx->bts, msg);
2044}
2045
Harald Welteaaf02d92009-04-29 13:25:57 +00002046int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2047{
2048 struct abis_om_hdr *oh;
2049 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002050 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002051
2052 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2053 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2054 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002055 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002056
2057 return abis_nm_sendmsg(bts, msg);
2058}
2059
Harald Welteef061952009-05-17 12:43:42 +00002060int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2061{
2062 struct abis_om_hdr *oh;
2063 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002064 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002065 NM_ATT_BS11_CCLK_TYPE };
2066
2067 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2068 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2069 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2070 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2071
2072 return abis_nm_sendmsg(bts, msg);
2073
2074}
Harald Welteaaf02d92009-04-29 13:25:57 +00002075
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002076//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002077
Harald Welte1bc09062009-01-18 14:17:52 +00002078int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002079{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002080 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2081}
2082
Daniel Willmann4b054c82010-01-07 00:46:26 +01002083int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2084{
2085 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2086}
2087
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002088int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002089{
Harald Welte05188ee2009-01-18 11:39:08 +00002090 struct abis_om_hdr *oh;
2091 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002092 struct bs11_date_time bdt;
2093
2094 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002095
2096 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002097 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002098 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002099 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002100 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002101 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002102 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002103 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002104 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002105 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002106 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002107 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002108 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002109 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002110 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002111 }
Harald Welte05188ee2009-01-18 11:39:08 +00002112
2113 return abis_nm_sendmsg(bts, msg);
2114}
Harald Welte1bc09062009-01-18 14:17:52 +00002115
2116int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2117{
2118 struct abis_om_hdr *oh;
2119 struct msgb *msg;
2120
2121 if (strlen(password) != 10)
2122 return -EINVAL;
2123
2124 msg = nm_msgb_alloc();
2125 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002126 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002127 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002128 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002129
2130 return abis_nm_sendmsg(bts, msg);
2131}
2132
Harald Weltee69f5fb2009-04-28 16:31:38 +00002133/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2134int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2135{
2136 struct abis_om_hdr *oh;
2137 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002138 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002139
2140 msg = nm_msgb_alloc();
2141 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2142 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2143 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002144
2145 if (locked)
2146 tlv_value = BS11_LI_PLL_LOCKED;
2147 else
2148 tlv_value = BS11_LI_PLL_STANDALONE;
2149
2150 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002151
2152 return abis_nm_sendmsg(bts, msg);
2153}
2154
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002155/* Set the calibration value of the PLL (work value/set value)
2156 * It depends on the login which one is changed */
2157int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2158{
2159 struct abis_om_hdr *oh;
2160 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002161 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002162
2163 msg = nm_msgb_alloc();
2164 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2165 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2166 BS11_OBJ_TRX1, 0x00, 0x00);
2167
2168 tlv_value[0] = value>>8;
2169 tlv_value[1] = value&0xff;
2170
2171 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2172
2173 return abis_nm_sendmsg(bts, msg);
2174}
2175
Harald Welte1bc09062009-01-18 14:17:52 +00002176int abis_nm_bs11_get_state(struct gsm_bts *bts)
2177{
2178 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2179}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002180
2181/* BS11 SWL */
2182
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002183void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002184
Harald Welte5e4d1b32009-02-01 13:36:56 +00002185struct abis_nm_bs11_sw {
2186 struct gsm_bts *bts;
2187 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002188 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002189 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002190 struct llist_head file_list;
2191 gsm_cbfn *user_cb; /* specified by the user */
2192};
2193static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2194
2195struct file_list_entry {
2196 struct llist_head list;
2197 char fname[PATH_MAX];
2198};
2199
2200struct file_list_entry *fl_dequeue(struct llist_head *queue)
2201{
2202 struct llist_head *lh;
2203
2204 if (llist_empty(queue))
2205 return NULL;
2206
2207 lh = queue->next;
2208 llist_del(lh);
2209
2210 return llist_entry(lh, struct file_list_entry, list);
2211}
2212
2213static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2214{
2215 char linebuf[255];
2216 struct llist_head *lh, *lh2;
2217 FILE *swl;
2218 int rc = 0;
2219
2220 swl = fopen(bs11_sw->swl_fname, "r");
2221 if (!swl)
2222 return -ENODEV;
2223
2224 /* zero the stale file list, if any */
2225 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2226 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002227 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002228 }
2229
2230 while (fgets(linebuf, sizeof(linebuf), swl)) {
2231 char file_id[12+1];
2232 char file_version[80+1];
2233 struct file_list_entry *fle;
2234 static char dir[PATH_MAX];
2235
2236 if (strlen(linebuf) < 4)
2237 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002238
Harald Welte5e4d1b32009-02-01 13:36:56 +00002239 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2240 if (rc < 0) {
2241 perror("ERR parsing SWL file");
2242 rc = -EINVAL;
2243 goto out;
2244 }
2245 if (rc < 2)
2246 continue;
2247
Harald Welte470ec292009-06-26 20:25:23 +02002248 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002249 if (!fle) {
2250 rc = -ENOMEM;
2251 goto out;
2252 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002253
2254 /* construct new filename */
2255 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2256 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2257 strcat(fle->fname, "/");
2258 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002259
2260 llist_add_tail(&fle->list, &bs11_sw->file_list);
2261 }
2262
2263out:
2264 fclose(swl);
2265 return rc;
2266}
2267
2268/* bs11 swload specific callback, passed to abis_nm core swload */
2269static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2270 struct msgb *msg, void *data, void *param)
2271{
2272 struct abis_nm_bs11_sw *bs11_sw = data;
2273 struct file_list_entry *fle;
2274 int rc = 0;
2275
Harald Welte5e4d1b32009-02-01 13:36:56 +00002276 switch (event) {
2277 case NM_MT_LOAD_END_ACK:
2278 fle = fl_dequeue(&bs11_sw->file_list);
2279 if (fle) {
2280 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002281 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002282 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002283 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002284 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002285 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002286 } else {
2287 /* activate the SWL */
2288 rc = abis_nm_software_activate(bs11_sw->bts,
2289 bs11_sw->swl_fname,
2290 bs11_swload_cbfn,
2291 bs11_sw);
2292 }
2293 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002294 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002295 case NM_MT_LOAD_END_NACK:
2296 case NM_MT_LOAD_INIT_ACK:
2297 case NM_MT_LOAD_INIT_NACK:
2298 case NM_MT_ACTIVATE_SW_NACK:
2299 case NM_MT_ACTIVATE_SW_ACK:
2300 default:
2301 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002302 if (bs11_sw->user_cb)
2303 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002304 break;
2305 }
2306
2307 return rc;
2308}
2309
2310/* Siemens provides a SWL file that is a mere listing of all the other
2311 * files that are part of a software release. We need to upload first
2312 * the list file, and then each file that is listed in the list file */
2313int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002314 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002315{
2316 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2317 struct file_list_entry *fle;
2318 int rc = 0;
2319
2320 INIT_LLIST_HEAD(&bs11_sw->file_list);
2321 bs11_sw->bts = bts;
2322 bs11_sw->win_size = win_size;
2323 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002324 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002325
2326 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2327 rc = bs11_read_swl_file(bs11_sw);
2328 if (rc < 0)
2329 return rc;
2330
2331 /* dequeue next item in file list */
2332 fle = fl_dequeue(&bs11_sw->file_list);
2333 if (!fle)
2334 return -EINVAL;
2335
2336 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002337 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002338 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002339 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002340 return rc;
2341}
2342
Harald Welte5083b0b2009-02-02 19:20:52 +00002343#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002344static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002345 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2346 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2347 NM_ATT_BS11_LMT_USER_NAME,
2348
2349 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2350
2351 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2352
2353 NM_ATT_BS11_SW_LOAD_STORED };
2354
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002355static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002356 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2357 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2358 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2359 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002360#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002361
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002362static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002363 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2364 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002365 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002366
2367int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2368{
2369 struct abis_om_hdr *oh;
2370 struct msgb *msg = nm_msgb_alloc();
2371
2372 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2373 /* SiemensHW CCTRL object */
2374 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2375 0x03, 0x00, 0x00);
2376 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2377
2378 return abis_nm_sendmsg(bts, msg);
2379}
Harald Welte268bb402009-02-01 19:11:56 +00002380
2381int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2382{
2383 struct abis_om_hdr *oh;
2384 struct msgb *msg = nm_msgb_alloc();
2385 struct bs11_date_time aet;
2386
2387 get_bs11_date_time(&aet);
2388 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2389 /* SiemensHW CCTRL object */
2390 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2391 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002392 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002393
2394 return abis_nm_sendmsg(bts, msg);
2395}
Harald Welte5c1e4582009-02-15 11:57:29 +00002396
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002397int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002398{
2399 struct abis_om_hdr *oh;
2400 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002401 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002402
2403 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2404 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2405 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2406 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2407
2408 return abis_nm_sendmsg(bts, msg);
2409}
2410
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002411int 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 +02002412{
2413 struct abis_om_hdr *oh;
2414 struct msgb *msg = nm_msgb_alloc();
2415 struct bs11_date_time aet;
2416
2417 get_bs11_date_time(&aet);
2418 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2419 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2420 bport, 0xff, 0x02);
2421 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2422
2423 return abis_nm_sendmsg(bts, msg);
2424}
2425
Harald Welte5c1e4582009-02-15 11:57:29 +00002426/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002427static const char ipaccess_magic[] = "com.ipaccess";
2428
Harald Welte677c21f2009-02-17 13:22:23 +00002429
2430static int abis_nm_rx_ipacc(struct msgb *msg)
2431{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002432 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002433 struct abis_om_hdr *oh = msgb_l2(msg);
2434 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002435 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002436 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002437 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002438
2439 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002440 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002441 return -EINVAL;
2442 }
2443
Harald Welte193fefc2009-04-30 15:16:27 +00002444 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002445 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002446
Harald Welte15c61722011-05-22 22:45:37 +02002447 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002448
Harald Welte746d6092009-10-19 22:11:11 +02002449 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002450
Harald Welte677c21f2009-02-17 13:22:23 +00002451 switch (foh->msg_type) {
2452 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002453 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002454 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2455 memcpy(&addr,
2456 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2457
2458 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2459 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002460 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002461 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002462 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002463 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002464 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2465 DEBUGPC(DNM, "STREAM=0x%02x ",
2466 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002467 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002468 break;
2469 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002470 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002471 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002472 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002473 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002474 else
2475 DEBUGPC(DNM, "\n");
2476 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002477 case NM_MT_IPACC_SET_NVATTR_ACK:
2478 DEBUGPC(DNM, "SET NVATTR ACK\n");
2479 /* FIXME: decode and show the actual attributes */
2480 break;
2481 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002482 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002483 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002484 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002485 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002486 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002487 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002488 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002489 case NM_MT_IPACC_GET_NVATTR_ACK:
2490 DEBUGPC(DNM, "GET NVATTR ACK\n");
2491 /* FIXME: decode and show the actual attributes */
2492 break;
2493 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002494 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002495 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002496 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002497 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002498 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002499 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002500 break;
Harald Welte15c44172009-10-08 20:15:24 +02002501 case NM_MT_IPACC_SET_ATTR_ACK:
2502 DEBUGPC(DNM, "SET ATTR ACK\n");
2503 break;
2504 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002505 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002506 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002507 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002508 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002509 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002510 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002511 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002512 default:
2513 DEBUGPC(DNM, "unknown\n");
2514 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002515 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002516
2517 /* signal handling */
2518 switch (foh->msg_type) {
2519 case NM_MT_IPACC_RSL_CONNECT_NACK:
2520 case NM_MT_IPACC_SET_NVATTR_NACK:
2521 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002522 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002523 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002524 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002525 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002526 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002527 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002528 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002529 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002530 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002531 default:
2532 break;
2533 }
2534
Harald Welte677c21f2009-02-17 13:22:23 +00002535 return 0;
2536}
2537
Harald Welte193fefc2009-04-30 15:16:27 +00002538/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002539int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2540 uint8_t obj_class, uint8_t bts_nr,
2541 uint8_t trx_nr, uint8_t ts_nr,
2542 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002543{
2544 struct msgb *msg = nm_msgb_alloc();
2545 struct abis_om_hdr *oh;
2546 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002547 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002548
2549 /* construct the 12.21 OM header, observe the erroneous length */
2550 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2551 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2552 oh->mdisc = ABIS_OM_MDISC_MANUF;
2553
2554 /* add the ip.access magic */
2555 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2556 *data++ = sizeof(ipaccess_magic);
2557 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2558
2559 /* fill the 12.21 FOM header */
2560 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2561 foh->msg_type = msg_type;
2562 foh->obj_class = obj_class;
2563 foh->obj_inst.bts_nr = bts_nr;
2564 foh->obj_inst.trx_nr = trx_nr;
2565 foh->obj_inst.ts_nr = ts_nr;
2566
2567 if (attr && attr_len) {
2568 data = msgb_put(msg, attr_len);
2569 memcpy(data, attr, attr_len);
2570 }
2571
2572 return abis_nm_sendmsg(bts, msg);
2573}
Harald Welte677c21f2009-02-17 13:22:23 +00002574
Harald Welte193fefc2009-04-30 15:16:27 +00002575/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002576int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002577 int attr_len)
2578{
Harald Welte2ef156d2010-01-07 20:39:42 +01002579 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2580 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002581 attr_len);
2582}
2583
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002584int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002585 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002586{
2587 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002588 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002589 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2590 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2591
2592 int attr_len = sizeof(attr);
2593
2594 ia.s_addr = htonl(ip);
2595 attr[1] = stream;
2596 attr[3] = port >> 8;
2597 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002598 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002599
2600 /* if ip == 0, we use the default IP */
2601 if (ip == 0)
2602 attr_len -= 5;
2603
2604 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002605 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002606
2607 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2608 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2609 trx->nr, 0xff, attr, attr_len);
2610}
2611
Harald Welte193fefc2009-04-30 15:16:27 +00002612/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002613int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002614{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002615 struct abis_om_hdr *oh;
2616 struct msgb *msg = nm_msgb_alloc();
2617
2618 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2619 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2620 trx->bts->nr, trx->nr, 0xff);
2621
2622 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002623}
Harald Weltedaef5212009-10-24 10:20:41 +02002624
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002625int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2626 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2627 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002628{
2629 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2630 obj_class, bts_nr, trx_nr, ts_nr,
2631 attr, attr_len);
2632}
Harald Welte0f255852009-11-12 14:48:42 +01002633
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002634void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002635{
2636 /* we simply reuse the GSM48 function and overwrite the RAC
2637 * with the Cell ID */
2638 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002639 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002640}
2641
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002642void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2643{
2644 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2645
Harald Welted64c0bc2011-05-30 12:07:53 +02002646 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002647 if (!trx->bts || !trx->bts->oml_link)
2648 return;
2649
2650 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2651 trx->bts->bts_nr, trx->nr, 0xff,
2652 new_state);
2653}
2654
Harald Welte92b1fe42010-03-25 11:45:30 +08002655static const struct value_string ipacc_testres_names[] = {
2656 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2657 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2658 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2659 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2660 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2661 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002662};
2663
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002664const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002665{
Harald Welte92b1fe42010-03-25 11:45:30 +08002666 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002667}
2668
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002669void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002670{
2671 cid->mcc = (buf[0] & 0xf) * 100;
2672 cid->mcc += (buf[0] >> 4) * 10;
2673 cid->mcc += (buf[1] & 0xf) * 1;
2674
2675 if (buf[1] >> 4 == 0xf) {
2676 cid->mnc = (buf[2] & 0xf) * 10;
2677 cid->mnc += (buf[2] >> 4) * 1;
2678 } else {
2679 cid->mnc = (buf[2] & 0xf) * 100;
2680 cid->mnc += (buf[2] >> 4) * 10;
2681 cid->mnc += (buf[1] >> 4) * 1;
2682 }
2683
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002684 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2685 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002686}
2687
Harald Welte0f255852009-11-12 14:48:42 +01002688/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002689int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002690{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002691 uint8_t *cur = buf;
2692 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01002693
Harald Welteaf109b92010-07-22 18:14:36 +02002694 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002695
2696 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2697 return -EINVAL;
2698 cur++;
2699
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002700 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002701 cur += 2;
2702
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002703 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002704 cur += 2;
2705
2706 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2707 binf->freq_qual = *cur >> 2;
2708
Harald Welteaf109b92010-07-22 18:14:36 +02002709 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002710 binf->arfcn |= *cur++;
2711
2712 if (binf->info_type & IPAC_BINF_RXLEV)
2713 binf->rx_lev = *cur & 0x3f;
2714 cur++;
2715
2716 if (binf->info_type & IPAC_BINF_RXQUAL)
2717 binf->rx_qual = *cur & 0x7;
2718 cur++;
2719
2720 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002721 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002722 cur += 2;
2723
2724 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002725 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002726 cur += 2;
2727
2728 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002729 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002730 cur += 4;
2731
Harald Weltea780a3d2010-07-30 22:34:42 +02002732#if 0
2733 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002734 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002735#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002736 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002737 cur++;
2738
Harald Welteb40a38f2009-11-13 11:56:05 +01002739 ipac_parse_cgi(&binf->cgi, cur);
2740 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002741
2742 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2743 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2744 cur += sizeof(binf->ba_list_si2);
2745 }
2746
2747 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2748 memcpy(binf->ba_list_si2bis, cur,
2749 sizeof(binf->ba_list_si2bis));
2750 cur += sizeof(binf->ba_list_si2bis);
2751 }
2752
2753 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2754 memcpy(binf->ba_list_si2ter, cur,
2755 sizeof(binf->ba_list_si2ter));
2756 cur += sizeof(binf->ba_list_si2ter);
2757 }
2758
2759 return 0;
2760}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002761
2762void abis_nm_clear_queue(struct gsm_bts *bts)
2763{
2764 struct msgb *msg;
2765
2766 while (!llist_empty(&bts->abis_queue)) {
2767 msg = msgb_dequeue(&bts->abis_queue);
2768 msgb_free(msg);
2769 }
2770
2771 bts->abis_nm_pend = 0;
2772}