blob: 027a2638b116a8e9baca25e20979c03a672d0007 [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>
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte59b04682009-06-10 05:40:52 +080047
48#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080051
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020052int 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 +080053{
Harald Welte59698fb2010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte59b04682009-06-10 05:40:52 +080057}
58
59static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
71#if 0
72/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
77#endif
78
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Weltec61a90e2011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte59b04682009-06-10 05:40:52 +080083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte59b04682009-06-10 05:40:52 +080089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte59b04682009-06-10 05:40:52 +080099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
103 fill_om_hdr(oh, len+sizeof(*foh));
104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
109}
110
111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte9cfc9352009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800115}
116
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200117int _abis_nm_sendmsg(struct msgb *msg, int to_trx_oml)
118{
119 struct e1inp_sign_link *sign_link = msg->dst;
120
121 msg->l2h = msg->data;
122
123 if (!msg->dst) {
124 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
125 return -EINVAL;
126 }
127
128 /* Check for TRX-specific OML link first */
129 if (to_trx_oml) {
130 if (!sign_link->trx->oml_link)
131 return -ENODEV;
132 msg->dst = sign_link->trx->oml_link;
133 }
134 return abis_sendmsg(msg);
135}
136
Harald Welte59b04682009-06-10 05:40:52 +0800137/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100138static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800139{
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200140 msg->dst = bts->oml_link;
Harald Welte59b04682009-06-10 05:40:52 +0800141
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100142 /* queue OML messages */
143 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
144 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Weltec5845042011-02-14 15:26:13 +0100145 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100146 } else {
147 msgb_enqueue(&bts->abis_queue, msg);
148 return 0;
149 }
150
151}
152
153int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
154{
155 OBSC_NM_W_ACK_CB(msg) = 1;
156 return abis_nm_queue_msg(bts, msg);
157}
158
159static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
160{
161 OBSC_NM_W_ACK_CB(msg) = 0;
162 return abis_nm_queue_msg(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800163}
164
165static int abis_nm_rcvmsg_sw(struct msgb *mb);
166
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100167int nm_is_running(struct gsm_nm_state *s) {
168 return (s->operational == NM_OPSTATE_ENABLED) && (
169 (s->availability == NM_AVSTATE_OK) ||
170 (s->availability == 0xff)
171 );
172}
173
Harald Welte59b04682009-06-10 05:40:52 +0800174/* Update the administrative state of a given object in our in-memory data
175 * structures and send an event to the higher layer */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200176static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
177 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Welte59b04682009-06-10 05:40:52 +0800178{
179 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100180 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800181
Harald Weltea348c082011-03-06 21:20:38 +0100182 memset(&nsd, 0, sizeof(nsd));
183
Harald Weltec6ed9282011-06-06 18:31:20 +0200184 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100185 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100186 return -EINVAL;
Harald Weltec6ed9282011-06-06 18:31:20 +0200187 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800188 if (!nm_state)
189 return -1;
190
191 new_state = *nm_state;
192 new_state.administrative = adm_state;
193
Harald Welteb03c4482011-03-06 22:11:32 +0100194 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100195 nsd.obj_class = obj_class;
196 nsd.old_state = nm_state;
197 nsd.new_state = &new_state;
198 nsd.obj_inst = obj_inst;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200199 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800200
201 nm_state->administrative = adm_state;
202
Harald Welte4c826f72011-01-14 15:55:42 +0100203 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800204}
205
206static int abis_nm_rx_statechg_rep(struct msgb *mb)
207{
208 struct abis_om_hdr *oh = msgb_l2(mb);
209 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200210 struct e1inp_sign_link *sign_link = mb->dst;
211 struct gsm_bts *bts = sign_link->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +0800212 struct tlv_parsed tp;
213 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800214
215 DEBUGPC(DNM, "STATE CHG: ");
216
217 memset(&new_state, 0, sizeof(new_state));
218
Harald Weltec6ed9282011-06-06 18:31:20 +0200219 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800220 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100221 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800222 return -EINVAL;
223 }
224
225 new_state = *nm_state;
226
Harald Welte59698fb2010-01-10 18:01:52 +0100227 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800228 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
229 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "OP_STATE=%s ",
231 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800232 }
233 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
234 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
235 new_state.availability = 0xff;
236 else
237 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Weltec61a90e2011-05-22 22:45:37 +0200238 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
239 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800240 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100241 } else
242 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800243 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
244 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200245 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200246 get_value_string(abis_nm_adm_state_names,
247 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800248 }
249 DEBUGPC(DNM, "\n");
250
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100251 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
252 new_state.operational != nm_state->operational ||
253 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800254 /* Update the operational state of a given object in our in-memory data
255 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100256 struct nm_statechg_signal_data nsd;
Harald Weltec6ed9282011-06-06 18:31:20 +0200257 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100258 nsd.obj_class = foh->obj_class;
259 nsd.old_state = nm_state;
260 nsd.new_state = &new_state;
261 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100262 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200263 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100264 nm_state->operational = new_state.operational;
265 nm_state->availability = new_state.availability;
266 if (nm_state->administrative == 0)
267 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800268 }
269#if 0
270 if (op_state == 1) {
271 /* try to enable objects that are disabled */
272 abis_nm_opstart(bts, foh->obj_class,
273 foh->obj_inst.bts_nr,
274 foh->obj_inst.trx_nr,
275 foh->obj_inst.ts_nr);
276 }
277#endif
278 return 0;
279}
280
281static int rx_fail_evt_rep(struct msgb *mb)
282{
283 struct abis_om_hdr *oh = msgb_l2(mb);
284 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200285 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800286 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100287 const uint8_t *p_val;
288 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800289
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200290 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800291
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200292 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800293
294 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Weltec61a90e2011-05-22 22:45:37 +0200295 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
296 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte59b04682009-06-10 05:40:52 +0800297 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Weltec61a90e2011-05-22 22:45:37 +0200298 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
299 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100300 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
301 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200302 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 +0100303 }
304 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
305 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
306 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
307 if (p_text) {
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200308 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100309 talloc_free(p_text);
310 }
311 }
Harald Welte59b04682009-06-10 05:40:52 +0800312
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200313 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800314
315 return 0;
316}
317
318static int abis_nm_rcvmsg_report(struct msgb *mb)
319{
320 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200321 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800322
Harald Weltec61a90e2011-05-22 22:45:37 +0200323 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800324
325 //nmh->cfg->report_cb(mb, foh);
326
327 switch (mt) {
328 case NM_MT_STATECHG_EVENT_REP:
329 return abis_nm_rx_statechg_rep(mb);
330 break;
331 case NM_MT_SW_ACTIVATED_REP:
332 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800334 break;
335 case NM_MT_FAILURE_EVENT_REP:
336 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200337 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800338 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200339 case NM_MT_TEST_REP:
340 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200341 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200342 break;
Harald Welte59b04682009-06-10 05:40:52 +0800343 default:
344 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
345 break;
346
347 };
348
349 return 0;
350}
351
352/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200353static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
354 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800355{
356 struct abis_om_hdr *oh;
357 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200358 uint8_t len = swdesc_len;
359 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800360
361 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
362 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
363
364 trailer = msgb_put(msg, swdesc_len);
365 memcpy(trailer, sw_desc, swdesc_len);
366
367 return abis_nm_sendmsg(bts, msg);
368}
369
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200370static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100371{
372 static const struct tlv_definition sw_descr_def = {
373 .def = {
374 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
375 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
376 },
377 };
378
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200379 uint8_t tag;
380 uint16_t tag_len;
381 const uint8_t *val;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100382 int ofs = 0, len;
383
384 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
385 * nested nature and the fact you have to assume it contains only two sub
386 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
387
388 if (sw_descr[0] != NM_ATT_SW_DESCR) {
389 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
390 return -1;
391 }
392 ofs += 1;
393
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
396 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
397 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
398 return -2;
399 }
400 ofs += len;
401
402 len = tlv_parse_one(&tag, &tag_len, &val,
403 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
404 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
405 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
406 return -3;
407 }
408 ofs += len;
409
410 return ofs;
411}
412
Harald Welte59b04682009-06-10 05:40:52 +0800413static int abis_nm_rx_sw_act_req(struct msgb *mb)
414{
415 struct abis_om_hdr *oh = msgb_l2(mb);
416 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200417 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200418 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200419 const uint8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100420 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800421
Harald Weltec61a90e2011-05-22 22:45:37 +0200422 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200423
424 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800425
Harald Welte3055e332010-03-14 15:37:43 +0800426 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800427
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200428 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800429 foh->obj_inst.bts_nr,
430 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800431 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800432 foh->data, oh->length-sizeof(*foh));
433
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200434 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200435 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
436 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
437 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
438 DEBUGP(DNM, "SW config not found! Can't continue.\n");
439 return -EINVAL;
440 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200441 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200442 }
443
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100444 /* Use the first SW_DESCR present in SW config */
445 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
446 if (sw_descr_len < 0)
447 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200448
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200449 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800450 foh->obj_inst.bts_nr,
451 foh->obj_inst.trx_nr,
452 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100453 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800454}
455
456/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
457static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
458{
459 struct abis_om_hdr *oh = msgb_l2(mb);
460 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200461 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800462 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200463 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800464
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200465 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800466 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
467 return -EINVAL;
468
469 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
470
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200471 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800472}
473
474static int abis_nm_rx_lmt_event(struct msgb *mb)
475{
476 struct abis_om_hdr *oh = msgb_l2(mb);
477 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200478 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800479 struct tlv_parsed tp;
480
481 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200482 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800483 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
484 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200485 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800486 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
487 }
488 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
489 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200490 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800491 DEBUGPC(DNM, "Level=%u ", level);
492 }
493 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
494 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
495 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
496 DEBUGPC(DNM, "Username=%s ", name);
497 }
498 DEBUGPC(DNM, "\n");
499 /* FIXME: parse LMT LOGON TIME */
500 return 0;
501}
502
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200503void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100504{
505 int wait = 0;
506 struct msgb *msg;
507 /* the queue is empty */
508 while (!llist_empty(&bts->abis_queue)) {
509 msg = msgb_dequeue(&bts->abis_queue);
510 wait = OBSC_NM_W_ACK_CB(msg);
Harald Weltec5845042011-02-14 15:26:13 +0100511 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100512
513 if (wait)
514 break;
515 }
516
517 bts->abis_nm_pend = wait;
518}
519
Harald Welte59b04682009-06-10 05:40:52 +0800520/* Receive a OML NM Message from BTS */
521static int abis_nm_rcvmsg_fom(struct msgb *mb)
522{
523 struct abis_om_hdr *oh = msgb_l2(mb);
524 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200525 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200526 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100527 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800528
529 /* check for unsolicited message */
530 if (is_report(mt))
531 return abis_nm_rcvmsg_report(mb);
532
Harald Weltec61a90e2011-05-22 22:45:37 +0200533 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800534 return abis_nm_rcvmsg_sw(mb);
535
Harald Weltec61a90e2011-05-22 22:45:37 +0200536 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800537 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800538 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200539
Harald Weltec61a90e2011-05-22 22:45:37 +0200540 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200541
Harald Weltec61a90e2011-05-22 22:45:37 +0200542 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800543
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200544 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800545 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200546 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200547 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800548 else
549 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200550
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800551 nack_data.msg = mb;
552 nack_data.mt = mt;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200553 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200554 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200555 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800556 }
557#if 0
558 /* check if last message is to be acked */
559 if (is_ack_nack(nmh->last_msgtype)) {
560 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100561 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800562 /* we got our ACK, continue sending the next msg */
563 } else if (mt == MT_NACK(nmh->last_msgtype)) {
564 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100565 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800566 /* FIXME: somehow signal this to the caller */
567 } else {
568 /* really strange things happen */
569 return -EINVAL;
570 }
571 }
572#endif
573
574 switch (mt) {
575 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100576 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800577 break;
578 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100579 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800580 break;
581 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100582 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800583 break;
Harald Welte204317e2009-08-06 17:58:31 +0200584 case NM_MT_CONN_MDROP_LINK_ACK:
585 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
586 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100587 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200588 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100589 break;
590 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200591 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100592 break;
Harald Welte08011e22011-03-04 13:41:31 +0100593 case NM_MT_SET_BTS_ATTR_ACK:
594 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200595 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
596 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Welte08011e22011-03-04 13:41:31 +0100597 }
598 break;
Harald Welte59b04682009-06-10 05:40:52 +0800599 }
600
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200601 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100602 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800603}
604
605static int abis_nm_rx_ipacc(struct msgb *mb);
606
607static int abis_nm_rcvmsg_manuf(struct msgb *mb)
608{
609 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200610 struct e1inp_sign_link *sign_link = mb->dst;
611 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800612
613 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100614 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +0800615 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200616 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800617 break;
618 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100619 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
620 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800621 rc = 0;
622 break;
623 }
624
625 return rc;
626}
627
628/* High-Level API */
629/* Entry-point where L2 OML from BTS enters the NM code */
630int abis_nm_rcvmsg(struct msgb *msg)
631{
632 struct abis_om_hdr *oh = msgb_l2(msg);
633 int rc = 0;
634
635 /* Various consistency checks */
636 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100637 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800638 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +0200639 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
640 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800641 }
642 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100643 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800644 oh->sequence);
645 return -EINVAL;
646 }
647#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200648 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800649 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
650 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100651 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800652 oh->length + sizeof(*oh), l2_len);
653 return -EINVAL;
654 }
655 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100656 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 +0800657#endif
658 msg->l3h = (unsigned char *)oh + sizeof(*oh);
659
660 switch (oh->mdisc) {
661 case ABIS_OM_MDISC_FOM:
662 rc = abis_nm_rcvmsg_fom(msg);
663 break;
664 case ABIS_OM_MDISC_MANUF:
665 rc = abis_nm_rcvmsg_manuf(msg);
666 break;
667 case ABIS_OM_MDISC_MMI:
668 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100669 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800670 oh->mdisc);
671 break;
672 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100673 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800674 oh->mdisc);
675 return -EINVAL;
676 }
677
678 msgb_free(msg);
679 return rc;
680}
681
682#if 0
683/* initialized all resources */
684struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
685{
686 struct abis_nm_h *nmh;
687
688 nmh = malloc(sizeof(*nmh));
689 if (!nmh)
690 return NULL;
691
692 nmh->cfg = cfg;
693
694 return nmh;
695}
696
697/* free all resources */
698void abis_nm_fini(struct abis_nm_h *nmh)
699{
700 free(nmh);
701}
702#endif
703
704/* Here we are trying to define a high-level API that can be used by
705 * the actual BSC implementation. However, the architecture is currently
706 * still under design. Ideally the calls to this API would be synchronous,
707 * while the underlying stack behind the APi runs in a traditional select
708 * based state machine.
709 */
710
711/* 6.2 Software Load: */
712enum sw_state {
713 SW_STATE_NONE,
714 SW_STATE_WAIT_INITACK,
715 SW_STATE_WAIT_SEGACK,
716 SW_STATE_WAIT_ENDACK,
717 SW_STATE_WAIT_ACTACK,
718 SW_STATE_ERROR,
719};
720
721struct abis_nm_sw {
722 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800723 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800724 gsm_cbfn *cbfn;
725 void *cb_data;
726 int forced;
727
728 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200729 uint8_t obj_class;
730 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800731
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200732 uint8_t file_id[255];
733 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800734
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200735 uint8_t file_version[255];
736 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800737
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200738 uint8_t window_size;
739 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800740
741 int fd;
742 FILE *stream;
743 enum sw_state state;
744 int last_seg;
745};
746
747static struct abis_nm_sw g_sw;
748
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100749static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
750{
751 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
752 msgb_v_put(msg, NM_ATT_SW_DESCR);
753 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
754 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
755 sw->file_version);
756 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
757 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
758 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
759 sw->file_version);
760 } else {
761 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
762 }
763}
764
Harald Welte59b04682009-06-10 05:40:52 +0800765/* 6.2.1 / 8.3.1: Load Data Initiate */
766static int sw_load_init(struct abis_nm_sw *sw)
767{
768 struct abis_om_hdr *oh;
769 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200770 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800771
772 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
773 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
774 sw->obj_instance[0], sw->obj_instance[1],
775 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100776
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100777 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800778 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
779
780 return abis_nm_sendmsg(sw->bts, msg);
781}
782
783static int is_last_line(FILE *stream)
784{
785 char next_seg_buf[256];
786 long pos;
787
788 /* check if we're sending the last line */
789 pos = ftell(stream);
790 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
791 fseek(stream, pos, SEEK_SET);
792 return 1;
793 }
794
795 fseek(stream, pos, SEEK_SET);
796 return 0;
797}
798
799/* 6.2.2 / 8.3.2 Load Data Segment */
800static int sw_load_segment(struct abis_nm_sw *sw)
801{
802 struct abis_om_hdr *oh;
803 struct msgb *msg = nm_msgb_alloc();
804 char seg_buf[256];
805 char *line_buf = seg_buf+2;
806 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +0200807 int len;
Harald Welte59b04682009-06-10 05:40:52 +0800808
809 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
810
811 switch (sw->bts->type) {
812 case GSM_BTS_TYPE_BS11:
813 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
814 perror("fgets reading segment");
815 return -EINVAL;
816 }
817 seg_buf[0] = 0x00;
818
819 /* check if we're sending the last line */
820 sw->last_seg = is_last_line(sw->stream);
821 if (sw->last_seg)
822 seg_buf[1] = 0;
823 else
824 seg_buf[1] = 1 + sw->seg_in_window++;
825
826 len = strlen(line_buf) + 2;
827 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200828 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800829 /* BS11 wants CR + LF in excess of the TLV length !?! */
830 tlv[1] -= 2;
831
832 /* we only now know the exact length for the OM hdr */
833 len = strlen(line_buf)+2;
834 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100835 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200836 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100837 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
838 if (len < 0) {
839 perror("read failed");
840 return -EINVAL;
841 }
842
843 if (len != IPACC_SEGMENT_SIZE)
844 sw->last_seg = 1;
845
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100846 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200847 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100848 len += 3;
849 break;
850 }
Harald Welte59b04682009-06-10 05:40:52 +0800851 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100852 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800853 /* FIXME: Other BTS types */
854 return -1;
855 }
856
857 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
858 sw->obj_instance[0], sw->obj_instance[1],
859 sw->obj_instance[2]);
860
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100861 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800862}
863
864/* 6.2.4 / 8.3.4 Load Data End */
865static int sw_load_end(struct abis_nm_sw *sw)
866{
867 struct abis_om_hdr *oh;
868 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200869 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800870
871 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
872 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
873 sw->obj_instance[0], sw->obj_instance[1],
874 sw->obj_instance[2]);
875
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100876 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800877 return abis_nm_sendmsg(sw->bts, msg);
878}
879
880/* Activate the specified software into the BTS */
881static int sw_activate(struct abis_nm_sw *sw)
882{
883 struct abis_om_hdr *oh;
884 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200885 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800886
887 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
888 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
889 sw->obj_instance[0], sw->obj_instance[1],
890 sw->obj_instance[2]);
891
892 /* FIXME: this is BS11 specific format */
893 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
894 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
895 sw->file_version);
896
897 return abis_nm_sendmsg(sw->bts, msg);
898}
899
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100900struct sdp_firmware {
901 char magic[4];
902 char more_magic[4];
903 unsigned int header_length;
904 unsigned int file_length;
905} __attribute__ ((packed));
906
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100907static int parse_sdp_header(struct abis_nm_sw *sw)
908{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100909 struct sdp_firmware firmware_header;
910 int rc;
911 struct stat stat;
912
913 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
914 if (rc != sizeof(firmware_header)) {
915 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
916 return -1;
917 }
918
919 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
920 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
921 return -1;
922 }
923
924 if (firmware_header.more_magic[0] != 0x10 ||
925 firmware_header.more_magic[1] != 0x02 ||
926 firmware_header.more_magic[2] != 0x00 ||
927 firmware_header.more_magic[3] != 0x00) {
928 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
929 return -1;
930 }
931
932
933 if (fstat(sw->fd, &stat) == -1) {
934 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
935 return -1;
936 }
937
938 if (ntohl(firmware_header.file_length) != stat.st_size) {
939 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
940 return -1;
941 }
942
943 /* go back to the start as we checked the whole filesize.. */
944 lseek(sw->fd, 0l, SEEK_SET);
945 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
946 "There might be checksums in the file that are not\n"
947 "verified and incomplete firmware might be flashed.\n"
948 "There is absolutely no WARRANTY that flashing will\n"
949 "work.\n");
950 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100951}
952
Harald Welte59b04682009-06-10 05:40:52 +0800953static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
954{
955 char file_id[12+1];
956 char file_version[80+1];
957 int rc;
958
959 sw->fd = open(fname, O_RDONLY);
960 if (sw->fd < 0)
961 return sw->fd;
962
963 switch (sw->bts->type) {
964 case GSM_BTS_TYPE_BS11:
965 sw->stream = fdopen(sw->fd, "r");
966 if (!sw->stream) {
967 perror("fdopen");
968 return -1;
969 }
970 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200971 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +0800972 file_id, file_version);
973 if (rc != 2) {
974 perror("parsing header line of software file");
975 return -1;
976 }
977 strcpy((char *)sw->file_id, file_id);
978 sw->file_id_len = strlen(file_id);
979 strcpy((char *)sw->file_version, file_version);
980 sw->file_version_len = strlen(file_version);
981 /* rewind to start of file */
982 rewind(sw->stream);
983 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100984 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100985 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100986 rc = parse_sdp_header(sw);
987 if (rc < 0) {
988 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
989 return -1;
990 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100991
992 strcpy((char *)sw->file_id, "id");
993 sw->file_id_len = 3;
994 strcpy((char *)sw->file_version, "version");
995 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100996 break;
Harald Welte59b04682009-06-10 05:40:52 +0800997 default:
998 /* We don't know how to treat them yet */
999 close(sw->fd);
1000 return -EINVAL;
1001 }
1002
1003 return 0;
1004}
1005
1006static void sw_close_file(struct abis_nm_sw *sw)
1007{
1008 switch (sw->bts->type) {
1009 case GSM_BTS_TYPE_BS11:
1010 fclose(sw->stream);
1011 break;
1012 default:
1013 close(sw->fd);
1014 break;
1015 }
1016}
1017
1018/* Fill the window */
1019static int sw_fill_window(struct abis_nm_sw *sw)
1020{
1021 int rc;
1022
1023 while (sw->seg_in_window < sw->window_size) {
1024 rc = sw_load_segment(sw);
1025 if (rc < 0)
1026 return rc;
1027 if (sw->last_seg)
1028 break;
1029 }
1030 return 0;
1031}
1032
1033/* callback function from abis_nm_rcvmsg() handler */
1034static int abis_nm_rcvmsg_sw(struct msgb *mb)
1035{
1036 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001037 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001038 int rc = -1;
1039 struct abis_nm_sw *sw = &g_sw;
1040 enum sw_state old_state = sw->state;
1041
1042 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1043
1044 switch (sw->state) {
1045 case SW_STATE_WAIT_INITACK:
1046 switch (foh->msg_type) {
1047 case NM_MT_LOAD_INIT_ACK:
1048 /* fill window with segments */
1049 if (sw->cbfn)
1050 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1051 NM_MT_LOAD_INIT_ACK, mb,
1052 sw->cb_data, NULL);
1053 rc = sw_fill_window(sw);
1054 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001055 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001056 break;
1057 case NM_MT_LOAD_INIT_NACK:
1058 if (sw->forced) {
1059 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1060 "Init NACK\n");
1061 if (sw->cbfn)
1062 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1063 NM_MT_LOAD_INIT_ACK, mb,
1064 sw->cb_data, NULL);
1065 rc = sw_fill_window(sw);
1066 sw->state = SW_STATE_WAIT_SEGACK;
1067 } else {
1068 DEBUGP(DNM, "Software Load Init NACK\n");
1069 /* FIXME: cause */
1070 if (sw->cbfn)
1071 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1072 NM_MT_LOAD_INIT_NACK, mb,
1073 sw->cb_data, NULL);
1074 sw->state = SW_STATE_ERROR;
1075 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001076 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001077 break;
1078 }
1079 break;
1080 case SW_STATE_WAIT_SEGACK:
1081 switch (foh->msg_type) {
1082 case NM_MT_LOAD_SEG_ACK:
1083 if (sw->cbfn)
1084 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1085 NM_MT_LOAD_SEG_ACK, mb,
1086 sw->cb_data, NULL);
1087 sw->seg_in_window = 0;
1088 if (!sw->last_seg) {
1089 /* fill window with more segments */
1090 rc = sw_fill_window(sw);
1091 sw->state = SW_STATE_WAIT_SEGACK;
1092 } else {
1093 /* end the transfer */
1094 sw->state = SW_STATE_WAIT_ENDACK;
1095 rc = sw_load_end(sw);
1096 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001097 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001098 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001099 case NM_MT_LOAD_ABORT:
1100 if (sw->cbfn)
1101 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1102 NM_MT_LOAD_ABORT, mb,
1103 sw->cb_data, NULL);
1104 break;
Harald Welte59b04682009-06-10 05:40:52 +08001105 }
1106 break;
1107 case SW_STATE_WAIT_ENDACK:
1108 switch (foh->msg_type) {
1109 case NM_MT_LOAD_END_ACK:
1110 sw_close_file(sw);
1111 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1112 sw->bts->nr);
1113 sw->state = SW_STATE_NONE;
1114 if (sw->cbfn)
1115 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1116 NM_MT_LOAD_END_ACK, mb,
1117 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001118 rc = 0;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001119 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001120 break;
1121 case NM_MT_LOAD_END_NACK:
1122 if (sw->forced) {
1123 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1124 "End NACK\n");
1125 sw->state = SW_STATE_NONE;
1126 if (sw->cbfn)
1127 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1128 NM_MT_LOAD_END_ACK, mb,
1129 sw->cb_data, NULL);
1130 } else {
1131 DEBUGP(DNM, "Software Load End NACK\n");
1132 /* FIXME: cause */
1133 sw->state = SW_STATE_ERROR;
1134 if (sw->cbfn)
1135 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1136 NM_MT_LOAD_END_NACK, mb,
1137 sw->cb_data, NULL);
1138 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001139 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001140 break;
1141 }
1142 case SW_STATE_WAIT_ACTACK:
1143 switch (foh->msg_type) {
1144 case NM_MT_ACTIVATE_SW_ACK:
1145 /* we're done */
1146 DEBUGP(DNM, "Activate Software DONE!\n");
1147 sw->state = SW_STATE_NONE;
1148 rc = 0;
1149 if (sw->cbfn)
1150 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1151 NM_MT_ACTIVATE_SW_ACK, mb,
1152 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001153 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001154 break;
1155 case NM_MT_ACTIVATE_SW_NACK:
1156 DEBUGP(DNM, "Activate Software NACK\n");
1157 /* FIXME: cause */
1158 sw->state = SW_STATE_ERROR;
1159 if (sw->cbfn)
1160 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1161 NM_MT_ACTIVATE_SW_NACK, mb,
1162 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001163 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001164 break;
1165 }
1166 case SW_STATE_NONE:
1167 switch (foh->msg_type) {
1168 case NM_MT_ACTIVATE_SW_ACK:
1169 rc = 0;
1170 break;
1171 }
1172 break;
1173 case SW_STATE_ERROR:
1174 break;
1175 }
1176
1177 if (rc)
1178 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1179 foh->msg_type, old_state, sw->state);
1180
1181 return rc;
1182}
1183
1184/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001185int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001186 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001187 gsm_cbfn *cbfn, void *cb_data)
1188{
1189 struct abis_nm_sw *sw = &g_sw;
1190 int rc;
1191
1192 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1193 bts->nr, fname);
1194
1195 if (sw->state != SW_STATE_NONE)
1196 return -EBUSY;
1197
1198 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001199 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001200
1201 switch (bts->type) {
1202 case GSM_BTS_TYPE_BS11:
1203 sw->obj_class = NM_OC_SITE_MANAGER;
1204 sw->obj_instance[0] = 0xff;
1205 sw->obj_instance[1] = 0xff;
1206 sw->obj_instance[2] = 0xff;
1207 break;
1208 case GSM_BTS_TYPE_NANOBTS:
1209 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001210 sw->obj_instance[0] = sw->bts->nr;
1211 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001212 sw->obj_instance[2] = 0xff;
1213 break;
1214 case GSM_BTS_TYPE_UNKNOWN:
1215 default:
1216 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1217 return -1;
1218 break;
1219 }
Harald Welte59b04682009-06-10 05:40:52 +08001220 sw->window_size = win_size;
1221 sw->state = SW_STATE_WAIT_INITACK;
1222 sw->cbfn = cbfn;
1223 sw->cb_data = cb_data;
1224 sw->forced = forced;
1225
1226 rc = sw_open_file(sw, fname);
1227 if (rc < 0) {
1228 sw->state = SW_STATE_NONE;
1229 return rc;
1230 }
1231
1232 return sw_load_init(sw);
1233}
1234
1235int abis_nm_software_load_status(struct gsm_bts *bts)
1236{
1237 struct abis_nm_sw *sw = &g_sw;
1238 struct stat st;
1239 int rc, percent;
1240
1241 rc = fstat(sw->fd, &st);
1242 if (rc < 0) {
1243 perror("ERROR during stat");
1244 return rc;
1245 }
1246
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001247 if (sw->stream)
1248 percent = (ftell(sw->stream) * 100) / st.st_size;
1249 else
1250 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001251 return percent;
1252}
1253
1254/* Activate the specified software into the BTS */
1255int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1256 gsm_cbfn *cbfn, void *cb_data)
1257{
1258 struct abis_nm_sw *sw = &g_sw;
1259 int rc;
1260
1261 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1262 bts->nr, fname);
1263
1264 if (sw->state != SW_STATE_NONE)
1265 return -EBUSY;
1266
1267 sw->bts = bts;
1268 sw->obj_class = NM_OC_SITE_MANAGER;
1269 sw->obj_instance[0] = 0xff;
1270 sw->obj_instance[1] = 0xff;
1271 sw->obj_instance[2] = 0xff;
1272 sw->state = SW_STATE_WAIT_ACTACK;
1273 sw->cbfn = cbfn;
1274 sw->cb_data = cb_data;
1275
1276 /* Open the file in order to fill some sw struct members */
1277 rc = sw_open_file(sw, fname);
1278 if (rc < 0) {
1279 sw->state = SW_STATE_NONE;
1280 return rc;
1281 }
1282 sw_close_file(sw);
1283
1284 return sw_activate(sw);
1285}
1286
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001287static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1288 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001289{
1290 ch->attrib = NM_ATT_ABIS_CHANNEL;
1291 ch->bts_port = bts_port;
1292 ch->timeslot = ts_nr;
1293 ch->subslot = subslot_nr;
1294}
1295
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001296int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1297 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1298 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001299{
1300 struct abis_om_hdr *oh;
1301 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001302 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001303 struct msgb *msg = nm_msgb_alloc();
1304
1305 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1306 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1307 bts->bts_nr, trx_nr, 0xff);
1308
1309 msgb_tv_put(msg, NM_ATT_TEI, tei);
1310
1311 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1312 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1313
1314 return abis_nm_sendmsg(bts, msg);
1315}
1316
1317/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1318int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001319 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001320{
1321 struct gsm_bts *bts = trx->bts;
1322 struct abis_om_hdr *oh;
1323 struct abis_nm_channel *ch;
1324 struct msgb *msg = nm_msgb_alloc();
1325
1326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1327 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1328 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1329
1330 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1331 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1332
1333 return abis_nm_sendmsg(bts, msg);
1334}
1335
1336#if 0
1337int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1338 struct abis_nm_abis_channel *chan)
1339{
1340}
1341#endif
1342
1343int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001344 uint8_t e1_port, uint8_t e1_timeslot,
1345 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001346{
1347 struct gsm_bts *bts = ts->trx->bts;
1348 struct abis_om_hdr *oh;
1349 struct abis_nm_channel *ch;
1350 struct msgb *msg = nm_msgb_alloc();
1351
1352 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1353 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1354 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1355
1356 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1357 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1358
1359 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1360 gsm_ts_name(ts),
1361 e1_port, e1_timeslot, e1_subslot);
1362
1363 return abis_nm_sendmsg(bts, msg);
1364}
1365
1366#if 0
1367int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1368 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001369 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001370{
1371}
1372#endif
1373
1374/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001375int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001376{
1377 struct abis_om_hdr *oh;
1378 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001379 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001380
1381 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1382
1383 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1384 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1385 cur = msgb_put(msg, attr_len);
1386 memcpy(cur, attr, attr_len);
1387
1388 return abis_nm_sendmsg(bts, msg);
1389}
1390
1391/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001392int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001393{
1394 struct abis_om_hdr *oh;
1395 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001396 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001397
1398 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1399
1400 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1401 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1402 trx->bts->bts_nr, trx->nr, 0xff);
1403 cur = msgb_put(msg, attr_len);
1404 memcpy(cur, attr, attr_len);
1405
1406 return abis_nm_sendmsg(trx->bts, msg);
1407}
1408
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001409static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Weltef2eb2782009-08-09 21:49:48 +02001410{
1411 int i;
1412
1413 /* As it turns out, the BS-11 has some very peculiar restrictions
1414 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301415 switch (ts->trx->bts->type) {
1416 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001417 switch (chan_comb) {
1418 case NM_CHANC_TCHHalf:
1419 case NM_CHANC_TCHHalf2:
1420 /* not supported */
1421 return -EINVAL;
1422 case NM_CHANC_SDCCH:
1423 /* only one SDCCH/8 per TRX */
1424 for (i = 0; i < TRX_NR_TS; i++) {
1425 if (i == ts->nr)
1426 continue;
1427 if (ts->trx->ts[i].nm_chan_comb ==
1428 NM_CHANC_SDCCH)
1429 return -EINVAL;
1430 }
1431 /* not allowed for TS0 of BCCH-TRX */
1432 if (ts->trx == ts->trx->bts->c0 &&
1433 ts->nr == 0)
1434 return -EINVAL;
1435 /* not on the same TRX that has a BCCH+SDCCH4
1436 * combination */
1437 if (ts->trx == ts->trx->bts->c0 &&
1438 (ts->trx->ts[0].nm_chan_comb == 5 ||
1439 ts->trx->ts[0].nm_chan_comb == 8))
1440 return -EINVAL;
1441 break;
1442 case NM_CHANC_mainBCCH:
1443 case NM_CHANC_BCCHComb:
1444 /* allowed only for TS0 of C0 */
1445 if (ts->trx != ts->trx->bts->c0 ||
1446 ts->nr != 0)
1447 return -EINVAL;
1448 break;
1449 case NM_CHANC_BCCH:
1450 /* allowed only for TS 2/4/6 of C0 */
1451 if (ts->trx != ts->trx->bts->c0)
1452 return -EINVAL;
1453 if (ts->nr != 2 && ts->nr != 4 &&
1454 ts->nr != 6)
1455 return -EINVAL;
1456 break;
1457 case 8: /* this is not like 08.58, but in fact
1458 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1459 /* FIXME: only one CBCH allowed per cell */
1460 break;
1461 }
Harald Welte76ba8812009-12-02 02:45:23 +05301462 break;
1463 case GSM_BTS_TYPE_NANOBTS:
1464 switch (ts->nr) {
1465 case 0:
1466 if (ts->trx->nr == 0) {
1467 /* only on TRX0 */
1468 switch (chan_comb) {
1469 case NM_CHANC_BCCH:
1470 case NM_CHANC_mainBCCH:
1471 case NM_CHANC_BCCHComb:
1472 return 0;
1473 break;
1474 default:
1475 return -EINVAL;
1476 }
1477 } else {
1478 switch (chan_comb) {
1479 case NM_CHANC_TCHFull:
1480 case NM_CHANC_TCHHalf:
1481 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1482 return 0;
1483 default:
1484 return -EINVAL;
1485 }
1486 }
1487 break;
1488 case 1:
1489 if (ts->trx->nr == 0) {
1490 switch (chan_comb) {
1491 case NM_CHANC_SDCCH_CBCH:
1492 if (ts->trx->ts[0].nm_chan_comb ==
1493 NM_CHANC_mainBCCH)
1494 return 0;
1495 return -EINVAL;
1496 case NM_CHANC_SDCCH:
1497 case NM_CHANC_TCHFull:
1498 case NM_CHANC_TCHHalf:
1499 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1500 case NM_CHANC_IPAC_TCHFull_PDCH:
1501 return 0;
1502 }
1503 } else {
1504 switch (chan_comb) {
1505 case NM_CHANC_SDCCH:
1506 case NM_CHANC_TCHFull:
1507 case NM_CHANC_TCHHalf:
1508 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1509 return 0;
1510 default:
1511 return -EINVAL;
1512 }
1513 }
1514 break;
1515 case 2:
1516 case 3:
1517 case 4:
1518 case 5:
1519 case 6:
1520 case 7:
1521 switch (chan_comb) {
1522 case NM_CHANC_TCHFull:
1523 case NM_CHANC_TCHHalf:
1524 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1525 return 0;
1526 case NM_CHANC_IPAC_PDCH:
1527 case NM_CHANC_IPAC_TCHFull_PDCH:
1528 if (ts->trx->nr == 0)
1529 return 0;
1530 else
1531 return -EINVAL;
1532 }
1533 break;
1534 }
1535 return -EINVAL;
1536 default:
1537 /* unknown BTS type */
1538 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001539 }
1540 return 0;
1541}
1542
Harald Welte59b04682009-06-10 05:40:52 +08001543/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001544int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001545{
1546 struct gsm_bts *bts = ts->trx->bts;
1547 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001548 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001549 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001550 uint8_t len = 2 + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001551
1552 if (bts->type == GSM_BTS_TYPE_BS11)
1553 len += 4 + 2 + 2 + 3;
1554
1555 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001556 if (verify_chan_comb(ts, chan_comb) < 0) {
1557 msgb_free(msg);
1558 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1559 return -EINVAL;
1560 }
1561 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001562
1563 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1564 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1565 NM_OC_CHANNEL, bts->bts_nr,
1566 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001567 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001568 if (ts->hopping.enabled) {
1569 unsigned int i;
1570 uint8_t *len;
1571
Harald Welte67104d12009-09-12 13:05:33 +02001572 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1573 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001574
1575 /* build the ARFCN list */
1576 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1577 len = msgb_put(msg, 1);
1578 *len = 0;
1579 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1580 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1581 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001582 /* At least BS-11 wants a TLV16 here */
1583 if (bts->type == GSM_BTS_TYPE_BS11)
1584 *len += 1;
1585 else
1586 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001587 }
1588 }
Harald Welte59b04682009-06-10 05:40:52 +08001589 }
Harald Welte85771a42011-05-30 12:09:13 +02001590 if (ts->tsc == -1)
1591 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1592 else
1593 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001594 if (bts->type == GSM_BTS_TYPE_BS11)
1595 msgb_tlv_put(msg, 0x59, 1, &zero);
1596
1597 return abis_nm_sendmsg(bts, msg);
1598}
1599
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001600int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1601 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001602{
1603 struct abis_om_hdr *oh;
1604 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001605 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1606 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001607
1608 if (nack) {
1609 len += 2;
1610 msgtype = NM_MT_SW_ACT_REQ_NACK;
1611 }
1612
1613 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1614 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1615
1616 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001617 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001618 memcpy(ptr, attr, att_len);
1619 }
1620 if (nack)
1621 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1622
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001623 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001624}
1625
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001626int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001627{
1628 struct msgb *msg = nm_msgb_alloc();
1629 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001630 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001631
1632 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1633 fill_om_hdr(oh, len);
1634 data = msgb_put(msg, len);
1635 memcpy(data, rawmsg, len);
1636
1637 return abis_nm_sendmsg(bts, msg);
1638}
1639
1640/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001641static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001642{
1643 struct abis_om_hdr *oh;
1644 struct msgb *msg = nm_msgb_alloc();
1645
1646 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1647 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1648 0xff, 0xff, 0xff);
1649
1650 return abis_nm_sendmsg(bts, msg);
1651}
1652
1653/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001654int 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 +08001655{
1656 struct abis_om_hdr *oh;
1657 struct msgb *msg = nm_msgb_alloc();
1658
Harald Welte59b04682009-06-10 05:40:52 +08001659 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1660 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1661
Harald Weltec61a90e2011-05-22 22:45:37 +02001662 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Welteb7284a92009-10-20 09:56:18 +02001663 DEBUGPC(DNM, "Sending OPSTART\n");
1664
Harald Welte59b04682009-06-10 05:40:52 +08001665 return abis_nm_sendmsg(bts, msg);
1666}
1667
1668/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001669int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1670 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001671{
1672 struct abis_om_hdr *oh;
1673 struct msgb *msg = nm_msgb_alloc();
1674
1675 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1676 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1677 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1678
1679 return abis_nm_sendmsg(bts, msg);
1680}
1681
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001682int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1683 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001684{
1685 struct abis_om_hdr *oh;
1686 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001687 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001688
1689 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1690 e1_port0, ts0, e1_port1, ts1);
1691
1692 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1693 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1694 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1695
1696 attr = msgb_put(msg, 3);
1697 attr[0] = NM_ATT_MDROP_LINK;
1698 attr[1] = e1_port0;
1699 attr[2] = ts0;
1700
1701 attr = msgb_put(msg, 3);
1702 attr[0] = NM_ATT_MDROP_NEXT;
1703 attr[1] = e1_port1;
1704 attr[2] = ts1;
1705
1706 return abis_nm_sendmsg(bts, msg);
1707}
Harald Welte59b04682009-06-10 05:40:52 +08001708
Harald Welte0bf8e302009-08-08 00:02:36 +02001709/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001710int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1711 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1712 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001713{
1714 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001715
Harald Weltec61a90e2011-05-22 22:45:37 +02001716 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001717
1718 if (!msg)
1719 msg = nm_msgb_alloc();
1720
1721 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1722 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1723 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1724 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001725 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001726
1727 return abis_nm_sendmsg(bts, msg);
1728}
1729
Harald Welte59b04682009-06-10 05:40:52 +08001730int abis_nm_event_reports(struct gsm_bts *bts, int on)
1731{
1732 if (on == 0)
1733 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1734 else
1735 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1736}
1737
1738/* Siemens (or BS-11) specific commands */
1739
1740int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1741{
1742 if (reconnect == 0)
1743 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1744 else
1745 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1746}
1747
1748int abis_nm_bs11_restart(struct gsm_bts *bts)
1749{
1750 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1751}
1752
1753
1754struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001755 uint16_t year;
1756 uint8_t month;
1757 uint8_t day;
1758 uint8_t hour;
1759 uint8_t min;
1760 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001761} __attribute__((packed));
1762
1763
1764void get_bs11_date_time(struct bs11_date_time *aet)
1765{
1766 time_t t;
1767 struct tm *tm;
1768
1769 t = time(NULL);
1770 tm = localtime(&t);
1771 aet->sec = tm->tm_sec;
1772 aet->min = tm->tm_min;
1773 aet->hour = tm->tm_hour;
1774 aet->day = tm->tm_mday;
1775 aet->month = tm->tm_mon;
1776 aet->year = htons(1900 + tm->tm_year);
1777}
1778
1779int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1780{
1781 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1782}
1783
1784int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1785{
1786 if (begin)
1787 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1788 else
1789 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1790}
1791
1792int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001793 enum abis_bs11_objtype type, uint8_t idx,
1794 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001795{
1796 struct abis_om_hdr *oh;
1797 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001798 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001799
1800 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1801 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1802 NM_OC_BS11, type, 0, idx);
1803 cur = msgb_put(msg, attr_len);
1804 memcpy(cur, attr, attr_len);
1805
1806 return abis_nm_sendmsg(bts, msg);
1807}
1808
1809int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001810 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001811{
1812 struct abis_om_hdr *oh;
1813 struct msgb *msg = nm_msgb_alloc();
1814
1815 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1816 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1817 NM_OC_BS11, type, 0, idx);
1818
1819 return abis_nm_sendmsg(bts, msg);
1820}
1821
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001822int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001823{
1824 struct abis_om_hdr *oh;
1825 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001826 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001827
1828 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1829 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1830 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1831 msgb_tlv_put(msg, 0x99, 1, &zero);
1832
1833 return abis_nm_sendmsg(bts, msg);
1834}
1835
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001836int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001837{
1838 struct abis_om_hdr *oh;
1839 struct msgb *msg = nm_msgb_alloc();
1840
1841 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1842 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001843 idx, 0xff, 0xff);
1844
1845 return abis_nm_sendmsg(bts, msg);
1846}
1847
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001848int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001849{
1850 struct abis_om_hdr *oh;
1851 struct msgb *msg = nm_msgb_alloc();
1852
1853 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1854 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1855 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001856
1857 return abis_nm_sendmsg(bts, msg);
1858}
1859
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001860static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001861int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1862{
1863 struct abis_om_hdr *oh;
1864 struct msgb *msg = nm_msgb_alloc();
1865
1866 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1867 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1868 0xff, 0xff, 0xff);
1869 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1870
1871 return abis_nm_sendmsg(bts, msg);
1872}
1873
1874/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001875int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1876 uint8_t e1_timeslot, uint8_t e1_subslot,
1877 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001878{
1879 struct abis_om_hdr *oh;
1880 struct abis_nm_channel *ch;
1881 struct msgb *msg = nm_msgb_alloc();
1882
1883 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1884 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1885 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1886
1887 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1888 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1889 msgb_tv_put(msg, NM_ATT_TEI, tei);
1890
1891 return abis_nm_sendmsg(bts, msg);
1892}
1893
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001894int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08001895{
1896 struct abis_om_hdr *oh;
1897 struct msgb *msg = nm_msgb_alloc();
1898
1899 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1900 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
1901 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1902 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1903
1904 return abis_nm_sendmsg(trx->bts, msg);
1905}
1906
1907int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1908{
1909 struct abis_om_hdr *oh;
1910 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001911 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08001912
1913 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1914 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1915 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1916 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1917
1918 return abis_nm_sendmsg(trx->bts, msg);
1919}
1920
1921int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1922{
1923 struct abis_om_hdr *oh;
1924 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001925 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08001926
1927 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1928 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1929 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
1930 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1931
1932 return abis_nm_sendmsg(bts, msg);
1933}
1934
1935int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1936{
1937 struct abis_om_hdr *oh;
1938 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001939 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08001940 NM_ATT_BS11_CCLK_TYPE };
1941
1942 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1943 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1944 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1945 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1946
1947 return abis_nm_sendmsg(bts, msg);
1948
1949}
1950
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001951//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08001952
1953int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
1954{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001955 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1956}
1957
Daniel Willmannbf2ca572010-01-07 00:46:26 +01001958int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1959{
1960 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1961}
1962
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001963int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001964{
Harald Welte59b04682009-06-10 05:40:52 +08001965 struct abis_om_hdr *oh;
1966 struct msgb *msg = nm_msgb_alloc();
1967 struct bs11_date_time bdt;
1968
1969 get_bs11_date_time(&bdt);
1970
1971 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1972 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001973 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001974 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08001975 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
1976 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
1977 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001978 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08001979 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001980 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08001981 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001982 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08001983 } else {
1984 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
1985 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
1986 }
1987
1988 return abis_nm_sendmsg(bts, msg);
1989}
1990
1991int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
1992{
1993 struct abis_om_hdr *oh;
1994 struct msgb *msg;
1995
1996 if (strlen(password) != 10)
1997 return -EINVAL;
1998
1999 msg = nm_msgb_alloc();
2000 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2001 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2002 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002003 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002004
2005 return abis_nm_sendmsg(bts, msg);
2006}
2007
2008/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2009int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2010{
2011 struct abis_om_hdr *oh;
2012 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002013 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002014
2015 msg = nm_msgb_alloc();
2016 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2017 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2018 BS11_OBJ_LI, 0x00, 0x00);
2019
2020 if (locked)
2021 tlv_value = BS11_LI_PLL_LOCKED;
2022 else
2023 tlv_value = BS11_LI_PLL_STANDALONE;
2024
2025 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2026
2027 return abis_nm_sendmsg(bts, msg);
2028}
2029
Daniel Willmann10b07db2010-01-07 00:54:01 +01002030/* Set the calibration value of the PLL (work value/set value)
2031 * It depends on the login which one is changed */
2032int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2033{
2034 struct abis_om_hdr *oh;
2035 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002036 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002037
2038 msg = nm_msgb_alloc();
2039 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2040 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2041 BS11_OBJ_TRX1, 0x00, 0x00);
2042
2043 tlv_value[0] = value>>8;
2044 tlv_value[1] = value&0xff;
2045
2046 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2047
2048 return abis_nm_sendmsg(bts, msg);
2049}
2050
Harald Welte59b04682009-06-10 05:40:52 +08002051int abis_nm_bs11_get_state(struct gsm_bts *bts)
2052{
2053 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2054}
2055
2056/* BS11 SWL */
2057
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002058void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002059
Harald Welte59b04682009-06-10 05:40:52 +08002060struct abis_nm_bs11_sw {
2061 struct gsm_bts *bts;
2062 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002063 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002064 int forced;
2065 struct llist_head file_list;
2066 gsm_cbfn *user_cb; /* specified by the user */
2067};
2068static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2069
2070struct file_list_entry {
2071 struct llist_head list;
2072 char fname[PATH_MAX];
2073};
2074
2075struct file_list_entry *fl_dequeue(struct llist_head *queue)
2076{
2077 struct llist_head *lh;
2078
2079 if (llist_empty(queue))
2080 return NULL;
2081
2082 lh = queue->next;
2083 llist_del(lh);
2084
2085 return llist_entry(lh, struct file_list_entry, list);
2086}
2087
2088static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2089{
2090 char linebuf[255];
2091 struct llist_head *lh, *lh2;
2092 FILE *swl;
2093 int rc = 0;
2094
2095 swl = fopen(bs11_sw->swl_fname, "r");
2096 if (!swl)
2097 return -ENODEV;
2098
2099 /* zero the stale file list, if any */
2100 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2101 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002102 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002103 }
2104
2105 while (fgets(linebuf, sizeof(linebuf), swl)) {
2106 char file_id[12+1];
2107 char file_version[80+1];
2108 struct file_list_entry *fle;
2109 static char dir[PATH_MAX];
2110
2111 if (strlen(linebuf) < 4)
2112 continue;
2113
2114 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2115 if (rc < 0) {
2116 perror("ERR parsing SWL file");
2117 rc = -EINVAL;
2118 goto out;
2119 }
2120 if (rc < 2)
2121 continue;
2122
Harald Welte857e00d2009-06-26 20:25:23 +02002123 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002124 if (!fle) {
2125 rc = -ENOMEM;
2126 goto out;
2127 }
Harald Welte59b04682009-06-10 05:40:52 +08002128
2129 /* construct new filename */
2130 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2131 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2132 strcat(fle->fname, "/");
2133 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2134
2135 llist_add_tail(&fle->list, &bs11_sw->file_list);
2136 }
2137
2138out:
2139 fclose(swl);
2140 return rc;
2141}
2142
2143/* bs11 swload specific callback, passed to abis_nm core swload */
2144static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2145 struct msgb *msg, void *data, void *param)
2146{
2147 struct abis_nm_bs11_sw *bs11_sw = data;
2148 struct file_list_entry *fle;
2149 int rc = 0;
2150
2151 switch (event) {
2152 case NM_MT_LOAD_END_ACK:
2153 fle = fl_dequeue(&bs11_sw->file_list);
2154 if (fle) {
2155 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002156 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002157 bs11_sw->win_size,
2158 bs11_sw->forced,
2159 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002160 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002161 } else {
2162 /* activate the SWL */
2163 rc = abis_nm_software_activate(bs11_sw->bts,
2164 bs11_sw->swl_fname,
2165 bs11_swload_cbfn,
2166 bs11_sw);
2167 }
2168 break;
2169 case NM_MT_LOAD_SEG_ACK:
2170 case NM_MT_LOAD_END_NACK:
2171 case NM_MT_LOAD_INIT_ACK:
2172 case NM_MT_LOAD_INIT_NACK:
2173 case NM_MT_ACTIVATE_SW_NACK:
2174 case NM_MT_ACTIVATE_SW_ACK:
2175 default:
2176 /* fallthrough to the user callback */
2177 if (bs11_sw->user_cb)
2178 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2179 break;
2180 }
2181
2182 return rc;
2183}
2184
2185/* Siemens provides a SWL file that is a mere listing of all the other
2186 * files that are part of a software release. We need to upload first
2187 * the list file, and then each file that is listed in the list file */
2188int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002189 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002190{
2191 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2192 struct file_list_entry *fle;
2193 int rc = 0;
2194
2195 INIT_LLIST_HEAD(&bs11_sw->file_list);
2196 bs11_sw->bts = bts;
2197 bs11_sw->win_size = win_size;
2198 bs11_sw->user_cb = cbfn;
2199 bs11_sw->forced = forced;
2200
2201 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2202 rc = bs11_read_swl_file(bs11_sw);
2203 if (rc < 0)
2204 return rc;
2205
2206 /* dequeue next item in file list */
2207 fle = fl_dequeue(&bs11_sw->file_list);
2208 if (!fle)
2209 return -EINVAL;
2210
2211 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002212 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002213 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002214 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002215 return rc;
2216}
2217
2218#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002219static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002220 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2221 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2222 NM_ATT_BS11_LMT_USER_NAME,
2223
2224 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2225
2226 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2227
2228 NM_ATT_BS11_SW_LOAD_STORED };
2229
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002230static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002231 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2232 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2233 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2234 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2235#endif
2236
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002237static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002238 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2239 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2240 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2241
2242int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2243{
2244 struct abis_om_hdr *oh;
2245 struct msgb *msg = nm_msgb_alloc();
2246
2247 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2248 /* SiemensHW CCTRL object */
2249 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2250 0x03, 0x00, 0x00);
2251 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2252
2253 return abis_nm_sendmsg(bts, msg);
2254}
2255
2256int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2257{
2258 struct abis_om_hdr *oh;
2259 struct msgb *msg = nm_msgb_alloc();
2260 struct bs11_date_time aet;
2261
2262 get_bs11_date_time(&aet);
2263 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2264 /* SiemensHW CCTRL object */
2265 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2266 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002267 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002268
2269 return abis_nm_sendmsg(bts, msg);
2270}
2271
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002272int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002273{
2274 struct abis_om_hdr *oh;
2275 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002276 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002277
2278 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2279 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2280 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2281 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2282
2283 return abis_nm_sendmsg(bts, msg);
2284}
2285
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002286int 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 +02002287{
2288 struct abis_om_hdr *oh;
2289 struct msgb *msg = nm_msgb_alloc();
2290 struct bs11_date_time aet;
2291
2292 get_bs11_date_time(&aet);
2293 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2294 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2295 bport, 0xff, 0x02);
2296 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2297
2298 return abis_nm_sendmsg(bts, msg);
2299}
2300
Harald Welte59b04682009-06-10 05:40:52 +08002301/* ip.access nanoBTS specific commands */
2302static const char ipaccess_magic[] = "com.ipaccess";
2303
2304
2305static int abis_nm_rx_ipacc(struct msgb *msg)
2306{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002307 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002308 struct abis_om_hdr *oh = msgb_l2(msg);
2309 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002310 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002311 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002312 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002313 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002314
2315 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002316 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002317 return -EINVAL;
2318 }
2319
2320 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002321 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002322
Harald Weltec61a90e2011-05-22 22:45:37 +02002323 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002324
Harald Welte5aeedd42009-10-19 22:11:11 +02002325 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002326
2327 switch (foh->msg_type) {
2328 case NM_MT_IPACC_RSL_CONNECT_ACK:
2329 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002330 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2331 memcpy(&addr,
2332 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2333
2334 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2335 }
Harald Welte4206d982009-07-12 09:33:54 +02002336 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002337 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002338 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002339 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002340 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2341 DEBUGPC(DNM, "STREAM=0x%02x ",
2342 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002343 DEBUGPC(DNM, "\n");
2344 break;
2345 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002346 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002347 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002348 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002349 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002350 else
2351 DEBUGPC(DNM, "\n");
2352 break;
2353 case NM_MT_IPACC_SET_NVATTR_ACK:
2354 DEBUGPC(DNM, "SET NVATTR ACK\n");
2355 /* FIXME: decode and show the actual attributes */
2356 break;
2357 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002358 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002359 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002360 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002361 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002362 else
Harald Weltede4477a2009-12-24 12:20:20 +01002363 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002364 break;
Harald Welte21460f02009-07-03 11:26:45 +02002365 case NM_MT_IPACC_GET_NVATTR_ACK:
2366 DEBUGPC(DNM, "GET NVATTR ACK\n");
2367 /* FIXME: decode and show the actual attributes */
2368 break;
2369 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002370 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002371 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002372 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002373 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002374 else
Harald Weltede4477a2009-12-24 12:20:20 +01002375 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002376 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002377 case NM_MT_IPACC_SET_ATTR_ACK:
2378 DEBUGPC(DNM, "SET ATTR ACK\n");
2379 break;
2380 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002381 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002382 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002383 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002384 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002385 else
Harald Weltede4477a2009-12-24 12:20:20 +01002386 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002387 break;
Harald Welte59b04682009-06-10 05:40:52 +08002388 default:
2389 DEBUGPC(DNM, "unknown\n");
2390 break;
2391 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002392
2393 /* signal handling */
2394 switch (foh->msg_type) {
2395 case NM_MT_IPACC_RSL_CONNECT_NACK:
2396 case NM_MT_IPACC_SET_NVATTR_NACK:
2397 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002398 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002399 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002400 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002401 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002402 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002403 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002404 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002405 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002406 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002407 default:
2408 break;
2409 }
2410
Harald Welte59b04682009-06-10 05:40:52 +08002411 return 0;
2412}
2413
2414/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002415int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2416 uint8_t obj_class, uint8_t bts_nr,
2417 uint8_t trx_nr, uint8_t ts_nr,
2418 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002419{
2420 struct msgb *msg = nm_msgb_alloc();
2421 struct abis_om_hdr *oh;
2422 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002423 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002424
2425 /* construct the 12.21 OM header, observe the erroneous length */
2426 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2427 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2428 oh->mdisc = ABIS_OM_MDISC_MANUF;
2429
2430 /* add the ip.access magic */
2431 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2432 *data++ = sizeof(ipaccess_magic);
2433 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2434
2435 /* fill the 12.21 FOM header */
2436 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2437 foh->msg_type = msg_type;
2438 foh->obj_class = obj_class;
2439 foh->obj_inst.bts_nr = bts_nr;
2440 foh->obj_inst.trx_nr = trx_nr;
2441 foh->obj_inst.ts_nr = ts_nr;
2442
2443 if (attr && attr_len) {
2444 data = msgb_put(msg, attr_len);
2445 memcpy(data, attr, attr_len);
2446 }
2447
2448 return abis_nm_sendmsg(bts, msg);
2449}
2450
2451/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002452int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002453 int attr_len)
2454{
Harald Weltef12c1052010-01-07 20:39:42 +01002455 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2456 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002457 attr_len);
2458}
2459
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002460int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002461 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002462{
2463 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002464 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002465 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2466 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2467
2468 int attr_len = sizeof(attr);
2469
2470 ia.s_addr = htonl(ip);
2471 attr[1] = stream;
2472 attr[3] = port >> 8;
2473 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002474 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002475
2476 /* if ip == 0, we use the default IP */
2477 if (ip == 0)
2478 attr_len -= 5;
2479
2480 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002481 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002482
2483 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2484 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2485 trx->nr, 0xff, attr, attr_len);
2486}
2487
Harald Welte59b04682009-06-10 05:40:52 +08002488/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002489int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002490{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002491 struct abis_om_hdr *oh;
2492 struct msgb *msg = nm_msgb_alloc();
2493
2494 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2495 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2496 trx->bts->nr, trx->nr, 0xff);
2497
2498 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002499}
Harald Welte0dfc6232009-10-24 10:20:41 +02002500
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002501int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2502 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2503 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002504{
2505 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2506 obj_class, bts_nr, trx_nr, ts_nr,
2507 attr, attr_len);
2508}
Harald Weltebeeae412009-11-12 14:48:42 +01002509
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002510void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002511{
2512 /* we simply reuse the GSM48 function and overwrite the RAC
2513 * with the Cell ID */
2514 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002515 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002516}
2517
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002518void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2519{
2520 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2521
Harald Welte69f6f812011-05-30 12:07:53 +02002522 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002523 if (!trx->bts || !trx->bts->oml_link)
2524 return;
2525
2526 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2527 trx->bts->bts_nr, trx->nr, 0xff,
2528 new_state);
2529}
2530
Harald Welte453141f2010-03-25 11:45:30 +08002531static const struct value_string ipacc_testres_names[] = {
2532 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2533 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2534 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2535 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2536 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2537 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002538};
2539
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002540const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002541{
Harald Welte453141f2010-03-25 11:45:30 +08002542 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002543}
2544
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002545void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002546{
2547 cid->mcc = (buf[0] & 0xf) * 100;
2548 cid->mcc += (buf[0] >> 4) * 10;
2549 cid->mcc += (buf[1] & 0xf) * 1;
2550
2551 if (buf[1] >> 4 == 0xf) {
2552 cid->mnc = (buf[2] & 0xf) * 10;
2553 cid->mnc += (buf[2] >> 4) * 1;
2554 } else {
2555 cid->mnc = (buf[2] & 0xf) * 100;
2556 cid->mnc += (buf[2] >> 4) * 10;
2557 cid->mnc += (buf[1] >> 4) * 1;
2558 }
2559
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002560 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2561 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002562}
2563
Harald Weltebeeae412009-11-12 14:48:42 +01002564/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002565int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002566{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002567 uint8_t *cur = buf;
2568 uint16_t len;
Harald Weltebeeae412009-11-12 14:48:42 +01002569
Harald Welteb784df82010-07-22 18:14:36 +02002570 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002571
2572 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2573 return -EINVAL;
2574 cur++;
2575
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002576 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002577 cur += 2;
2578
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002579 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002580 cur += 2;
2581
2582 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2583 binf->freq_qual = *cur >> 2;
2584
Harald Welteb784df82010-07-22 18:14:36 +02002585 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002586 binf->arfcn |= *cur++;
2587
2588 if (binf->info_type & IPAC_BINF_RXLEV)
2589 binf->rx_lev = *cur & 0x3f;
2590 cur++;
2591
2592 if (binf->info_type & IPAC_BINF_RXQUAL)
2593 binf->rx_qual = *cur & 0x7;
2594 cur++;
2595
2596 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002597 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002598 cur += 2;
2599
2600 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002601 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002602 cur += 2;
2603
2604 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002605 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002606 cur += 4;
2607
Harald Welte22cb81f2010-07-30 22:34:42 +02002608#if 0
2609 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002610 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002611#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002612 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002613 cur++;
2614
Harald Weltebfc21092009-11-13 11:56:05 +01002615 ipac_parse_cgi(&binf->cgi, cur);
2616 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002617
2618 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2619 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2620 cur += sizeof(binf->ba_list_si2);
2621 }
2622
2623 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2624 memcpy(binf->ba_list_si2bis, cur,
2625 sizeof(binf->ba_list_si2bis));
2626 cur += sizeof(binf->ba_list_si2bis);
2627 }
2628
2629 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2630 memcpy(binf->ba_list_si2ter, cur,
2631 sizeof(binf->ba_list_si2ter));
2632 cur += sizeof(binf->ba_list_si2ter);
2633 }
2634
2635 return 0;
2636}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002637
2638void abis_nm_clear_queue(struct gsm_bts *bts)
2639{
2640 struct msgb *msg;
2641
2642 while (!llist_empty(&bts->abis_queue)) {
2643 msg = msgb_dequeue(&bts->abis_queue);
2644 msgb_free(msg);
2645 }
2646
2647 bts->abis_nm_pend = 0;
2648}