blob: f2220a7b7e54746eddd609534bd0039aba813f2e [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 Welte59b04682009-06-10 05:40:52 +0800153/* obtain the gsm_nm_state data structure for a given object instance */
154static struct gsm_nm_state *
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200155objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800156 struct abis_om_obj_inst *obj_inst)
157{
158 struct gsm_bts_trx *trx;
159 struct gsm_nm_state *nm_state = NULL;
160
161 switch (obj_class) {
162 case NM_OC_BTS:
163 nm_state = &bts->nm_state;
164 break;
165 case NM_OC_RADIO_CARRIER:
Harald 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 Welte59b04682009-06-10 05:40:52 +0800171 nm_state = &trx->nm_state;
172 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 Welte59b04682009-06-10 05:40:52 +0800179 nm_state = &trx->bb_transc.nm_state;
180 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;
189 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
190 break;
191 case NM_OC_SITE_MANAGER:
192 nm_state = &bts->site_mgr.nm_state;
193 break;
194 case NM_OC_BS11:
195 switch (obj_inst->bts_nr) {
196 case BS11_OBJ_CCLK:
197 nm_state = &bts->bs11.cclk.nm_state;
198 break;
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 Welte59b04682009-06-10 05:40:52 +0800203 nm_state = &trx->bs11.bbsig.nm_state;
204 break;
205 case BS11_OBJ_PA:
206 if (obj_inst->ts_nr > bts->num_trx)
207 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200208 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800209 nm_state = &trx->bs11.pa.nm_state;
210 break;
211 default:
212 return NULL;
213 }
214 case NM_OC_BS11_RACK:
215 nm_state = &bts->bs11.rack.nm_state;
216 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;
220 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
221 break;
Harald Welte439e1282009-10-24 10:19:14 +0200222 case NM_OC_GPRS_NSE:
223 nm_state = &bts->gprs.nse.nm_state;
224 break;
225 case NM_OC_GPRS_CELL:
226 nm_state = &bts->gprs.cell.nm_state;
227 break;
228 case NM_OC_GPRS_NSVC:
Holger Hans Peter 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;
231 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
232 break;
Harald Welte59b04682009-06-10 05:40:52 +0800233 }
234 return nm_state;
235}
236
237/* obtain the in-memory data structure of a given object instance */
238static void *
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200239objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800240 struct abis_om_obj_inst *obj_inst)
241{
242 struct gsm_bts_trx *trx;
243 void *obj = NULL;
244
245 switch (obj_class) {
246 case NM_OC_BTS:
247 obj = bts;
248 break;
249 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100250 if (obj_inst->trx_nr >= bts->num_trx) {
251 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800252 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100253 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200254 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800255 obj = trx;
256 break;
257 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100258 if (obj_inst->trx_nr >= bts->num_trx) {
259 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800260 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100261 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200262 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800263 obj = &trx->bb_transc;
264 break;
265 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100266 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100267 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800268 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100269 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200270 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800271 if (obj_inst->ts_nr >= TRX_NR_TS)
272 return NULL;
273 obj = &trx->ts[obj_inst->ts_nr];
274 break;
275 case NM_OC_SITE_MANAGER:
276 obj = &bts->site_mgr;
277 break;
Harald Welte439e1282009-10-24 10:19:14 +0200278 case NM_OC_GPRS_NSE:
279 obj = &bts->gprs.nse;
280 break;
281 case NM_OC_GPRS_CELL:
282 obj = &bts->gprs.cell;
283 break;
284 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100285 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200286 return NULL;
287 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
288 break;
Harald Welte59b04682009-06-10 05:40:52 +0800289 }
290 return obj;
291}
292
293/* Update the administrative state of a given object in our in-memory data
294 * structures and send an event to the higher layer */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200295static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
296 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Welte59b04682009-06-10 05:40:52 +0800297{
298 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100299 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800300
Harald Weltea348c082011-03-06 21:20:38 +0100301 memset(&nsd, 0, sizeof(nsd));
302
Harald Welte4c826f72011-01-14 15:55:42 +0100303 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
304 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100305 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800306 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
307 if (!nm_state)
308 return -1;
309
310 new_state = *nm_state;
311 new_state.administrative = adm_state;
312
Harald Welteb03c4482011-03-06 22:11:32 +0100313 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100314 nsd.obj_class = obj_class;
315 nsd.old_state = nm_state;
316 nsd.new_state = &new_state;
317 nsd.obj_inst = obj_inst;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200318 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800319
320 nm_state->administrative = adm_state;
321
Harald Welte4c826f72011-01-14 15:55:42 +0100322 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800323}
324
325static int abis_nm_rx_statechg_rep(struct msgb *mb)
326{
327 struct abis_om_hdr *oh = msgb_l2(mb);
328 struct abis_om_fom_hdr *foh = msgb_l3(mb);
329 struct gsm_bts *bts = mb->trx->bts;
330 struct tlv_parsed tp;
331 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800332
333 DEBUGPC(DNM, "STATE CHG: ");
334
335 memset(&new_state, 0, sizeof(new_state));
336
337 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
338 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100339 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800340 return -EINVAL;
341 }
342
343 new_state = *nm_state;
344
Harald Welte59698fb2010-01-10 18:01:52 +0100345 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800346 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
347 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200348 DEBUGPC(DNM, "OP_STATE=%s ",
349 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800350 }
351 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
352 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
353 new_state.availability = 0xff;
354 else
355 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Weltec61a90e2011-05-22 22:45:37 +0200356 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
357 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800358 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100359 } else
360 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800361 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
362 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200363 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200364 get_value_string(abis_nm_adm_state_names,
365 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800366 }
367 DEBUGPC(DNM, "\n");
368
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100369 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
370 new_state.operational != nm_state->operational ||
371 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800372 /* Update the operational state of a given object in our in-memory data
373 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100374 struct nm_statechg_signal_data nsd;
375 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
376 nsd.obj_class = foh->obj_class;
377 nsd.old_state = nm_state;
378 nsd.new_state = &new_state;
379 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100380 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200381 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100382 nm_state->operational = new_state.operational;
383 nm_state->availability = new_state.availability;
384 if (nm_state->administrative == 0)
385 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800386 }
387#if 0
388 if (op_state == 1) {
389 /* try to enable objects that are disabled */
390 abis_nm_opstart(bts, foh->obj_class,
391 foh->obj_inst.bts_nr,
392 foh->obj_inst.trx_nr,
393 foh->obj_inst.ts_nr);
394 }
395#endif
396 return 0;
397}
398
399static int rx_fail_evt_rep(struct msgb *mb)
400{
401 struct abis_om_hdr *oh = msgb_l2(mb);
402 struct abis_om_fom_hdr *foh = msgb_l3(mb);
403 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100404 const uint8_t *p_val;
405 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800406
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200407 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800408
Harald Welte59698fb2010-01-10 18:01:52 +0100409 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800410
411 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Weltec61a90e2011-05-22 22:45:37 +0200412 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
413 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte59b04682009-06-10 05:40:52 +0800414 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Weltec61a90e2011-05-22 22:45:37 +0200415 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
416 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100417 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
418 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200419 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100420 }
421 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
422 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
423 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
424 if (p_text) {
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200425 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100426 talloc_free(p_text);
427 }
428 }
Harald Welte59b04682009-06-10 05:40:52 +0800429
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200430 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800431
432 return 0;
433}
434
435static int abis_nm_rcvmsg_report(struct msgb *mb)
436{
437 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200438 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800439
Harald Weltec61a90e2011-05-22 22:45:37 +0200440 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800441
442 //nmh->cfg->report_cb(mb, foh);
443
444 switch (mt) {
445 case NM_MT_STATECHG_EVENT_REP:
446 return abis_nm_rx_statechg_rep(mb);
447 break;
448 case NM_MT_SW_ACTIVATED_REP:
449 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200450 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800451 break;
452 case NM_MT_FAILURE_EVENT_REP:
453 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200454 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800455 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200456 case NM_MT_TEST_REP:
457 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200458 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200459 break;
Harald Welte59b04682009-06-10 05:40:52 +0800460 default:
461 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
462 break;
463
464 };
465
466 return 0;
467}
468
469/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200470static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
471 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800472{
473 struct abis_om_hdr *oh;
474 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200475 uint8_t len = swdesc_len;
476 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800477
478 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
479 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
480
481 trailer = msgb_put(msg, swdesc_len);
482 memcpy(trailer, sw_desc, swdesc_len);
483
484 return abis_nm_sendmsg(bts, msg);
485}
486
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200487static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100488{
489 static const struct tlv_definition sw_descr_def = {
490 .def = {
491 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
492 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
493 },
494 };
495
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200496 uint8_t tag;
497 uint16_t tag_len;
498 const uint8_t *val;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100499 int ofs = 0, len;
500
501 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
502 * nested nature and the fact you have to assume it contains only two sub
503 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
504
505 if (sw_descr[0] != NM_ATT_SW_DESCR) {
506 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
507 return -1;
508 }
509 ofs += 1;
510
511 len = tlv_parse_one(&tag, &tag_len, &val,
512 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
513 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
514 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
515 return -2;
516 }
517 ofs += len;
518
519 len = tlv_parse_one(&tag, &tag_len, &val,
520 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
521 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
522 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
523 return -3;
524 }
525 ofs += len;
526
527 return ofs;
528}
529
Harald Welte59b04682009-06-10 05:40:52 +0800530static int abis_nm_rx_sw_act_req(struct msgb *mb)
531{
532 struct abis_om_hdr *oh = msgb_l2(mb);
533 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200534 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200535 const uint8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100536 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800537
Harald Weltec61a90e2011-05-22 22:45:37 +0200538 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200539
540 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800541
Harald Welte3055e332010-03-14 15:37:43 +0800542 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800543
544 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
545 foh->obj_inst.bts_nr,
546 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800547 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800548 foh->data, oh->length-sizeof(*foh));
549
Harald Welte59698fb2010-01-10 18:01:52 +0100550 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200551 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
552 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
553 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
554 DEBUGP(DNM, "SW config not found! Can't continue.\n");
555 return -EINVAL;
556 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200557 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200558 }
559
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100560 /* Use the first SW_DESCR present in SW config */
561 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
562 if (sw_descr_len < 0)
563 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200564
Harald Welte59b04682009-06-10 05:40:52 +0800565 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
566 foh->obj_inst.bts_nr,
567 foh->obj_inst.trx_nr,
568 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100569 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800570}
571
572/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
573static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
574{
575 struct abis_om_hdr *oh = msgb_l2(mb);
576 struct abis_om_fom_hdr *foh = msgb_l3(mb);
577 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200578 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800579
Harald Welte59698fb2010-01-10 18:01:52 +0100580 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800581 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
582 return -EINVAL;
583
584 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
585
586 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
587}
588
589static int abis_nm_rx_lmt_event(struct msgb *mb)
590{
591 struct abis_om_hdr *oh = msgb_l2(mb);
592 struct abis_om_fom_hdr *foh = msgb_l3(mb);
593 struct tlv_parsed tp;
594
595 DEBUGP(DNM, "LMT Event ");
Harald Welte59698fb2010-01-10 18:01:52 +0100596 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800597 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
598 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200599 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800600 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
601 }
602 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
603 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200604 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800605 DEBUGPC(DNM, "Level=%u ", level);
606 }
607 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
608 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
609 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
610 DEBUGPC(DNM, "Username=%s ", name);
611 }
612 DEBUGPC(DNM, "\n");
613 /* FIXME: parse LMT LOGON TIME */
614 return 0;
615}
616
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100617static void abis_nm_queue_send_next(struct gsm_bts *bts)
618{
619 int wait = 0;
620 struct msgb *msg;
621 /* the queue is empty */
622 while (!llist_empty(&bts->abis_queue)) {
623 msg = msgb_dequeue(&bts->abis_queue);
624 wait = OBSC_NM_W_ACK_CB(msg);
Harald Weltec5845042011-02-14 15:26:13 +0100625 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100626
627 if (wait)
628 break;
629 }
630
631 bts->abis_nm_pend = wait;
632}
633
Harald Welte59b04682009-06-10 05:40:52 +0800634/* Receive a OML NM Message from BTS */
635static int abis_nm_rcvmsg_fom(struct msgb *mb)
636{
637 struct abis_om_hdr *oh = msgb_l2(mb);
638 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200639 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100640 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800641
642 /* check for unsolicited message */
643 if (is_report(mt))
644 return abis_nm_rcvmsg_report(mb);
645
Harald Weltec61a90e2011-05-22 22:45:37 +0200646 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800647 return abis_nm_rcvmsg_sw(mb);
648
Harald Weltec61a90e2011-05-22 22:45:37 +0200649 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800650 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800651 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200652
Harald Weltec61a90e2011-05-22 22:45:37 +0200653 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200654
Harald Weltec61a90e2011-05-22 22:45:37 +0200655 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800656
Harald Welte59698fb2010-01-10 18:01:52 +0100657 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800658 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200659 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200660 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800661 else
662 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200663
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800664 nack_data.msg = mb;
665 nack_data.mt = mt;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200666 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100667 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200668 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800669 }
670#if 0
671 /* check if last message is to be acked */
672 if (is_ack_nack(nmh->last_msgtype)) {
673 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100674 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800675 /* we got our ACK, continue sending the next msg */
676 } else if (mt == MT_NACK(nmh->last_msgtype)) {
677 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100678 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800679 /* FIXME: somehow signal this to the caller */
680 } else {
681 /* really strange things happen */
682 return -EINVAL;
683 }
684 }
685#endif
686
687 switch (mt) {
688 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100689 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800690 break;
691 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100692 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800693 break;
694 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100695 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800696 break;
Harald Welte204317e2009-08-06 17:58:31 +0200697 case NM_MT_CONN_MDROP_LINK_ACK:
698 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
699 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100700 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200701 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100702 break;
703 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200704 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100705 break;
Harald Welte08011e22011-03-04 13:41:31 +0100706 case NM_MT_SET_BTS_ATTR_ACK:
707 /* The HSL wants an OPSTART _after_ the SI has been set */
708 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
709 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
710 }
711 break;
Harald Welte59b04682009-06-10 05:40:52 +0800712 }
713
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100714 abis_nm_queue_send_next(mb->trx->bts);
715 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800716}
717
718static int abis_nm_rx_ipacc(struct msgb *mb);
719
720static int abis_nm_rcvmsg_manuf(struct msgb *mb)
721{
722 int rc;
723 int bts_type = mb->trx->bts->type;
724
725 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100726 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +0800727 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100728 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800729 break;
730 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100731 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
732 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800733 rc = 0;
734 break;
735 }
736
737 return rc;
738}
739
740/* High-Level API */
741/* Entry-point where L2 OML from BTS enters the NM code */
742int abis_nm_rcvmsg(struct msgb *msg)
743{
744 struct abis_om_hdr *oh = msgb_l2(msg);
745 int rc = 0;
746
747 /* Various consistency checks */
748 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100749 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800750 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +0200751 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
752 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800753 }
754 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100755 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800756 oh->sequence);
757 return -EINVAL;
758 }
759#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200760 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800761 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
762 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100763 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800764 oh->length + sizeof(*oh), l2_len);
765 return -EINVAL;
766 }
767 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100768 LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
Harald Welte59b04682009-06-10 05:40:52 +0800769#endif
770 msg->l3h = (unsigned char *)oh + sizeof(*oh);
771
772 switch (oh->mdisc) {
773 case ABIS_OM_MDISC_FOM:
774 rc = abis_nm_rcvmsg_fom(msg);
775 break;
776 case ABIS_OM_MDISC_MANUF:
777 rc = abis_nm_rcvmsg_manuf(msg);
778 break;
779 case ABIS_OM_MDISC_MMI:
780 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100781 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800782 oh->mdisc);
783 break;
784 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100785 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800786 oh->mdisc);
787 return -EINVAL;
788 }
789
790 msgb_free(msg);
791 return rc;
792}
793
794#if 0
795/* initialized all resources */
796struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
797{
798 struct abis_nm_h *nmh;
799
800 nmh = malloc(sizeof(*nmh));
801 if (!nmh)
802 return NULL;
803
804 nmh->cfg = cfg;
805
806 return nmh;
807}
808
809/* free all resources */
810void abis_nm_fini(struct abis_nm_h *nmh)
811{
812 free(nmh);
813}
814#endif
815
816/* Here we are trying to define a high-level API that can be used by
817 * the actual BSC implementation. However, the architecture is currently
818 * still under design. Ideally the calls to this API would be synchronous,
819 * while the underlying stack behind the APi runs in a traditional select
820 * based state machine.
821 */
822
823/* 6.2 Software Load: */
824enum sw_state {
825 SW_STATE_NONE,
826 SW_STATE_WAIT_INITACK,
827 SW_STATE_WAIT_SEGACK,
828 SW_STATE_WAIT_ENDACK,
829 SW_STATE_WAIT_ACTACK,
830 SW_STATE_ERROR,
831};
832
833struct abis_nm_sw {
834 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800835 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800836 gsm_cbfn *cbfn;
837 void *cb_data;
838 int forced;
839
840 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200841 uint8_t obj_class;
842 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800843
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200844 uint8_t file_id[255];
845 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800846
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200847 uint8_t file_version[255];
848 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800849
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200850 uint8_t window_size;
851 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800852
853 int fd;
854 FILE *stream;
855 enum sw_state state;
856 int last_seg;
857};
858
859static struct abis_nm_sw g_sw;
860
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100861static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
862{
863 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
864 msgb_v_put(msg, NM_ATT_SW_DESCR);
865 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
866 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
867 sw->file_version);
868 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
869 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
870 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
871 sw->file_version);
872 } else {
873 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
874 }
875}
876
Harald Welte59b04682009-06-10 05:40:52 +0800877/* 6.2.1 / 8.3.1: Load Data Initiate */
878static int sw_load_init(struct abis_nm_sw *sw)
879{
880 struct abis_om_hdr *oh;
881 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200882 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800883
884 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
885 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
886 sw->obj_instance[0], sw->obj_instance[1],
887 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100888
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100889 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800890 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
891
892 return abis_nm_sendmsg(sw->bts, msg);
893}
894
895static int is_last_line(FILE *stream)
896{
897 char next_seg_buf[256];
898 long pos;
899
900 /* check if we're sending the last line */
901 pos = ftell(stream);
902 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
903 fseek(stream, pos, SEEK_SET);
904 return 1;
905 }
906
907 fseek(stream, pos, SEEK_SET);
908 return 0;
909}
910
911/* 6.2.2 / 8.3.2 Load Data Segment */
912static int sw_load_segment(struct abis_nm_sw *sw)
913{
914 struct abis_om_hdr *oh;
915 struct msgb *msg = nm_msgb_alloc();
916 char seg_buf[256];
917 char *line_buf = seg_buf+2;
918 unsigned char *tlv;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200919 uint8_t len;
Harald Welte59b04682009-06-10 05:40:52 +0800920
921 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
922
923 switch (sw->bts->type) {
924 case GSM_BTS_TYPE_BS11:
925 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
926 perror("fgets reading segment");
927 return -EINVAL;
928 }
929 seg_buf[0] = 0x00;
930
931 /* check if we're sending the last line */
932 sw->last_seg = is_last_line(sw->stream);
933 if (sw->last_seg)
934 seg_buf[1] = 0;
935 else
936 seg_buf[1] = 1 + sw->seg_in_window++;
937
938 len = strlen(line_buf) + 2;
939 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200940 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800941 /* BS11 wants CR + LF in excess of the TLV length !?! */
942 tlv[1] -= 2;
943
944 /* we only now know the exact length for the OM hdr */
945 len = strlen(line_buf)+2;
946 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100947 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200948 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100949 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
950 if (len < 0) {
951 perror("read failed");
952 return -EINVAL;
953 }
954
955 if (len != IPACC_SEGMENT_SIZE)
956 sw->last_seg = 1;
957
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100958 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200959 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100960 len += 3;
961 break;
962 }
Harald Welte59b04682009-06-10 05:40:52 +0800963 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100964 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800965 /* FIXME: Other BTS types */
966 return -1;
967 }
968
969 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
970 sw->obj_instance[0], sw->obj_instance[1],
971 sw->obj_instance[2]);
972
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100973 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800974}
975
976/* 6.2.4 / 8.3.4 Load Data End */
977static int sw_load_end(struct abis_nm_sw *sw)
978{
979 struct abis_om_hdr *oh;
980 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200981 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800982
983 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
984 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
985 sw->obj_instance[0], sw->obj_instance[1],
986 sw->obj_instance[2]);
987
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100988 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800989 return abis_nm_sendmsg(sw->bts, msg);
990}
991
992/* Activate the specified software into the BTS */
993static int sw_activate(struct abis_nm_sw *sw)
994{
995 struct abis_om_hdr *oh;
996 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200997 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800998
999 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1000 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1001 sw->obj_instance[0], sw->obj_instance[1],
1002 sw->obj_instance[2]);
1003
1004 /* FIXME: this is BS11 specific format */
1005 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1006 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1007 sw->file_version);
1008
1009 return abis_nm_sendmsg(sw->bts, msg);
1010}
1011
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001012struct sdp_firmware {
1013 char magic[4];
1014 char more_magic[4];
1015 unsigned int header_length;
1016 unsigned int file_length;
1017} __attribute__ ((packed));
1018
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001019static int parse_sdp_header(struct abis_nm_sw *sw)
1020{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001021 struct sdp_firmware firmware_header;
1022 int rc;
1023 struct stat stat;
1024
1025 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1026 if (rc != sizeof(firmware_header)) {
1027 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1028 return -1;
1029 }
1030
1031 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1032 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1033 return -1;
1034 }
1035
1036 if (firmware_header.more_magic[0] != 0x10 ||
1037 firmware_header.more_magic[1] != 0x02 ||
1038 firmware_header.more_magic[2] != 0x00 ||
1039 firmware_header.more_magic[3] != 0x00) {
1040 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1041 return -1;
1042 }
1043
1044
1045 if (fstat(sw->fd, &stat) == -1) {
1046 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1047 return -1;
1048 }
1049
1050 if (ntohl(firmware_header.file_length) != stat.st_size) {
1051 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1052 return -1;
1053 }
1054
1055 /* go back to the start as we checked the whole filesize.. */
1056 lseek(sw->fd, 0l, SEEK_SET);
1057 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1058 "There might be checksums in the file that are not\n"
1059 "verified and incomplete firmware might be flashed.\n"
1060 "There is absolutely no WARRANTY that flashing will\n"
1061 "work.\n");
1062 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001063}
1064
Harald Welte59b04682009-06-10 05:40:52 +08001065static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1066{
1067 char file_id[12+1];
1068 char file_version[80+1];
1069 int rc;
1070
1071 sw->fd = open(fname, O_RDONLY);
1072 if (sw->fd < 0)
1073 return sw->fd;
1074
1075 switch (sw->bts->type) {
1076 case GSM_BTS_TYPE_BS11:
1077 sw->stream = fdopen(sw->fd, "r");
1078 if (!sw->stream) {
1079 perror("fdopen");
1080 return -1;
1081 }
1082 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001083 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001084 file_id, file_version);
1085 if (rc != 2) {
1086 perror("parsing header line of software file");
1087 return -1;
1088 }
1089 strcpy((char *)sw->file_id, file_id);
1090 sw->file_id_len = strlen(file_id);
1091 strcpy((char *)sw->file_version, file_version);
1092 sw->file_version_len = strlen(file_version);
1093 /* rewind to start of file */
1094 rewind(sw->stream);
1095 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001096 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001097 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001098 rc = parse_sdp_header(sw);
1099 if (rc < 0) {
1100 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1101 return -1;
1102 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001103
1104 strcpy((char *)sw->file_id, "id");
1105 sw->file_id_len = 3;
1106 strcpy((char *)sw->file_version, "version");
1107 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001108 break;
Harald Welte59b04682009-06-10 05:40:52 +08001109 default:
1110 /* We don't know how to treat them yet */
1111 close(sw->fd);
1112 return -EINVAL;
1113 }
1114
1115 return 0;
1116}
1117
1118static void sw_close_file(struct abis_nm_sw *sw)
1119{
1120 switch (sw->bts->type) {
1121 case GSM_BTS_TYPE_BS11:
1122 fclose(sw->stream);
1123 break;
1124 default:
1125 close(sw->fd);
1126 break;
1127 }
1128}
1129
1130/* Fill the window */
1131static int sw_fill_window(struct abis_nm_sw *sw)
1132{
1133 int rc;
1134
1135 while (sw->seg_in_window < sw->window_size) {
1136 rc = sw_load_segment(sw);
1137 if (rc < 0)
1138 return rc;
1139 if (sw->last_seg)
1140 break;
1141 }
1142 return 0;
1143}
1144
1145/* callback function from abis_nm_rcvmsg() handler */
1146static int abis_nm_rcvmsg_sw(struct msgb *mb)
1147{
1148 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1149 int rc = -1;
1150 struct abis_nm_sw *sw = &g_sw;
1151 enum sw_state old_state = sw->state;
1152
1153 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1154
1155 switch (sw->state) {
1156 case SW_STATE_WAIT_INITACK:
1157 switch (foh->msg_type) {
1158 case NM_MT_LOAD_INIT_ACK:
1159 /* fill window with segments */
1160 if (sw->cbfn)
1161 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1162 NM_MT_LOAD_INIT_ACK, mb,
1163 sw->cb_data, NULL);
1164 rc = sw_fill_window(sw);
1165 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001166 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001167 break;
1168 case NM_MT_LOAD_INIT_NACK:
1169 if (sw->forced) {
1170 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1171 "Init NACK\n");
1172 if (sw->cbfn)
1173 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1174 NM_MT_LOAD_INIT_ACK, mb,
1175 sw->cb_data, NULL);
1176 rc = sw_fill_window(sw);
1177 sw->state = SW_STATE_WAIT_SEGACK;
1178 } else {
1179 DEBUGP(DNM, "Software Load Init NACK\n");
1180 /* FIXME: cause */
1181 if (sw->cbfn)
1182 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1183 NM_MT_LOAD_INIT_NACK, mb,
1184 sw->cb_data, NULL);
1185 sw->state = SW_STATE_ERROR;
1186 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001187 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001188 break;
1189 }
1190 break;
1191 case SW_STATE_WAIT_SEGACK:
1192 switch (foh->msg_type) {
1193 case NM_MT_LOAD_SEG_ACK:
1194 if (sw->cbfn)
1195 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1196 NM_MT_LOAD_SEG_ACK, mb,
1197 sw->cb_data, NULL);
1198 sw->seg_in_window = 0;
1199 if (!sw->last_seg) {
1200 /* fill window with more segments */
1201 rc = sw_fill_window(sw);
1202 sw->state = SW_STATE_WAIT_SEGACK;
1203 } else {
1204 /* end the transfer */
1205 sw->state = SW_STATE_WAIT_ENDACK;
1206 rc = sw_load_end(sw);
1207 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001208 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001209 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001210 case NM_MT_LOAD_ABORT:
1211 if (sw->cbfn)
1212 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1213 NM_MT_LOAD_ABORT, mb,
1214 sw->cb_data, NULL);
1215 break;
Harald Welte59b04682009-06-10 05:40:52 +08001216 }
1217 break;
1218 case SW_STATE_WAIT_ENDACK:
1219 switch (foh->msg_type) {
1220 case NM_MT_LOAD_END_ACK:
1221 sw_close_file(sw);
1222 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1223 sw->bts->nr);
1224 sw->state = SW_STATE_NONE;
1225 if (sw->cbfn)
1226 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1227 NM_MT_LOAD_END_ACK, mb,
1228 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001229 rc = 0;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001230 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001231 break;
1232 case NM_MT_LOAD_END_NACK:
1233 if (sw->forced) {
1234 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1235 "End NACK\n");
1236 sw->state = SW_STATE_NONE;
1237 if (sw->cbfn)
1238 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1239 NM_MT_LOAD_END_ACK, mb,
1240 sw->cb_data, NULL);
1241 } else {
1242 DEBUGP(DNM, "Software Load End NACK\n");
1243 /* FIXME: cause */
1244 sw->state = SW_STATE_ERROR;
1245 if (sw->cbfn)
1246 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1247 NM_MT_LOAD_END_NACK, mb,
1248 sw->cb_data, NULL);
1249 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001250 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001251 break;
1252 }
1253 case SW_STATE_WAIT_ACTACK:
1254 switch (foh->msg_type) {
1255 case NM_MT_ACTIVATE_SW_ACK:
1256 /* we're done */
1257 DEBUGP(DNM, "Activate Software DONE!\n");
1258 sw->state = SW_STATE_NONE;
1259 rc = 0;
1260 if (sw->cbfn)
1261 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1262 NM_MT_ACTIVATE_SW_ACK, mb,
1263 sw->cb_data, NULL);
Holger Hans Peter 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 case NM_MT_ACTIVATE_SW_NACK:
1267 DEBUGP(DNM, "Activate Software NACK\n");
1268 /* FIXME: cause */
1269 sw->state = SW_STATE_ERROR;
1270 if (sw->cbfn)
1271 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1272 NM_MT_ACTIVATE_SW_NACK, mb,
1273 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001274 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001275 break;
1276 }
1277 case SW_STATE_NONE:
1278 switch (foh->msg_type) {
1279 case NM_MT_ACTIVATE_SW_ACK:
1280 rc = 0;
1281 break;
1282 }
1283 break;
1284 case SW_STATE_ERROR:
1285 break;
1286 }
1287
1288 if (rc)
1289 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1290 foh->msg_type, old_state, sw->state);
1291
1292 return rc;
1293}
1294
1295/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001296int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001297 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001298 gsm_cbfn *cbfn, void *cb_data)
1299{
1300 struct abis_nm_sw *sw = &g_sw;
1301 int rc;
1302
1303 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1304 bts->nr, fname);
1305
1306 if (sw->state != SW_STATE_NONE)
1307 return -EBUSY;
1308
1309 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001310 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001311
1312 switch (bts->type) {
1313 case GSM_BTS_TYPE_BS11:
1314 sw->obj_class = NM_OC_SITE_MANAGER;
1315 sw->obj_instance[0] = 0xff;
1316 sw->obj_instance[1] = 0xff;
1317 sw->obj_instance[2] = 0xff;
1318 break;
1319 case GSM_BTS_TYPE_NANOBTS:
1320 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001321 sw->obj_instance[0] = sw->bts->nr;
1322 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001323 sw->obj_instance[2] = 0xff;
1324 break;
1325 case GSM_BTS_TYPE_UNKNOWN:
1326 default:
1327 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1328 return -1;
1329 break;
1330 }
Harald Welte59b04682009-06-10 05:40:52 +08001331 sw->window_size = win_size;
1332 sw->state = SW_STATE_WAIT_INITACK;
1333 sw->cbfn = cbfn;
1334 sw->cb_data = cb_data;
1335 sw->forced = forced;
1336
1337 rc = sw_open_file(sw, fname);
1338 if (rc < 0) {
1339 sw->state = SW_STATE_NONE;
1340 return rc;
1341 }
1342
1343 return sw_load_init(sw);
1344}
1345
1346int abis_nm_software_load_status(struct gsm_bts *bts)
1347{
1348 struct abis_nm_sw *sw = &g_sw;
1349 struct stat st;
1350 int rc, percent;
1351
1352 rc = fstat(sw->fd, &st);
1353 if (rc < 0) {
1354 perror("ERROR during stat");
1355 return rc;
1356 }
1357
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001358 if (sw->stream)
1359 percent = (ftell(sw->stream) * 100) / st.st_size;
1360 else
1361 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001362 return percent;
1363}
1364
1365/* Activate the specified software into the BTS */
1366int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1367 gsm_cbfn *cbfn, void *cb_data)
1368{
1369 struct abis_nm_sw *sw = &g_sw;
1370 int rc;
1371
1372 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1373 bts->nr, fname);
1374
1375 if (sw->state != SW_STATE_NONE)
1376 return -EBUSY;
1377
1378 sw->bts = bts;
1379 sw->obj_class = NM_OC_SITE_MANAGER;
1380 sw->obj_instance[0] = 0xff;
1381 sw->obj_instance[1] = 0xff;
1382 sw->obj_instance[2] = 0xff;
1383 sw->state = SW_STATE_WAIT_ACTACK;
1384 sw->cbfn = cbfn;
1385 sw->cb_data = cb_data;
1386
1387 /* Open the file in order to fill some sw struct members */
1388 rc = sw_open_file(sw, fname);
1389 if (rc < 0) {
1390 sw->state = SW_STATE_NONE;
1391 return rc;
1392 }
1393 sw_close_file(sw);
1394
1395 return sw_activate(sw);
1396}
1397
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001398static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1399 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001400{
1401 ch->attrib = NM_ATT_ABIS_CHANNEL;
1402 ch->bts_port = bts_port;
1403 ch->timeslot = ts_nr;
1404 ch->subslot = subslot_nr;
1405}
1406
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001407int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1408 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1409 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001410{
1411 struct abis_om_hdr *oh;
1412 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001413 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001414 struct msgb *msg = nm_msgb_alloc();
1415
1416 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1417 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1418 bts->bts_nr, trx_nr, 0xff);
1419
1420 msgb_tv_put(msg, NM_ATT_TEI, tei);
1421
1422 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1423 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1424
1425 return abis_nm_sendmsg(bts, msg);
1426}
1427
1428/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1429int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001430 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001431{
1432 struct gsm_bts *bts = trx->bts;
1433 struct abis_om_hdr *oh;
1434 struct abis_nm_channel *ch;
1435 struct msgb *msg = nm_msgb_alloc();
1436
1437 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1438 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1439 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1440
1441 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1442 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1443
1444 return abis_nm_sendmsg(bts, msg);
1445}
1446
1447#if 0
1448int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1449 struct abis_nm_abis_channel *chan)
1450{
1451}
1452#endif
1453
1454int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001455 uint8_t e1_port, uint8_t e1_timeslot,
1456 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001457{
1458 struct gsm_bts *bts = ts->trx->bts;
1459 struct abis_om_hdr *oh;
1460 struct abis_nm_channel *ch;
1461 struct msgb *msg = nm_msgb_alloc();
1462
1463 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1464 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1465 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1466
1467 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1468 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1469
1470 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1471 gsm_ts_name(ts),
1472 e1_port, e1_timeslot, e1_subslot);
1473
1474 return abis_nm_sendmsg(bts, msg);
1475}
1476
1477#if 0
1478int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1479 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001480 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001481{
1482}
1483#endif
1484
1485/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001486int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001487{
1488 struct abis_om_hdr *oh;
1489 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001490 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001491
1492 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1493
1494 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1495 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1496 cur = msgb_put(msg, attr_len);
1497 memcpy(cur, attr, attr_len);
1498
1499 return abis_nm_sendmsg(bts, msg);
1500}
1501
1502/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001503int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001504{
1505 struct abis_om_hdr *oh;
1506 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001507 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001508
1509 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1510
1511 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1512 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1513 trx->bts->bts_nr, trx->nr, 0xff);
1514 cur = msgb_put(msg, attr_len);
1515 memcpy(cur, attr, attr_len);
1516
1517 return abis_nm_sendmsg(trx->bts, msg);
1518}
1519
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001520static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Weltef2eb2782009-08-09 21:49:48 +02001521{
1522 int i;
1523
1524 /* As it turns out, the BS-11 has some very peculiar restrictions
1525 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301526 switch (ts->trx->bts->type) {
1527 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001528 switch (chan_comb) {
1529 case NM_CHANC_TCHHalf:
1530 case NM_CHANC_TCHHalf2:
1531 /* not supported */
1532 return -EINVAL;
1533 case NM_CHANC_SDCCH:
1534 /* only one SDCCH/8 per TRX */
1535 for (i = 0; i < TRX_NR_TS; i++) {
1536 if (i == ts->nr)
1537 continue;
1538 if (ts->trx->ts[i].nm_chan_comb ==
1539 NM_CHANC_SDCCH)
1540 return -EINVAL;
1541 }
1542 /* not allowed for TS0 of BCCH-TRX */
1543 if (ts->trx == ts->trx->bts->c0 &&
1544 ts->nr == 0)
1545 return -EINVAL;
1546 /* not on the same TRX that has a BCCH+SDCCH4
1547 * combination */
1548 if (ts->trx == ts->trx->bts->c0 &&
1549 (ts->trx->ts[0].nm_chan_comb == 5 ||
1550 ts->trx->ts[0].nm_chan_comb == 8))
1551 return -EINVAL;
1552 break;
1553 case NM_CHANC_mainBCCH:
1554 case NM_CHANC_BCCHComb:
1555 /* allowed only for TS0 of C0 */
1556 if (ts->trx != ts->trx->bts->c0 ||
1557 ts->nr != 0)
1558 return -EINVAL;
1559 break;
1560 case NM_CHANC_BCCH:
1561 /* allowed only for TS 2/4/6 of C0 */
1562 if (ts->trx != ts->trx->bts->c0)
1563 return -EINVAL;
1564 if (ts->nr != 2 && ts->nr != 4 &&
1565 ts->nr != 6)
1566 return -EINVAL;
1567 break;
1568 case 8: /* this is not like 08.58, but in fact
1569 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1570 /* FIXME: only one CBCH allowed per cell */
1571 break;
1572 }
Harald Welte76ba8812009-12-02 02:45:23 +05301573 break;
1574 case GSM_BTS_TYPE_NANOBTS:
1575 switch (ts->nr) {
1576 case 0:
1577 if (ts->trx->nr == 0) {
1578 /* only on TRX0 */
1579 switch (chan_comb) {
1580 case NM_CHANC_BCCH:
1581 case NM_CHANC_mainBCCH:
1582 case NM_CHANC_BCCHComb:
1583 return 0;
1584 break;
1585 default:
1586 return -EINVAL;
1587 }
1588 } else {
1589 switch (chan_comb) {
1590 case NM_CHANC_TCHFull:
1591 case NM_CHANC_TCHHalf:
1592 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1593 return 0;
1594 default:
1595 return -EINVAL;
1596 }
1597 }
1598 break;
1599 case 1:
1600 if (ts->trx->nr == 0) {
1601 switch (chan_comb) {
1602 case NM_CHANC_SDCCH_CBCH:
1603 if (ts->trx->ts[0].nm_chan_comb ==
1604 NM_CHANC_mainBCCH)
1605 return 0;
1606 return -EINVAL;
1607 case NM_CHANC_SDCCH:
1608 case NM_CHANC_TCHFull:
1609 case NM_CHANC_TCHHalf:
1610 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1611 case NM_CHANC_IPAC_TCHFull_PDCH:
1612 return 0;
1613 }
1614 } else {
1615 switch (chan_comb) {
1616 case NM_CHANC_SDCCH:
1617 case NM_CHANC_TCHFull:
1618 case NM_CHANC_TCHHalf:
1619 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1620 return 0;
1621 default:
1622 return -EINVAL;
1623 }
1624 }
1625 break;
1626 case 2:
1627 case 3:
1628 case 4:
1629 case 5:
1630 case 6:
1631 case 7:
1632 switch (chan_comb) {
1633 case NM_CHANC_TCHFull:
1634 case NM_CHANC_TCHHalf:
1635 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1636 return 0;
1637 case NM_CHANC_IPAC_PDCH:
1638 case NM_CHANC_IPAC_TCHFull_PDCH:
1639 if (ts->trx->nr == 0)
1640 return 0;
1641 else
1642 return -EINVAL;
1643 }
1644 break;
1645 }
1646 return -EINVAL;
1647 default:
1648 /* unknown BTS type */
1649 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001650 }
1651 return 0;
1652}
1653
Harald Welte59b04682009-06-10 05:40:52 +08001654/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001655int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001656{
1657 struct gsm_bts *bts = ts->trx->bts;
1658 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001659 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001660 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001661 uint8_t len = 2 + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001662
1663 if (bts->type == GSM_BTS_TYPE_BS11)
1664 len += 4 + 2 + 2 + 3;
1665
1666 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001667 if (verify_chan_comb(ts, chan_comb) < 0) {
1668 msgb_free(msg);
1669 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1670 return -EINVAL;
1671 }
1672 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001673
1674 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1675 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1676 NM_OC_CHANNEL, bts->bts_nr,
1677 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001678 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001679 if (ts->hopping.enabled) {
1680 unsigned int i;
1681 uint8_t *len;
1682
Harald Welte67104d12009-09-12 13:05:33 +02001683 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1684 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001685
1686 /* build the ARFCN list */
1687 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1688 len = msgb_put(msg, 1);
1689 *len = 0;
1690 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1691 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1692 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001693 /* At least BS-11 wants a TLV16 here */
1694 if (bts->type == GSM_BTS_TYPE_BS11)
1695 *len += 1;
1696 else
1697 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001698 }
1699 }
Harald Welte59b04682009-06-10 05:40:52 +08001700 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02001701 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001702 if (bts->type == GSM_BTS_TYPE_BS11)
1703 msgb_tlv_put(msg, 0x59, 1, &zero);
1704
1705 return abis_nm_sendmsg(bts, msg);
1706}
1707
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001708int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1709 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001710{
1711 struct abis_om_hdr *oh;
1712 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001713 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1714 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001715
1716 if (nack) {
1717 len += 2;
1718 msgtype = NM_MT_SW_ACT_REQ_NACK;
1719 }
1720
1721 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1722 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1723
1724 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001725 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001726 memcpy(ptr, attr, att_len);
1727 }
1728 if (nack)
1729 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1730
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001731 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001732}
1733
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001734int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001735{
1736 struct msgb *msg = nm_msgb_alloc();
1737 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001738 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001739
1740 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1741 fill_om_hdr(oh, len);
1742 data = msgb_put(msg, len);
1743 memcpy(data, rawmsg, len);
1744
1745 return abis_nm_sendmsg(bts, msg);
1746}
1747
1748/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001749static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001750{
1751 struct abis_om_hdr *oh;
1752 struct msgb *msg = nm_msgb_alloc();
1753
1754 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1755 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1756 0xff, 0xff, 0xff);
1757
1758 return abis_nm_sendmsg(bts, msg);
1759}
1760
1761/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001762int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
Harald Welte59b04682009-06-10 05:40:52 +08001763{
1764 struct abis_om_hdr *oh;
1765 struct msgb *msg = nm_msgb_alloc();
1766
Harald Welte59b04682009-06-10 05:40:52 +08001767 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1768 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1769
Harald Weltec61a90e2011-05-22 22:45:37 +02001770 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Welteb7284a92009-10-20 09:56:18 +02001771 DEBUGPC(DNM, "Sending OPSTART\n");
1772
Harald Welte59b04682009-06-10 05:40:52 +08001773 return abis_nm_sendmsg(bts, msg);
1774}
1775
1776/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001777int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1778 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001779{
1780 struct abis_om_hdr *oh;
1781 struct msgb *msg = nm_msgb_alloc();
1782
1783 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1784 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1785 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1786
1787 return abis_nm_sendmsg(bts, msg);
1788}
1789
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001790int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1791 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001792{
1793 struct abis_om_hdr *oh;
1794 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001795 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001796
1797 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1798 e1_port0, ts0, e1_port1, ts1);
1799
1800 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1801 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1802 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1803
1804 attr = msgb_put(msg, 3);
1805 attr[0] = NM_ATT_MDROP_LINK;
1806 attr[1] = e1_port0;
1807 attr[2] = ts0;
1808
1809 attr = msgb_put(msg, 3);
1810 attr[0] = NM_ATT_MDROP_NEXT;
1811 attr[1] = e1_port1;
1812 attr[2] = ts1;
1813
1814 return abis_nm_sendmsg(bts, msg);
1815}
Harald Welte59b04682009-06-10 05:40:52 +08001816
Harald Welte0bf8e302009-08-08 00:02:36 +02001817/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001818int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1819 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1820 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001821{
1822 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001823
Harald Weltec61a90e2011-05-22 22:45:37 +02001824 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001825
1826 if (!msg)
1827 msg = nm_msgb_alloc();
1828
1829 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1830 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1831 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1832 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001833 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001834
1835 return abis_nm_sendmsg(bts, msg);
1836}
1837
Harald Welte59b04682009-06-10 05:40:52 +08001838int abis_nm_event_reports(struct gsm_bts *bts, int on)
1839{
1840 if (on == 0)
1841 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1842 else
1843 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1844}
1845
1846/* Siemens (or BS-11) specific commands */
1847
1848int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1849{
1850 if (reconnect == 0)
1851 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1852 else
1853 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1854}
1855
1856int abis_nm_bs11_restart(struct gsm_bts *bts)
1857{
1858 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1859}
1860
1861
1862struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001863 uint16_t year;
1864 uint8_t month;
1865 uint8_t day;
1866 uint8_t hour;
1867 uint8_t min;
1868 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001869} __attribute__((packed));
1870
1871
1872void get_bs11_date_time(struct bs11_date_time *aet)
1873{
1874 time_t t;
1875 struct tm *tm;
1876
1877 t = time(NULL);
1878 tm = localtime(&t);
1879 aet->sec = tm->tm_sec;
1880 aet->min = tm->tm_min;
1881 aet->hour = tm->tm_hour;
1882 aet->day = tm->tm_mday;
1883 aet->month = tm->tm_mon;
1884 aet->year = htons(1900 + tm->tm_year);
1885}
1886
1887int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1888{
1889 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1890}
1891
1892int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1893{
1894 if (begin)
1895 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1896 else
1897 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1898}
1899
1900int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001901 enum abis_bs11_objtype type, uint8_t idx,
1902 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001903{
1904 struct abis_om_hdr *oh;
1905 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001906 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001907
1908 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1909 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1910 NM_OC_BS11, type, 0, idx);
1911 cur = msgb_put(msg, attr_len);
1912 memcpy(cur, attr, attr_len);
1913
1914 return abis_nm_sendmsg(bts, msg);
1915}
1916
1917int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001918 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001919{
1920 struct abis_om_hdr *oh;
1921 struct msgb *msg = nm_msgb_alloc();
1922
1923 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1924 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1925 NM_OC_BS11, type, 0, idx);
1926
1927 return abis_nm_sendmsg(bts, msg);
1928}
1929
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001930int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001931{
1932 struct abis_om_hdr *oh;
1933 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001934 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001935
1936 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1937 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1938 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1939 msgb_tlv_put(msg, 0x99, 1, &zero);
1940
1941 return abis_nm_sendmsg(bts, msg);
1942}
1943
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001944int abis_nm_bs11_create_bport(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();
1948
1949 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1950 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001951 idx, 0xff, 0xff);
1952
1953 return abis_nm_sendmsg(bts, msg);
1954}
1955
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001956int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001957{
1958 struct abis_om_hdr *oh;
1959 struct msgb *msg = nm_msgb_alloc();
1960
1961 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1962 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1963 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001964
1965 return abis_nm_sendmsg(bts, msg);
1966}
1967
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001968static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001969int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1970{
1971 struct abis_om_hdr *oh;
1972 struct msgb *msg = nm_msgb_alloc();
1973
1974 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1975 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1976 0xff, 0xff, 0xff);
1977 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1978
1979 return abis_nm_sendmsg(bts, msg);
1980}
1981
1982/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001983int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1984 uint8_t e1_timeslot, uint8_t e1_subslot,
1985 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001986{
1987 struct abis_om_hdr *oh;
1988 struct abis_nm_channel *ch;
1989 struct msgb *msg = nm_msgb_alloc();
1990
1991 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1992 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1993 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1994
1995 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1996 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1997 msgb_tv_put(msg, NM_ATT_TEI, tei);
1998
1999 return abis_nm_sendmsg(bts, msg);
2000}
2001
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002002int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08002003{
2004 struct abis_om_hdr *oh;
2005 struct msgb *msg = nm_msgb_alloc();
2006
2007 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2008 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2009 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2010 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2011
2012 return abis_nm_sendmsg(trx->bts, msg);
2013}
2014
2015int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2016{
2017 struct abis_om_hdr *oh;
2018 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002019 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08002020
2021 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2022 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2023 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2024 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2025
2026 return abis_nm_sendmsg(trx->bts, msg);
2027}
2028
2029int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2030{
2031 struct abis_om_hdr *oh;
2032 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002033 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
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_LI, 0x00, 0x00);
2038 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2039
2040 return abis_nm_sendmsg(bts, msg);
2041}
2042
2043int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2044{
2045 struct abis_om_hdr *oh;
2046 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002047 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08002048 NM_ATT_BS11_CCLK_TYPE };
2049
2050 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2051 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2052 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2053 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2054
2055 return abis_nm_sendmsg(bts, msg);
2056
2057}
2058
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002059//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002060
2061int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2062{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002063 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2064}
2065
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002066int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2067{
2068 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2069}
2070
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002071int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002072{
Harald Welte59b04682009-06-10 05:40:52 +08002073 struct abis_om_hdr *oh;
2074 struct msgb *msg = nm_msgb_alloc();
2075 struct bs11_date_time bdt;
2076
2077 get_bs11_date_time(&bdt);
2078
2079 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2080 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002081 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002082 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002083 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2084 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2085 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002086 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08002087 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002088 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002089 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002090 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002091 } else {
2092 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2093 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2094 }
2095
2096 return abis_nm_sendmsg(bts, msg);
2097}
2098
2099int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2100{
2101 struct abis_om_hdr *oh;
2102 struct msgb *msg;
2103
2104 if (strlen(password) != 10)
2105 return -EINVAL;
2106
2107 msg = nm_msgb_alloc();
2108 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2109 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2110 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002111 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002112
2113 return abis_nm_sendmsg(bts, msg);
2114}
2115
2116/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2117int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2118{
2119 struct abis_om_hdr *oh;
2120 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002121 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002122
2123 msg = nm_msgb_alloc();
2124 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2125 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2126 BS11_OBJ_LI, 0x00, 0x00);
2127
2128 if (locked)
2129 tlv_value = BS11_LI_PLL_LOCKED;
2130 else
2131 tlv_value = BS11_LI_PLL_STANDALONE;
2132
2133 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2134
2135 return abis_nm_sendmsg(bts, msg);
2136}
2137
Daniel Willmann10b07db2010-01-07 00:54:01 +01002138/* Set the calibration value of the PLL (work value/set value)
2139 * It depends on the login which one is changed */
2140int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2141{
2142 struct abis_om_hdr *oh;
2143 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002144 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002145
2146 msg = nm_msgb_alloc();
2147 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2148 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2149 BS11_OBJ_TRX1, 0x00, 0x00);
2150
2151 tlv_value[0] = value>>8;
2152 tlv_value[1] = value&0xff;
2153
2154 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2155
2156 return abis_nm_sendmsg(bts, msg);
2157}
2158
Harald Welte59b04682009-06-10 05:40:52 +08002159int abis_nm_bs11_get_state(struct gsm_bts *bts)
2160{
2161 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2162}
2163
2164/* BS11 SWL */
2165
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002166void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002167
Harald Welte59b04682009-06-10 05:40:52 +08002168struct abis_nm_bs11_sw {
2169 struct gsm_bts *bts;
2170 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002171 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002172 int forced;
2173 struct llist_head file_list;
2174 gsm_cbfn *user_cb; /* specified by the user */
2175};
2176static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2177
2178struct file_list_entry {
2179 struct llist_head list;
2180 char fname[PATH_MAX];
2181};
2182
2183struct file_list_entry *fl_dequeue(struct llist_head *queue)
2184{
2185 struct llist_head *lh;
2186
2187 if (llist_empty(queue))
2188 return NULL;
2189
2190 lh = queue->next;
2191 llist_del(lh);
2192
2193 return llist_entry(lh, struct file_list_entry, list);
2194}
2195
2196static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2197{
2198 char linebuf[255];
2199 struct llist_head *lh, *lh2;
2200 FILE *swl;
2201 int rc = 0;
2202
2203 swl = fopen(bs11_sw->swl_fname, "r");
2204 if (!swl)
2205 return -ENODEV;
2206
2207 /* zero the stale file list, if any */
2208 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2209 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002210 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002211 }
2212
2213 while (fgets(linebuf, sizeof(linebuf), swl)) {
2214 char file_id[12+1];
2215 char file_version[80+1];
2216 struct file_list_entry *fle;
2217 static char dir[PATH_MAX];
2218
2219 if (strlen(linebuf) < 4)
2220 continue;
2221
2222 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2223 if (rc < 0) {
2224 perror("ERR parsing SWL file");
2225 rc = -EINVAL;
2226 goto out;
2227 }
2228 if (rc < 2)
2229 continue;
2230
Harald Welte857e00d2009-06-26 20:25:23 +02002231 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002232 if (!fle) {
2233 rc = -ENOMEM;
2234 goto out;
2235 }
Harald Welte59b04682009-06-10 05:40:52 +08002236
2237 /* construct new filename */
2238 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2239 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2240 strcat(fle->fname, "/");
2241 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2242
2243 llist_add_tail(&fle->list, &bs11_sw->file_list);
2244 }
2245
2246out:
2247 fclose(swl);
2248 return rc;
2249}
2250
2251/* bs11 swload specific callback, passed to abis_nm core swload */
2252static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2253 struct msgb *msg, void *data, void *param)
2254{
2255 struct abis_nm_bs11_sw *bs11_sw = data;
2256 struct file_list_entry *fle;
2257 int rc = 0;
2258
2259 switch (event) {
2260 case NM_MT_LOAD_END_ACK:
2261 fle = fl_dequeue(&bs11_sw->file_list);
2262 if (fle) {
2263 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002264 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002265 bs11_sw->win_size,
2266 bs11_sw->forced,
2267 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002268 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002269 } else {
2270 /* activate the SWL */
2271 rc = abis_nm_software_activate(bs11_sw->bts,
2272 bs11_sw->swl_fname,
2273 bs11_swload_cbfn,
2274 bs11_sw);
2275 }
2276 break;
2277 case NM_MT_LOAD_SEG_ACK:
2278 case NM_MT_LOAD_END_NACK:
2279 case NM_MT_LOAD_INIT_ACK:
2280 case NM_MT_LOAD_INIT_NACK:
2281 case NM_MT_ACTIVATE_SW_NACK:
2282 case NM_MT_ACTIVATE_SW_ACK:
2283 default:
2284 /* fallthrough to the user callback */
2285 if (bs11_sw->user_cb)
2286 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2287 break;
2288 }
2289
2290 return rc;
2291}
2292
2293/* Siemens provides a SWL file that is a mere listing of all the other
2294 * files that are part of a software release. We need to upload first
2295 * the list file, and then each file that is listed in the list file */
2296int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002297 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002298{
2299 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2300 struct file_list_entry *fle;
2301 int rc = 0;
2302
2303 INIT_LLIST_HEAD(&bs11_sw->file_list);
2304 bs11_sw->bts = bts;
2305 bs11_sw->win_size = win_size;
2306 bs11_sw->user_cb = cbfn;
2307 bs11_sw->forced = forced;
2308
2309 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2310 rc = bs11_read_swl_file(bs11_sw);
2311 if (rc < 0)
2312 return rc;
2313
2314 /* dequeue next item in file list */
2315 fle = fl_dequeue(&bs11_sw->file_list);
2316 if (!fle)
2317 return -EINVAL;
2318
2319 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002320 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002321 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002322 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002323 return rc;
2324}
2325
2326#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002327static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002328 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2329 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2330 NM_ATT_BS11_LMT_USER_NAME,
2331
2332 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2333
2334 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2335
2336 NM_ATT_BS11_SW_LOAD_STORED };
2337
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002338static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002339 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2340 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2341 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2342 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2343#endif
2344
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002345static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002346 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2347 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2348 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2349
2350int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2351{
2352 struct abis_om_hdr *oh;
2353 struct msgb *msg = nm_msgb_alloc();
2354
2355 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2356 /* SiemensHW CCTRL object */
2357 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2358 0x03, 0x00, 0x00);
2359 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2360
2361 return abis_nm_sendmsg(bts, msg);
2362}
2363
2364int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2365{
2366 struct abis_om_hdr *oh;
2367 struct msgb *msg = nm_msgb_alloc();
2368 struct bs11_date_time aet;
2369
2370 get_bs11_date_time(&aet);
2371 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2372 /* SiemensHW CCTRL object */
2373 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2374 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002375 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002376
2377 return abis_nm_sendmsg(bts, msg);
2378}
2379
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002380int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002381{
2382 struct abis_om_hdr *oh;
2383 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002384 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002385
2386 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2387 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2388 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2389 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2390
2391 return abis_nm_sendmsg(bts, msg);
2392}
2393
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002394int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg)
Daniel Willmann5655afe2009-08-10 11:49:36 +02002395{
2396 struct abis_om_hdr *oh;
2397 struct msgb *msg = nm_msgb_alloc();
2398 struct bs11_date_time aet;
2399
2400 get_bs11_date_time(&aet);
2401 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2402 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2403 bport, 0xff, 0x02);
2404 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2405
2406 return abis_nm_sendmsg(bts, msg);
2407}
2408
Harald Welte59b04682009-06-10 05:40:52 +08002409/* ip.access nanoBTS specific commands */
2410static const char ipaccess_magic[] = "com.ipaccess";
2411
2412
2413static int abis_nm_rx_ipacc(struct msgb *msg)
2414{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002415 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002416 struct abis_om_hdr *oh = msgb_l2(msg);
2417 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002418 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002419 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002420 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002421
2422 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002423 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002424 return -EINVAL;
2425 }
2426
2427 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002428 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002429
Harald Weltec61a90e2011-05-22 22:45:37 +02002430 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002431
Harald Welte5aeedd42009-10-19 22:11:11 +02002432 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002433
2434 switch (foh->msg_type) {
2435 case NM_MT_IPACC_RSL_CONNECT_ACK:
2436 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002437 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2438 memcpy(&addr,
2439 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2440
2441 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2442 }
Harald Welte4206d982009-07-12 09:33:54 +02002443 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002444 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002445 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002446 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002447 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2448 DEBUGPC(DNM, "STREAM=0x%02x ",
2449 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002450 DEBUGPC(DNM, "\n");
2451 break;
2452 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002453 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002454 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002455 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002456 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002457 else
2458 DEBUGPC(DNM, "\n");
2459 break;
2460 case NM_MT_IPACC_SET_NVATTR_ACK:
2461 DEBUGPC(DNM, "SET NVATTR ACK\n");
2462 /* FIXME: decode and show the actual attributes */
2463 break;
2464 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002465 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002466 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002467 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002468 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002469 else
Harald Weltede4477a2009-12-24 12:20:20 +01002470 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002471 break;
Harald Welte21460f02009-07-03 11:26:45 +02002472 case NM_MT_IPACC_GET_NVATTR_ACK:
2473 DEBUGPC(DNM, "GET NVATTR ACK\n");
2474 /* FIXME: decode and show the actual attributes */
2475 break;
2476 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002477 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002478 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002479 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002480 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002481 else
Harald Weltede4477a2009-12-24 12:20:20 +01002482 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002483 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002484 case NM_MT_IPACC_SET_ATTR_ACK:
2485 DEBUGPC(DNM, "SET ATTR ACK\n");
2486 break;
2487 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002488 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002489 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002490 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002491 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002492 else
Harald Weltede4477a2009-12-24 12:20:20 +01002493 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002494 break;
Harald Welte59b04682009-06-10 05:40:52 +08002495 default:
2496 DEBUGPC(DNM, "unknown\n");
2497 break;
2498 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002499
2500 /* signal handling */
2501 switch (foh->msg_type) {
2502 case NM_MT_IPACC_RSL_CONNECT_NACK:
2503 case NM_MT_IPACC_SET_NVATTR_NACK:
2504 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002505 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002506 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002507 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002508 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002509 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002510 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002511 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002512 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002513 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002514 default:
2515 break;
2516 }
2517
Harald Welte59b04682009-06-10 05:40:52 +08002518 return 0;
2519}
2520
2521/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002522int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2523 uint8_t obj_class, uint8_t bts_nr,
2524 uint8_t trx_nr, uint8_t ts_nr,
2525 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002526{
2527 struct msgb *msg = nm_msgb_alloc();
2528 struct abis_om_hdr *oh;
2529 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002530 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002531
2532 /* construct the 12.21 OM header, observe the erroneous length */
2533 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2534 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2535 oh->mdisc = ABIS_OM_MDISC_MANUF;
2536
2537 /* add the ip.access magic */
2538 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2539 *data++ = sizeof(ipaccess_magic);
2540 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2541
2542 /* fill the 12.21 FOM header */
2543 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2544 foh->msg_type = msg_type;
2545 foh->obj_class = obj_class;
2546 foh->obj_inst.bts_nr = bts_nr;
2547 foh->obj_inst.trx_nr = trx_nr;
2548 foh->obj_inst.ts_nr = ts_nr;
2549
2550 if (attr && attr_len) {
2551 data = msgb_put(msg, attr_len);
2552 memcpy(data, attr, attr_len);
2553 }
2554
2555 return abis_nm_sendmsg(bts, msg);
2556}
2557
2558/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002559int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002560 int attr_len)
2561{
Harald Weltef12c1052010-01-07 20:39:42 +01002562 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2563 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002564 attr_len);
2565}
2566
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002567int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002568 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002569{
2570 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002571 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002572 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2573 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2574
2575 int attr_len = sizeof(attr);
2576
2577 ia.s_addr = htonl(ip);
2578 attr[1] = stream;
2579 attr[3] = port >> 8;
2580 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002581 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002582
2583 /* if ip == 0, we use the default IP */
2584 if (ip == 0)
2585 attr_len -= 5;
2586
2587 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002588 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002589
2590 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2591 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2592 trx->nr, 0xff, attr, attr_len);
2593}
2594
Harald Welte59b04682009-06-10 05:40:52 +08002595/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002596int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002597{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002598 struct abis_om_hdr *oh;
2599 struct msgb *msg = nm_msgb_alloc();
2600
2601 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2602 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2603 trx->bts->nr, trx->nr, 0xff);
2604
2605 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002606}
Harald Welte0dfc6232009-10-24 10:20:41 +02002607
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002608int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2609 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2610 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002611{
2612 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2613 obj_class, bts_nr, trx_nr, ts_nr,
2614 attr, attr_len);
2615}
Harald Weltebeeae412009-11-12 14:48:42 +01002616
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002617void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002618{
2619 /* we simply reuse the GSM48 function and overwrite the RAC
2620 * with the Cell ID */
2621 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002622 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002623}
2624
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002625void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2626{
2627 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2628
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01002629 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002630 if (!trx->bts || !trx->bts->oml_link)
2631 return;
2632
2633 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2634 trx->bts->bts_nr, trx->nr, 0xff,
2635 new_state);
2636}
2637
Harald Welte453141f2010-03-25 11:45:30 +08002638static const struct value_string ipacc_testres_names[] = {
2639 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2640 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2641 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2642 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2643 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2644 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002645};
2646
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002647const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002648{
Harald Welte453141f2010-03-25 11:45:30 +08002649 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002650}
2651
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002652void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002653{
2654 cid->mcc = (buf[0] & 0xf) * 100;
2655 cid->mcc += (buf[0] >> 4) * 10;
2656 cid->mcc += (buf[1] & 0xf) * 1;
2657
2658 if (buf[1] >> 4 == 0xf) {
2659 cid->mnc = (buf[2] & 0xf) * 10;
2660 cid->mnc += (buf[2] >> 4) * 1;
2661 } else {
2662 cid->mnc = (buf[2] & 0xf) * 100;
2663 cid->mnc += (buf[2] >> 4) * 10;
2664 cid->mnc += (buf[1] >> 4) * 1;
2665 }
2666
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002667 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2668 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002669}
2670
Harald Weltebeeae412009-11-12 14:48:42 +01002671/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002672int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002673{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002674 uint8_t *cur = buf;
2675 uint16_t len;
Harald Weltebeeae412009-11-12 14:48:42 +01002676
Harald Welteb784df82010-07-22 18:14:36 +02002677 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002678
2679 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2680 return -EINVAL;
2681 cur++;
2682
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002683 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002684 cur += 2;
2685
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002686 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002687 cur += 2;
2688
2689 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2690 binf->freq_qual = *cur >> 2;
2691
Harald Welteb784df82010-07-22 18:14:36 +02002692 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002693 binf->arfcn |= *cur++;
2694
2695 if (binf->info_type & IPAC_BINF_RXLEV)
2696 binf->rx_lev = *cur & 0x3f;
2697 cur++;
2698
2699 if (binf->info_type & IPAC_BINF_RXQUAL)
2700 binf->rx_qual = *cur & 0x7;
2701 cur++;
2702
2703 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002704 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002705 cur += 2;
2706
2707 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002708 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002709 cur += 2;
2710
2711 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002712 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002713 cur += 4;
2714
Harald Welte22cb81f2010-07-30 22:34:42 +02002715#if 0
2716 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002717 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002718#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002719 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002720 cur++;
2721
Harald Weltebfc21092009-11-13 11:56:05 +01002722 ipac_parse_cgi(&binf->cgi, cur);
2723 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002724
2725 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2726 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2727 cur += sizeof(binf->ba_list_si2);
2728 }
2729
2730 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2731 memcpy(binf->ba_list_si2bis, cur,
2732 sizeof(binf->ba_list_si2bis));
2733 cur += sizeof(binf->ba_list_si2bis);
2734 }
2735
2736 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2737 memcpy(binf->ba_list_si2ter, cur,
2738 sizeof(binf->ba_list_si2ter));
2739 cur += sizeof(binf->ba_list_si2ter);
2740 }
2741
2742 return 0;
2743}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002744
2745void abis_nm_clear_queue(struct gsm_bts *bts)
2746{
2747 struct msgb *msg;
2748
2749 while (!llist_empty(&bts->abis_queue)) {
2750 msg = msgb_dequeue(&bts->abis_queue);
2751 msgb_free(msg);
2752 }
2753
2754 bts->abis_nm_pend = 0;
2755}