blob: 0c3fff56c985bca84bc5ba5ff9de241bf0c95fdc [file] [log] [blame]
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte59b04682009-06-10 05:40:52 +08002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-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 Welte59b04682009-06-10 05:40:52 +080011 * (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 Welte0e3e88e2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080017 *
Harald Welte0e3e88e2011-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 Welte59b04682009-06-10 05:40:52 +080020 *
21 */
22
23
24#include <errno.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30#include <time.h>
31#include <limits.h>
32
Harald Welte59b04682009-06-10 05:40:52 +080033#include <sys/stat.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Weltec61a90e2011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080043#include <openbsc/abis_nm.h>
44#include <openbsc/misdn.h>
45#include <openbsc/signal.h>
46
47#define OM_ALLOC_SIZE 1024
48#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010049#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080050
Holger Hans Peter Freyther7eb8a9a2011-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 Welte59b04682009-06-10 05:40:52 +080052{
Harald Welte59698fb2010-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 Welte59b04682009-06-10 05:40:52 +080056}
57
58static 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
70#if 0
71/* 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}
76#endif
77
78/* is this msgtype a report ? */
79static int is_report(enum abis_nm_msgtype mt)
80{
Harald Weltec61a90e2011-05-22 22:45:37 +020081 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte59b04682009-06-10 05:40:52 +080082}
83
84#define MT_ACK(x) (x+1)
85#define MT_NACK(x) (x+2)
86
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020087static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte59b04682009-06-10 05:40:52 +080088{
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 Freyther7eb8a9a2011-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 Welte59b04682009-06-10 05:40:52 +080098{
99 struct abis_om_fom_hdr *foh =
100 (struct abis_om_fom_hdr *) oh->data;
101
102 fill_om_hdr(oh, len+sizeof(*foh));
103 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
110static struct msgb *nm_msgb_alloc(void)
111{
Harald Welte9cfc9352009-06-26 19:39:35 +0200112 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
113 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800114}
115
116/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100117static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800118{
119 msg->trx = bts->c0;
120
Holger Hans Peter Freyther2a6bffe2010-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 Weltec5845042011-02-14 15:26:13 +0100124 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-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 Welte59b04682009-06-10 05:40:52 +0800142}
143
144static int abis_nm_rcvmsg_sw(struct msgb *mb);
145
Sylvain Munautca3e04f2010-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 Welte69f6f812011-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 Welte59b04682009-06-10 05:40:52 +0800157{
158 struct gsm_bts_trx *trx;
Harald Welte69f6f812011-05-30 12:07:53 +0200159 struct gsm_abis_mo *mo = NULL;
Harald Welte59b04682009-06-10 05:40:52 +0800160
161 switch (obj_class) {
162 case NM_OC_BTS:
Harald Welte69f6f812011-05-30 12:07:53 +0200163 mo = &bts->mo;
Harald Welte59b04682009-06-10 05:40:52 +0800164 break;
165 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-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 Welte59b04682009-06-10 05:40:52 +0800168 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100169 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200170 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte69f6f812011-05-30 12:07:53 +0200171 mo = &trx->mo;
Harald Welte59b04682009-06-10 05:40:52 +0800172 break;
173 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-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 Welte59b04682009-06-10 05:40:52 +0800176 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100177 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200178 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte69f6f812011-05-30 12:07:53 +0200179 mo = &trx->bb_transc.mo;
Harald Welte59b04682009-06-10 05:40:52 +0800180 break;
181 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100182 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100183 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800184 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100185 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200186 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800187 if (obj_inst->ts_nr >= TRX_NR_TS)
188 return NULL;
Harald Welte69f6f812011-05-30 12:07:53 +0200189 mo = &trx->ts[obj_inst->ts_nr].mo;
Harald Welte59b04682009-06-10 05:40:52 +0800190 break;
191 case NM_OC_SITE_MANAGER:
Harald Welte69f6f812011-05-30 12:07:53 +0200192 mo = &bts->site_mgr.mo;
Harald Welte59b04682009-06-10 05:40:52 +0800193 break;
194 case NM_OC_BS11:
195 switch (obj_inst->bts_nr) {
196 case BS11_OBJ_CCLK:
Harald Welte69f6f812011-05-30 12:07:53 +0200197 mo = &bts->bs11.cclk.mo;
Harald Welte59b04682009-06-10 05:40:52 +0800198 break;
199 case BS11_OBJ_BBSIG:
200 if (obj_inst->ts_nr > bts->num_trx)
201 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200202 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte69f6f812011-05-30 12:07:53 +0200203 mo = &trx->bs11.bbsig.mo;
Harald Welte59b04682009-06-10 05:40:52 +0800204 break;
205 case BS11_OBJ_PA:
206 if (obj_inst->ts_nr > bts->num_trx)
207 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200208 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte69f6f812011-05-30 12:07:53 +0200209 mo = &trx->bs11.pa.mo;
Harald Welte59b04682009-06-10 05:40:52 +0800210 break;
211 default:
212 return NULL;
213 }
214 case NM_OC_BS11_RACK:
Harald Welte69f6f812011-05-30 12:07:53 +0200215 mo = &bts->bs11.rack.mo;
Harald Welte59b04682009-06-10 05:40:52 +0800216 break;
217 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100218 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte59b04682009-06-10 05:40:52 +0800219 return NULL;
Harald Welte69f6f812011-05-30 12:07:53 +0200220 mo = &bts->bs11.envabtse[obj_inst->trx_nr].mo;
Harald Welte59b04682009-06-10 05:40:52 +0800221 break;
Harald Welte439e1282009-10-24 10:19:14 +0200222 case NM_OC_GPRS_NSE:
Harald Welte69f6f812011-05-30 12:07:53 +0200223 mo = &bts->gprs.nse.mo;
Harald Welte439e1282009-10-24 10:19:14 +0200224 break;
225 case NM_OC_GPRS_CELL:
Harald Welte69f6f812011-05-30 12:07:53 +0200226 mo = &bts->gprs.cell.mo;
Harald Welte439e1282009-10-24 10:19:14 +0200227 break;
228 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100229 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200230 return NULL;
Harald Welte69f6f812011-05-30 12:07:53 +0200231 mo = &bts->gprs.nsvc[obj_inst->trx_nr].mo;
Harald Welte439e1282009-10-24 10:19:14 +0200232 break;
Harald Welte59b04682009-06-10 05:40:52 +0800233 }
Harald Welte69f6f812011-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 Welte59b04682009-06-10 05:40:52 +0800249}
250
251/* obtain the in-memory data structure of a given object instance */
252static void *
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200253objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800254 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 Welte3d9ecf72009-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 Welte59b04682009-06-10 05:40:52 +0800266 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100267 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200268 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800269 obj = trx;
270 break;
271 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-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 Welte59b04682009-06-10 05:40:52 +0800274 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100275 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200276 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800277 obj = &trx->bb_transc;
278 break;
279 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100280 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100281 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800282 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100283 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200284 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800285 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 Welte439e1282009-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 Freyther5bd48ca2009-12-21 17:06:07 +0100299 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200300 return NULL;
301 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
302 break;
Harald Welte59b04682009-06-10 05:40:52 +0800303 }
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 Freyther7eb8a9a2011-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 Welte59b04682009-06-10 05:40:52 +0800311{
312 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100313 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800314
Harald Weltea348c082011-03-06 21:20:38 +0100315 memset(&nsd, 0, sizeof(nsd));
316
Harald Welte4c826f72011-01-14 15:55:42 +0100317 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
318 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100319 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800320 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 Welteb03c4482011-03-06 22:11:32 +0100327 nsd.bts = bts;
Harald Welte4c826f72011-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 Ayusoef717c62011-05-06 12:12:31 +0200332 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800333
334 nm_state->administrative = adm_state;
335
Harald Welte4c826f72011-01-14 15:55:42 +0100336 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800337}
338
339static int abis_nm_rx_statechg_rep(struct msgb *mb)
340{
341 struct abis_om_hdr *oh = msgb_l2(mb);
342 struct abis_om_fom_hdr *foh = msgb_l3(mb);
343 struct gsm_bts *bts = mb->trx->bts;
344 struct tlv_parsed tp;
345 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800346
347 DEBUGPC(DNM, "STATE CHG: ");
348
349 memset(&new_state, 0, sizeof(new_state));
350
351 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
352 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100353 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800354 return -EINVAL;
355 }
356
357 new_state = *nm_state;
358
Harald Welte59698fb2010-01-10 18:01:52 +0100359 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800360 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
361 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200362 DEBUGPC(DNM, "OP_STATE=%s ",
363 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800364 }
365 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
366 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 Weltec61a90e2011-05-22 22:45:37 +0200370 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
371 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800372 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100373 } else
374 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800375 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
376 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200377 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200378 get_value_string(abis_nm_adm_state_names,
379 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800380 }
381 DEBUGPC(DNM, "\n");
382
Holger Hans Peter Freyther677bb2f2009-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 Welte59b04682009-06-10 05:40:52 +0800386 /* Update the operational state of a given object in our in-memory data
387 * structures and send an event to the higher layer */
Harald Welte4c826f72011-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 Welteb03c4482011-03-06 22:11:32 +0100394 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200395 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-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 Welte59b04682009-06-10 05:40:52 +0800400 }
401#if 0
402 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 }
409#endif
410 return 0;
411}
412
413static 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 Spaarf5888a72011-02-18 11:06:51 +0100418 const uint8_t *p_val;
419 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800420
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200421 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800422
Harald Welte59698fb2010-01-10 18:01:52 +0100423 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800424
425 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Weltec61a90e2011-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 Welte59b04682009-06-10 05:40:52 +0800428 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Weltec61a90e2011-05-22 22:45:37 +0200429 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
430 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-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 Freytherf569b2f2011-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 Spaarf5888a72011-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 Freytherf569b2f2011-04-26 09:29:01 +0200439 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100440 talloc_free(p_text);
441 }
442 }
Harald Welte59b04682009-06-10 05:40:52 +0800443
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200444 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800445
446 return 0;
447}
448
449static int abis_nm_rcvmsg_report(struct msgb *mb)
450{
451 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200452 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800453
Harald Weltec61a90e2011-05-22 22:45:37 +0200454 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800455
456 //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;
462 case NM_MT_SW_ACTIVATED_REP:
463 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200464 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800465 break;
466 case NM_MT_FAILURE_EVENT_REP:
467 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200468 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800469 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200470 case NM_MT_TEST_REP:
471 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200472 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200473 break;
Harald Welte59b04682009-06-10 05:40:52 +0800474 default:
475 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
476 break;
477
478 };
479
480 return 0;
481}
482
483/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-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 Welte59b04682009-06-10 05:40:52 +0800486{
487 struct abis_om_hdr *oh;
488 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200489 uint8_t len = swdesc_len;
490 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800491
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 Freyther7eb8a9a2011-04-18 17:04:00 +0200501static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munaut7e3edbf2009-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 Freyther7eb8a9a2011-04-18 17:04:00 +0200510 uint8_t tag;
511 uint16_t tag_len;
512 const uint8_t *val;
Sylvain Munaut7e3edbf2009-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 Welte59b04682009-06-10 05:40:52 +0800544static 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 Haben322fc582009-10-01 14:56:13 +0200548 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200549 const uint8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100550 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800551
Harald Weltec61a90e2011-05-22 22:45:37 +0200552 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200553
554 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800555
Harald Welte3055e332010-03-14 15:37:43 +0800556 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800557
558 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
559 foh->obj_inst.bts_nr,
560 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800561 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800562 foh->data, oh->length-sizeof(*foh));
563
Harald Welte59698fb2010-01-10 18:01:52 +0100564 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-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 Ayusob1d5a692011-05-07 12:12:48 +0200571 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200572 }
573
Sylvain Munaut7e3edbf2009-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 Haben322fc582009-10-01 14:56:13 +0200578
Harald Welte59b04682009-06-10 05:40:52 +0800579 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 Munaut7e3edbf2009-10-25 17:48:42 +0100583 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800584}
585
586/* 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 Freyther7eb8a9a2011-04-18 17:04:00 +0200592 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800593
Harald Welte59698fb2010-01-10 18:01:52 +0100594 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800595 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
603static 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 Welte59698fb2010-01-10 18:01:52 +0100610 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800611 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
612 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200613 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800614 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 Freyther7eb8a9a2011-04-18 17:04:00 +0200618 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800619 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 Freyther2a6bffe2010-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 Weltec5845042011-02-14 15:26:13 +0100639 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100640
641 if (wait)
642 break;
643 }
644
645 bts->abis_nm_pend = wait;
646}
647
Harald Welte59b04682009-06-10 05:40:52 +0800648/* Receive a OML NM Message from BTS */
649static int abis_nm_rcvmsg_fom(struct msgb *mb)
650{
651 struct abis_om_hdr *oh = msgb_l2(mb);
652 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200653 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100654 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800655
656 /* check for unsolicited message */
657 if (is_report(mt))
658 return abis_nm_rcvmsg_report(mb);
659
Harald Weltec61a90e2011-05-22 22:45:37 +0200660 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800661 return abis_nm_rcvmsg_sw(mb);
662
Harald Weltec61a90e2011-05-22 22:45:37 +0200663 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800664 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800665 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200666
Harald Weltec61a90e2011-05-22 22:45:37 +0200667 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200668
Harald Weltec61a90e2011-05-22 22:45:37 +0200669 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800670
Harald Welte59698fb2010-01-10 18:01:52 +0100671 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800672 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200673 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200674 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800675 else
676 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200677
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800678 nack_data.msg = mb;
679 nack_data.mt = mt;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200680 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100681 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200682 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800683 }
684#if 0
685 /* 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 Weltede4477a2009-12-24 12:20:20 +0100688 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800689 /* 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 Weltede4477a2009-12-24 12:20:20 +0100692 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800693 /* FIXME: somehow signal this to the caller */
694 } else {
695 /* really strange things happen */
696 return -EINVAL;
697 }
698 }
699#endif
700
701 switch (mt) {
702 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100703 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800704 break;
705 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100706 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800707 break;
708 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100709 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800710 break;
Harald Welte204317e2009-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 Freyther9ef8e5a2009-12-30 09:00:01 +0100714 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200715 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100716 break;
717 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200718 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100719 break;
Harald Welte08011e22011-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 Welte59b04682009-06-10 05:40:52 +0800726 }
727
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100728 abis_nm_queue_send_next(mb->trx->bts);
729 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800730}
731
732static 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 Haben66e0ba02009-10-02 12:19:34 +0100740 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +0800741 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100742 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800743 break;
744 default:
Harald Weltecf2ec4a2009-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 Welte59b04682009-06-10 05:40:52 +0800747 rc = 0;
748 break;
749 }
750
751 return rc;
752}
753
754/* High-Level API */
755/* Entry-point where L2 OML from BTS enters the NM code */
756int abis_nm_rcvmsg(struct msgb *msg)
757{
758 struct abis_om_hdr *oh = msgb_l2(msg);
759 int rc = 0;
760
761 /* Various consistency checks */
762 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100763 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800764 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +0200765 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
766 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800767 }
768 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100769 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800770 oh->sequence);
771 return -EINVAL;
772 }
773#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200774 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800775 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
776 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100777 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800778 oh->length + sizeof(*oh), l2_len);
779 return -EINVAL;
780 }
781 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-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 Welte59b04682009-06-10 05:40:52 +0800783#endif
784 msg->l3h = (unsigned char *)oh + sizeof(*oh);
785
786 switch (oh->mdisc) {
787 case ABIS_OM_MDISC_FOM:
788 rc = abis_nm_rcvmsg_fom(msg);
789 break;
790 case ABIS_OM_MDISC_MANUF:
791 rc = abis_nm_rcvmsg_manuf(msg);
792 break;
793 case ABIS_OM_MDISC_MMI:
794 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100795 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800796 oh->mdisc);
797 break;
798 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100799 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800800 oh->mdisc);
801 return -EINVAL;
802 }
803
804 msgb_free(msg);
805 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
837/* 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};
846
847struct abis_nm_sw {
848 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800849 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800850 gsm_cbfn *cbfn;
851 void *cb_data;
852 int forced;
853
854 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200855 uint8_t obj_class;
856 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800857
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200858 uint8_t file_id[255];
859 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800860
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200861 uint8_t file_version[255];
862 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800863
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200864 uint8_t window_size;
865 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800866
867 int fd;
868 FILE *stream;
869 enum sw_state state;
870 int last_seg;
871};
872
873static struct abis_nm_sw g_sw;
874
Holger Hans Peter Freytherd617f562009-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 Welte59b04682009-06-10 05:40:52 +0800891/* 6.2.1 / 8.3.1: Load Data Initiate */
892static int sw_load_init(struct abis_nm_sw *sw)
893{
894 struct abis_om_hdr *oh;
895 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200896 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800897
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 Freyther38907002009-12-28 09:02:41 +0100902
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100903 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800904 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
905
906 return abis_nm_sendmsg(sw->bts, msg);
907}
908
909static 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
925/* 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;
932 unsigned char *tlv;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200933 uint8_t len;
Harald Welte59b04682009-06-10 05:40:52 +0800934
935 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
936
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;
944
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++;
951
952 len = strlen(line_buf) + 2;
953 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200954 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800955 /* 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 Freytherb5f54482009-12-28 10:04:26 +0100961 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200962 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-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 Freyther679a2eb2009-12-28 11:28:51 +0100972 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200973 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100974 len += 3;
975 break;
976 }
Harald Welte59b04682009-06-10 05:40:52 +0800977 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100978 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800979 /* FIXME: Other BTS types */
980 return -1;
981 }
982
983 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 Freyther2a6bffe2010-11-15 20:50:42 +0100987 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800988}
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 Freyther7eb8a9a2011-04-18 17:04:00 +0200995 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800996
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 Freytherd617f562009-12-30 09:23:48 +01001002 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001003 return abis_nm_sendmsg(sw->bts, msg);
1004}
1005
1006/* Activate the specified software into the BTS */
1007static int sw_activate(struct abis_nm_sw *sw)
1008{
1009 struct abis_om_hdr *oh;
1010 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001011 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +08001012
1013 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);
1024}
1025
Holger Hans Peter Freythera3ae06b2009-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 Freytherb5c03d32009-12-23 08:06:31 +01001033static int parse_sdp_header(struct abis_nm_sw *sw)
1034{
Holger Hans Peter Freythera3ae06b2009-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 Freytherb5c03d32009-12-23 08:06:31 +01001077}
1078
Harald Welte59b04682009-06-10 05:40:52 +08001079static 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 Freyther71135142010-03-29 08:47:44 +02001097 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001098 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 */
1108 rewind(sw->stream);
1109 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001110 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001111 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-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 Freyther38907002009-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 Freytherdfdced02009-12-23 07:26:57 +01001122 break;
Harald Welte59b04682009-06-10 05:40:52 +08001123 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;
1153 if (sw->last_seg)
1154 break;
1155 }
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
1167 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1168
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 */
1174 if (sw->cbfn)
1175 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1176 NM_MT_LOAD_INIT_ACK, mb,
1177 sw->cb_data, NULL);
1178 rc = sw_fill_window(sw);
1179 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001180 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001181 break;
1182 case NM_MT_LOAD_INIT_NACK:
1183 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");
1194 /* FIXME: cause */
1195 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 Freyther2a6bffe2010-11-15 20:50:42 +01001201 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001202 break;
1203 }
1204 break;
1205 case SW_STATE_WAIT_SEGACK:
1206 switch (foh->msg_type) {
1207 case NM_MT_LOAD_SEG_ACK:
1208 if (sw->cbfn)
1209 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1210 NM_MT_LOAD_SEG_ACK, mb,
1211 sw->cb_data, NULL);
1212 sw->seg_in_window = 0;
1213 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 Freyther2a6bffe2010-11-15 20:50:42 +01001222 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001223 break;
Holger Hans Peter Freyther61f814d2009-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 Welte59b04682009-06-10 05:40:52 +08001230 }
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);
1236 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 Freyther99300722009-12-28 11:48:12 +01001243 rc = 0;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001244 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001245 break;
1246 case NM_MT_LOAD_END_NACK:
1247 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");
1257 /* FIXME: cause */
1258 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 Freyther2a6bffe2010-11-15 20:50:42 +01001264 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001265 break;
1266 }
1267 case SW_STATE_WAIT_ACTACK:
1268 switch (foh->msg_type) {
1269 case NM_MT_ACTIVATE_SW_ACK:
1270 /* we're done */
1271 DEBUGP(DNM, "Activate Software DONE!\n");
1272 sw->state = SW_STATE_NONE;
1273 rc = 0;
1274 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 Freyther2a6bffe2010-11-15 20:50:42 +01001278 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001279 break;
1280 case NM_MT_ACTIVATE_SW_NACK:
1281 DEBUGP(DNM, "Activate Software NACK\n");
1282 /* FIXME: cause */
1283 sw->state = SW_STATE_ERROR;
1284 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 Freyther2a6bffe2010-11-15 20:50:42 +01001288 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001289 break;
1290 }
1291 case SW_STATE_NONE:
1292 switch (foh->msg_type) {
1293 case NM_MT_ACTIVATE_SW_ACK:
1294 rc = 0;
1295 break;
1296 }
1297 break;
1298 case SW_STATE_ERROR:
1299 break;
1300 }
1301
1302 if (rc)
1303 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1304 foh->msg_type, old_state, sw->state);
1305
1306 return rc;
1307}
1308
1309/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001310int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001311 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001312 gsm_cbfn *cbfn, void *cb_data)
1313{
1314 struct abis_nm_sw *sw = &g_sw;
1315 int rc;
1316
1317 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1318 bts->nr, fname);
1319
1320 if (sw->state != SW_STATE_NONE)
1321 return -EBUSY;
1322
1323 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001324 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-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 Freyther2b4083a2010-05-12 23:51:46 +08001335 sw->obj_instance[0] = sw->bts->nr;
1336 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-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 Welte59b04682009-06-10 05:40:52 +08001345 sw->window_size = win_size;
1346 sw->state = SW_STATE_WAIT_INITACK;
1347 sw->cbfn = cbfn;
1348 sw->cb_data = cb_data;
1349 sw->forced = forced;
1350
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}
1359
1360int 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 Freyther876a06b2009-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 Welte59b04682009-06-10 05:40:52 +08001376 return percent;
1377}
1378
1379/* 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 Freyther7eb8a9a2011-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 Welte59b04682009-06-10 05:40:52 +08001414{
1415 ch->attrib = NM_ATT_ABIS_CHANNEL;
1416 ch->bts_port = bts_port;
1417 ch->timeslot = ts_nr;
1418 ch->subslot = subslot_nr;
1419}
1420
Holger Hans Peter Freyther7eb8a9a2011-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 Welte59b04682009-06-10 05:40:52 +08001424{
1425 struct abis_om_hdr *oh;
1426 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001427 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001428 struct msgb *msg = nm_msgb_alloc();
1429
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
1434 msgb_tv_put(msg, NM_ATT_TEI, tei);
1435
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 Freyther7eb8a9a2011-04-18 17:04:00 +02001444 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001445{
1446 struct gsm_bts *bts = trx->bts;
1447 struct abis_om_hdr *oh;
1448 struct abis_nm_channel *ch;
1449 struct msgb *msg = nm_msgb_alloc();
1450
1451 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1452 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1453 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 Freyther7eb8a9a2011-04-18 17:04:00 +02001469 uint8_t e1_port, uint8_t e1_timeslot,
1470 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001471{
1472 struct gsm_bts *bts = ts->trx->bts;
1473 struct abis_om_hdr *oh;
1474 struct abis_nm_channel *ch;
1475 struct msgb *msg = nm_msgb_alloc();
1476
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,
1479 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1480
1481 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1482 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1483
1484 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1485 gsm_ts_name(ts),
1486 e1_port, e1_timeslot, e1_subslot);
1487
1488 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 Freyther7eb8a9a2011-04-18 17:04:00 +02001494 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001495{
1496}
1497#endif
1498
1499/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001500int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001501{
1502 struct abis_om_hdr *oh;
1503 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001504 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001505
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);
1509 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1510 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 Freyther7eb8a9a2011-04-18 17:04:00 +02001517int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001518{
1519 struct abis_om_hdr *oh;
1520 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001521 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001522
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,
1527 trx->bts->bts_nr, trx->nr, 0xff);
1528 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 Freyther7eb8a9a2011-04-18 17:04:00 +02001534static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Weltef2eb2782009-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 Welte76ba8812009-12-02 02:45:23 +05301540 switch (ts->trx->bts->type) {
1541 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-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 Welte76ba8812009-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 Weltef2eb2782009-08-09 21:49:48 +02001664 }
1665 return 0;
1666}
1667
Harald Welte59b04682009-06-10 05:40:52 +08001668/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001669int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001670{
1671 struct gsm_bts *bts = ts->trx->bts;
1672 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001673 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001674 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001675 uint8_t len = 2 + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001676
1677 if (bts->type == GSM_BTS_TYPE_BS11)
1678 len += 4 + 2 + 2 + 3;
1679
1680 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-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 Welte59b04682009-06-10 05:40:52 +08001687
1688 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1689 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1690 NM_OC_CHANNEL, bts->bts_nr,
1691 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001692 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001693 if (ts->hopping.enabled) {
1694 unsigned int i;
1695 uint8_t *len;
1696
Harald Welte67104d12009-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 Weltea42a93f2010-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);
laforgedcc63bb2010-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 Weltea42a93f2010-06-14 22:26:10 +02001712 }
1713 }
Harald Welte59b04682009-06-10 05:40:52 +08001714 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02001715 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001716 if (bts->type == GSM_BTS_TYPE_BS11)
1717 msgb_tlv_put(msg, 0x59, 1, &zero);
1718
1719 return abis_nm_sendmsg(bts, msg);
1720}
1721
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001722int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1723 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001724{
1725 struct abis_om_hdr *oh;
1726 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001727 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1728 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001729
1730 if (nack) {
1731 len += 2;
1732 msgtype = NM_MT_SW_ACT_REQ_NACK;
1733 }
1734
1735 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1736 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1737
1738 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001739 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001740 memcpy(ptr, attr, att_len);
1741 }
1742 if (nack)
1743 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1744
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001745 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001746}
1747
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001748int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001749{
1750 struct msgb *msg = nm_msgb_alloc();
1751 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001752 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001753
1754 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1755 fill_om_hdr(oh, len);
1756 data = msgb_put(msg, len);
1757 memcpy(data, rawmsg, len);
1758
1759 return abis_nm_sendmsg(bts, msg);
1760}
1761
1762/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001763static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001764{
1765 struct abis_om_hdr *oh;
1766 struct msgb *msg = nm_msgb_alloc();
1767
1768 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1769 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1770 0xff, 0xff, 0xff);
1771
1772 return abis_nm_sendmsg(bts, msg);
1773}
1774
1775/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001776int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
Harald Welte59b04682009-06-10 05:40:52 +08001777{
1778 struct abis_om_hdr *oh;
1779 struct msgb *msg = nm_msgb_alloc();
1780
Harald Welte59b04682009-06-10 05:40:52 +08001781 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1782 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1783
Harald Weltec61a90e2011-05-22 22:45:37 +02001784 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Welteb7284a92009-10-20 09:56:18 +02001785 DEBUGPC(DNM, "Sending OPSTART\n");
1786
Harald Welte59b04682009-06-10 05:40:52 +08001787 return abis_nm_sendmsg(bts, msg);
1788}
1789
1790/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001791int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1792 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001793{
1794 struct abis_om_hdr *oh;
1795 struct msgb *msg = nm_msgb_alloc();
1796
1797 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1798 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1799 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1800
1801 return abis_nm_sendmsg(bts, msg);
1802}
1803
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001804int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1805 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001806{
1807 struct abis_om_hdr *oh;
1808 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001809 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001810
1811 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1812 e1_port0, ts0, e1_port1, ts1);
1813
1814 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1815 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1816 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1817
1818 attr = msgb_put(msg, 3);
1819 attr[0] = NM_ATT_MDROP_LINK;
1820 attr[1] = e1_port0;
1821 attr[2] = ts0;
1822
1823 attr = msgb_put(msg, 3);
1824 attr[0] = NM_ATT_MDROP_NEXT;
1825 attr[1] = e1_port1;
1826 attr[2] = ts1;
1827
1828 return abis_nm_sendmsg(bts, msg);
1829}
Harald Welte59b04682009-06-10 05:40:52 +08001830
Harald Welte0bf8e302009-08-08 00:02:36 +02001831/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001832int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1833 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1834 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001835{
1836 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001837
Harald Weltec61a90e2011-05-22 22:45:37 +02001838 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001839
1840 if (!msg)
1841 msg = nm_msgb_alloc();
1842
1843 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1844 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1845 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1846 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001847 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001848
1849 return abis_nm_sendmsg(bts, msg);
1850}
1851
Harald Welte59b04682009-06-10 05:40:52 +08001852int abis_nm_event_reports(struct gsm_bts *bts, int on)
1853{
1854 if (on == 0)
1855 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1856 else
1857 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1858}
1859
1860/* Siemens (or BS-11) specific commands */
1861
1862int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1863{
1864 if (reconnect == 0)
1865 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1866 else
1867 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1868}
1869
1870int abis_nm_bs11_restart(struct gsm_bts *bts)
1871{
1872 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1873}
1874
1875
1876struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001877 uint16_t year;
1878 uint8_t month;
1879 uint8_t day;
1880 uint8_t hour;
1881 uint8_t min;
1882 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001883} __attribute__((packed));
1884
1885
1886void get_bs11_date_time(struct bs11_date_time *aet)
1887{
1888 time_t t;
1889 struct tm *tm;
1890
1891 t = time(NULL);
1892 tm = localtime(&t);
1893 aet->sec = tm->tm_sec;
1894 aet->min = tm->tm_min;
1895 aet->hour = tm->tm_hour;
1896 aet->day = tm->tm_mday;
1897 aet->month = tm->tm_mon;
1898 aet->year = htons(1900 + tm->tm_year);
1899}
1900
1901int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1902{
1903 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1904}
1905
1906int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1907{
1908 if (begin)
1909 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1910 else
1911 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1912}
1913
1914int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001915 enum abis_bs11_objtype type, uint8_t idx,
1916 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001917{
1918 struct abis_om_hdr *oh;
1919 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001920 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001921
1922 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1923 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1924 NM_OC_BS11, type, 0, idx);
1925 cur = msgb_put(msg, attr_len);
1926 memcpy(cur, attr, attr_len);
1927
1928 return abis_nm_sendmsg(bts, msg);
1929}
1930
1931int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001932 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001933{
1934 struct abis_om_hdr *oh;
1935 struct msgb *msg = nm_msgb_alloc();
1936
1937 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1938 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1939 NM_OC_BS11, type, 0, idx);
1940
1941 return abis_nm_sendmsg(bts, msg);
1942}
1943
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001944int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001945{
1946 struct abis_om_hdr *oh;
1947 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001948 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001949
1950 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1951 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1952 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1953 msgb_tlv_put(msg, 0x99, 1, &zero);
1954
1955 return abis_nm_sendmsg(bts, msg);
1956}
1957
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001958int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001959{
1960 struct abis_om_hdr *oh;
1961 struct msgb *msg = nm_msgb_alloc();
1962
1963 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1964 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001965 idx, 0xff, 0xff);
1966
1967 return abis_nm_sendmsg(bts, msg);
1968}
1969
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001970int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001971{
1972 struct abis_om_hdr *oh;
1973 struct msgb *msg = nm_msgb_alloc();
1974
1975 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1976 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1977 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001978
1979 return abis_nm_sendmsg(bts, msg);
1980}
1981
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001982static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001983int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1984{
1985 struct abis_om_hdr *oh;
1986 struct msgb *msg = nm_msgb_alloc();
1987
1988 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1989 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1990 0xff, 0xff, 0xff);
1991 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1992
1993 return abis_nm_sendmsg(bts, msg);
1994}
1995
1996/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001997int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1998 uint8_t e1_timeslot, uint8_t e1_subslot,
1999 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08002000{
2001 struct abis_om_hdr *oh;
2002 struct abis_nm_channel *ch;
2003 struct msgb *msg = nm_msgb_alloc();
2004
2005 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2006 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2007 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2008
2009 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2010 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2011 msgb_tv_put(msg, NM_ATT_TEI, tei);
2012
2013 return abis_nm_sendmsg(bts, msg);
2014}
2015
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002016int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08002017{
2018 struct abis_om_hdr *oh;
2019 struct msgb *msg = nm_msgb_alloc();
2020
2021 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2022 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2023 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2024 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2025
2026 return abis_nm_sendmsg(trx->bts, msg);
2027}
2028
2029int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2030{
2031 struct abis_om_hdr *oh;
2032 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002033 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08002034
2035 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2036 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2037 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2038 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2039
2040 return abis_nm_sendmsg(trx->bts, msg);
2041}
2042
2043int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2044{
2045 struct abis_om_hdr *oh;
2046 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002047 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08002048
2049 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2050 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2051 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2052 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2053
2054 return abis_nm_sendmsg(bts, msg);
2055}
2056
2057int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2058{
2059 struct abis_om_hdr *oh;
2060 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002061 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08002062 NM_ATT_BS11_CCLK_TYPE };
2063
2064 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2065 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2066 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2067 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2068
2069 return abis_nm_sendmsg(bts, msg);
2070
2071}
2072
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002073//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002074
2075int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2076{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002077 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2078}
2079
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002080int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2081{
2082 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2083}
2084
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002085int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002086{
Harald Welte59b04682009-06-10 05:40:52 +08002087 struct abis_om_hdr *oh;
2088 struct msgb *msg = nm_msgb_alloc();
2089 struct bs11_date_time bdt;
2090
2091 get_bs11_date_time(&bdt);
2092
2093 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2094 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002095 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002096 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002097 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2098 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2099 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002100 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08002101 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002102 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002103 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002104 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002105 } else {
2106 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2107 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2108 }
2109
2110 return abis_nm_sendmsg(bts, msg);
2111}
2112
2113int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2114{
2115 struct abis_om_hdr *oh;
2116 struct msgb *msg;
2117
2118 if (strlen(password) != 10)
2119 return -EINVAL;
2120
2121 msg = nm_msgb_alloc();
2122 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2123 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2124 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002125 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002126
2127 return abis_nm_sendmsg(bts, msg);
2128}
2129
2130/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2131int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2132{
2133 struct abis_om_hdr *oh;
2134 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002135 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002136
2137 msg = nm_msgb_alloc();
2138 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2139 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2140 BS11_OBJ_LI, 0x00, 0x00);
2141
2142 if (locked)
2143 tlv_value = BS11_LI_PLL_LOCKED;
2144 else
2145 tlv_value = BS11_LI_PLL_STANDALONE;
2146
2147 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2148
2149 return abis_nm_sendmsg(bts, msg);
2150}
2151
Daniel Willmann10b07db2010-01-07 00:54:01 +01002152/* Set the calibration value of the PLL (work value/set value)
2153 * It depends on the login which one is changed */
2154int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2155{
2156 struct abis_om_hdr *oh;
2157 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002158 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002159
2160 msg = nm_msgb_alloc();
2161 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2162 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2163 BS11_OBJ_TRX1, 0x00, 0x00);
2164
2165 tlv_value[0] = value>>8;
2166 tlv_value[1] = value&0xff;
2167
2168 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2169
2170 return abis_nm_sendmsg(bts, msg);
2171}
2172
Harald Welte59b04682009-06-10 05:40:52 +08002173int abis_nm_bs11_get_state(struct gsm_bts *bts)
2174{
2175 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2176}
2177
2178/* BS11 SWL */
2179
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002180void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002181
Harald Welte59b04682009-06-10 05:40:52 +08002182struct abis_nm_bs11_sw {
2183 struct gsm_bts *bts;
2184 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002185 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002186 int forced;
2187 struct llist_head file_list;
2188 gsm_cbfn *user_cb; /* specified by the user */
2189};
2190static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2191
2192struct file_list_entry {
2193 struct llist_head list;
2194 char fname[PATH_MAX];
2195};
2196
2197struct file_list_entry *fl_dequeue(struct llist_head *queue)
2198{
2199 struct llist_head *lh;
2200
2201 if (llist_empty(queue))
2202 return NULL;
2203
2204 lh = queue->next;
2205 llist_del(lh);
2206
2207 return llist_entry(lh, struct file_list_entry, list);
2208}
2209
2210static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2211{
2212 char linebuf[255];
2213 struct llist_head *lh, *lh2;
2214 FILE *swl;
2215 int rc = 0;
2216
2217 swl = fopen(bs11_sw->swl_fname, "r");
2218 if (!swl)
2219 return -ENODEV;
2220
2221 /* zero the stale file list, if any */
2222 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2223 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002224 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002225 }
2226
2227 while (fgets(linebuf, sizeof(linebuf), swl)) {
2228 char file_id[12+1];
2229 char file_version[80+1];
2230 struct file_list_entry *fle;
2231 static char dir[PATH_MAX];
2232
2233 if (strlen(linebuf) < 4)
2234 continue;
2235
2236 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2237 if (rc < 0) {
2238 perror("ERR parsing SWL file");
2239 rc = -EINVAL;
2240 goto out;
2241 }
2242 if (rc < 2)
2243 continue;
2244
Harald Welte857e00d2009-06-26 20:25:23 +02002245 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002246 if (!fle) {
2247 rc = -ENOMEM;
2248 goto out;
2249 }
Harald Welte59b04682009-06-10 05:40:52 +08002250
2251 /* construct new filename */
2252 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2253 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2254 strcat(fle->fname, "/");
2255 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2256
2257 llist_add_tail(&fle->list, &bs11_sw->file_list);
2258 }
2259
2260out:
2261 fclose(swl);
2262 return rc;
2263}
2264
2265/* bs11 swload specific callback, passed to abis_nm core swload */
2266static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2267 struct msgb *msg, void *data, void *param)
2268{
2269 struct abis_nm_bs11_sw *bs11_sw = data;
2270 struct file_list_entry *fle;
2271 int rc = 0;
2272
2273 switch (event) {
2274 case NM_MT_LOAD_END_ACK:
2275 fle = fl_dequeue(&bs11_sw->file_list);
2276 if (fle) {
2277 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002278 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002279 bs11_sw->win_size,
2280 bs11_sw->forced,
2281 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002282 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002283 } else {
2284 /* activate the SWL */
2285 rc = abis_nm_software_activate(bs11_sw->bts,
2286 bs11_sw->swl_fname,
2287 bs11_swload_cbfn,
2288 bs11_sw);
2289 }
2290 break;
2291 case NM_MT_LOAD_SEG_ACK:
2292 case NM_MT_LOAD_END_NACK:
2293 case NM_MT_LOAD_INIT_ACK:
2294 case NM_MT_LOAD_INIT_NACK:
2295 case NM_MT_ACTIVATE_SW_NACK:
2296 case NM_MT_ACTIVATE_SW_ACK:
2297 default:
2298 /* fallthrough to the user callback */
2299 if (bs11_sw->user_cb)
2300 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2301 break;
2302 }
2303
2304 return rc;
2305}
2306
2307/* Siemens provides a SWL file that is a mere listing of all the other
2308 * files that are part of a software release. We need to upload first
2309 * the list file, and then each file that is listed in the list file */
2310int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002311 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002312{
2313 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2314 struct file_list_entry *fle;
2315 int rc = 0;
2316
2317 INIT_LLIST_HEAD(&bs11_sw->file_list);
2318 bs11_sw->bts = bts;
2319 bs11_sw->win_size = win_size;
2320 bs11_sw->user_cb = cbfn;
2321 bs11_sw->forced = forced;
2322
2323 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2324 rc = bs11_read_swl_file(bs11_sw);
2325 if (rc < 0)
2326 return rc;
2327
2328 /* dequeue next item in file list */
2329 fle = fl_dequeue(&bs11_sw->file_list);
2330 if (!fle)
2331 return -EINVAL;
2332
2333 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002334 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002335 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002336 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002337 return rc;
2338}
2339
2340#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002341static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002342 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2343 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2344 NM_ATT_BS11_LMT_USER_NAME,
2345
2346 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2347
2348 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2349
2350 NM_ATT_BS11_SW_LOAD_STORED };
2351
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002352static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002353 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2354 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2355 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2356 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2357#endif
2358
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002359static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002360 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2361 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2362 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2363
2364int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2365{
2366 struct abis_om_hdr *oh;
2367 struct msgb *msg = nm_msgb_alloc();
2368
2369 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2370 /* SiemensHW CCTRL object */
2371 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2372 0x03, 0x00, 0x00);
2373 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2374
2375 return abis_nm_sendmsg(bts, msg);
2376}
2377
2378int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2379{
2380 struct abis_om_hdr *oh;
2381 struct msgb *msg = nm_msgb_alloc();
2382 struct bs11_date_time aet;
2383
2384 get_bs11_date_time(&aet);
2385 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2386 /* SiemensHW CCTRL object */
2387 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2388 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002389 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002390
2391 return abis_nm_sendmsg(bts, msg);
2392}
2393
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002394int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002395{
2396 struct abis_om_hdr *oh;
2397 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002398 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002399
2400 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2401 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2402 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2403 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2404
2405 return abis_nm_sendmsg(bts, msg);
2406}
2407
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002408int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg)
Daniel Willmann5655afe2009-08-10 11:49:36 +02002409{
2410 struct abis_om_hdr *oh;
2411 struct msgb *msg = nm_msgb_alloc();
2412 struct bs11_date_time aet;
2413
2414 get_bs11_date_time(&aet);
2415 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2416 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2417 bport, 0xff, 0x02);
2418 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2419
2420 return abis_nm_sendmsg(bts, msg);
2421}
2422
Harald Welte59b04682009-06-10 05:40:52 +08002423/* ip.access nanoBTS specific commands */
2424static const char ipaccess_magic[] = "com.ipaccess";
2425
2426
2427static int abis_nm_rx_ipacc(struct msgb *msg)
2428{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002429 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002430 struct abis_om_hdr *oh = msgb_l2(msg);
2431 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002432 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002433 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002434 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002435
2436 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002437 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002438 return -EINVAL;
2439 }
2440
2441 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002442 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002443
Harald Weltec61a90e2011-05-22 22:45:37 +02002444 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002445
Harald Welte5aeedd42009-10-19 22:11:11 +02002446 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002447
2448 switch (foh->msg_type) {
2449 case NM_MT_IPACC_RSL_CONNECT_ACK:
2450 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002451 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2452 memcpy(&addr,
2453 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2454
2455 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2456 }
Harald Welte4206d982009-07-12 09:33:54 +02002457 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002458 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002459 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002460 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002461 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2462 DEBUGPC(DNM, "STREAM=0x%02x ",
2463 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002464 DEBUGPC(DNM, "\n");
2465 break;
2466 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002467 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002468 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002469 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002470 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002471 else
2472 DEBUGPC(DNM, "\n");
2473 break;
2474 case NM_MT_IPACC_SET_NVATTR_ACK:
2475 DEBUGPC(DNM, "SET NVATTR ACK\n");
2476 /* FIXME: decode and show the actual attributes */
2477 break;
2478 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002479 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002480 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002481 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002482 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002483 else
Harald Weltede4477a2009-12-24 12:20:20 +01002484 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002485 break;
Harald Welte21460f02009-07-03 11:26:45 +02002486 case NM_MT_IPACC_GET_NVATTR_ACK:
2487 DEBUGPC(DNM, "GET NVATTR ACK\n");
2488 /* FIXME: decode and show the actual attributes */
2489 break;
2490 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002491 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002492 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002493 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002494 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002495 else
Harald Weltede4477a2009-12-24 12:20:20 +01002496 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002497 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002498 case NM_MT_IPACC_SET_ATTR_ACK:
2499 DEBUGPC(DNM, "SET ATTR ACK\n");
2500 break;
2501 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002502 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002503 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002504 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002505 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002506 else
Harald Weltede4477a2009-12-24 12:20:20 +01002507 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002508 break;
Harald Welte59b04682009-06-10 05:40:52 +08002509 default:
2510 DEBUGPC(DNM, "unknown\n");
2511 break;
2512 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002513
2514 /* signal handling */
2515 switch (foh->msg_type) {
2516 case NM_MT_IPACC_RSL_CONNECT_NACK:
2517 case NM_MT_IPACC_SET_NVATTR_NACK:
2518 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002519 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002520 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002521 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002522 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002523 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002524 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002525 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002526 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002527 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002528 default:
2529 break;
2530 }
2531
Harald Welte59b04682009-06-10 05:40:52 +08002532 return 0;
2533}
2534
2535/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002536int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2537 uint8_t obj_class, uint8_t bts_nr,
2538 uint8_t trx_nr, uint8_t ts_nr,
2539 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002540{
2541 struct msgb *msg = nm_msgb_alloc();
2542 struct abis_om_hdr *oh;
2543 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002544 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002545
2546 /* construct the 12.21 OM header, observe the erroneous length */
2547 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2548 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2549 oh->mdisc = ABIS_OM_MDISC_MANUF;
2550
2551 /* add the ip.access magic */
2552 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2553 *data++ = sizeof(ipaccess_magic);
2554 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2555
2556 /* fill the 12.21 FOM header */
2557 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2558 foh->msg_type = msg_type;
2559 foh->obj_class = obj_class;
2560 foh->obj_inst.bts_nr = bts_nr;
2561 foh->obj_inst.trx_nr = trx_nr;
2562 foh->obj_inst.ts_nr = ts_nr;
2563
2564 if (attr && attr_len) {
2565 data = msgb_put(msg, attr_len);
2566 memcpy(data, attr, attr_len);
2567 }
2568
2569 return abis_nm_sendmsg(bts, msg);
2570}
2571
2572/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002573int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002574 int attr_len)
2575{
Harald Weltef12c1052010-01-07 20:39:42 +01002576 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2577 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002578 attr_len);
2579}
2580
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002581int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002582 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002583{
2584 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002585 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002586 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2587 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2588
2589 int attr_len = sizeof(attr);
2590
2591 ia.s_addr = htonl(ip);
2592 attr[1] = stream;
2593 attr[3] = port >> 8;
2594 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002595 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002596
2597 /* if ip == 0, we use the default IP */
2598 if (ip == 0)
2599 attr_len -= 5;
2600
2601 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002602 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002603
2604 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2605 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2606 trx->nr, 0xff, attr, attr_len);
2607}
2608
Harald Welte59b04682009-06-10 05:40:52 +08002609/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002610int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002611{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002612 struct abis_om_hdr *oh;
2613 struct msgb *msg = nm_msgb_alloc();
2614
2615 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2616 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2617 trx->bts->nr, trx->nr, 0xff);
2618
2619 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002620}
Harald Welte0dfc6232009-10-24 10:20:41 +02002621
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002622int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2623 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2624 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002625{
2626 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2627 obj_class, bts_nr, trx_nr, ts_nr,
2628 attr, attr_len);
2629}
Harald Weltebeeae412009-11-12 14:48:42 +01002630
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002631void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002632{
2633 /* we simply reuse the GSM48 function and overwrite the RAC
2634 * with the Cell ID */
2635 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002636 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002637}
2638
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002639void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2640{
2641 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2642
Harald Welte69f6f812011-05-30 12:07:53 +02002643 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002644 if (!trx->bts || !trx->bts->oml_link)
2645 return;
2646
2647 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2648 trx->bts->bts_nr, trx->nr, 0xff,
2649 new_state);
2650}
2651
Harald Welte453141f2010-03-25 11:45:30 +08002652static const struct value_string ipacc_testres_names[] = {
2653 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2654 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2655 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2656 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2657 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2658 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002659};
2660
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002661const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002662{
Harald Welte453141f2010-03-25 11:45:30 +08002663 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002664}
2665
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002666void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002667{
2668 cid->mcc = (buf[0] & 0xf) * 100;
2669 cid->mcc += (buf[0] >> 4) * 10;
2670 cid->mcc += (buf[1] & 0xf) * 1;
2671
2672 if (buf[1] >> 4 == 0xf) {
2673 cid->mnc = (buf[2] & 0xf) * 10;
2674 cid->mnc += (buf[2] >> 4) * 1;
2675 } else {
2676 cid->mnc = (buf[2] & 0xf) * 100;
2677 cid->mnc += (buf[2] >> 4) * 10;
2678 cid->mnc += (buf[1] >> 4) * 1;
2679 }
2680
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002681 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2682 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002683}
2684
Harald Weltebeeae412009-11-12 14:48:42 +01002685/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002686int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002687{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002688 uint8_t *cur = buf;
2689 uint16_t len;
Harald Weltebeeae412009-11-12 14:48:42 +01002690
Harald Welteb784df82010-07-22 18:14:36 +02002691 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002692
2693 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2694 return -EINVAL;
2695 cur++;
2696
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002697 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002698 cur += 2;
2699
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002700 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002701 cur += 2;
2702
2703 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2704 binf->freq_qual = *cur >> 2;
2705
Harald Welteb784df82010-07-22 18:14:36 +02002706 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002707 binf->arfcn |= *cur++;
2708
2709 if (binf->info_type & IPAC_BINF_RXLEV)
2710 binf->rx_lev = *cur & 0x3f;
2711 cur++;
2712
2713 if (binf->info_type & IPAC_BINF_RXQUAL)
2714 binf->rx_qual = *cur & 0x7;
2715 cur++;
2716
2717 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002718 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002719 cur += 2;
2720
2721 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002722 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002723 cur += 2;
2724
2725 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002726 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002727 cur += 4;
2728
Harald Welte22cb81f2010-07-30 22:34:42 +02002729#if 0
2730 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002731 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002732#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002733 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002734 cur++;
2735
Harald Weltebfc21092009-11-13 11:56:05 +01002736 ipac_parse_cgi(&binf->cgi, cur);
2737 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002738
2739 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2740 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2741 cur += sizeof(binf->ba_list_si2);
2742 }
2743
2744 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2745 memcpy(binf->ba_list_si2bis, cur,
2746 sizeof(binf->ba_list_si2bis));
2747 cur += sizeof(binf->ba_list_si2bis);
2748 }
2749
2750 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2751 memcpy(binf->ba_list_si2ter, cur,
2752 sizeof(binf->ba_list_si2ter));
2753 cur += sizeof(binf->ba_list_si2ter);
2754 }
2755
2756 return 0;
2757}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002758
2759void abis_nm_clear_queue(struct gsm_bts *bts)
2760{
2761 struct msgb *msg;
2762
2763 while (!llist_empty(&bts->abis_queue)) {
2764 msg = msgb_dequeue(&bts->abis_queue);
2765 msgb_free(msg);
2766 }
2767
2768 bts->abis_nm_pend = 0;
2769}