blob: 58e3bed66849e619a0b30f9bb779d2061bb36e6d [file] [log] [blame]
Harald Welte3300c012011-06-05 13:31:33 +02001/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
2 *
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <errno.h>
25#include <ctype.h>
26
27#include <netinet/in.h>
28
29#include <osmocom/core/linuxlist.h>
30#include <osmocom/core/talloc.h>
31#include <osmocom/gsm/gsm_utils.h>
32#include <osmocom/gsm/abis_nm.h>
33#include <osmocom/core/statistics.h>
34
Harald Welte5ac01792011-06-06 17:52:38 +020035#include <openbsc/gsm_data.h>
Harald Welte3300c012011-06-05 13:31:33 +020036
Harald Welteb7849982011-06-29 16:49:03 +020037void gsm_abis_mo_reset(struct gsm_abis_mo *mo)
38{
39 mo->nm_state.administrative = NM_STATE_NULL;
40 mo->nm_state.operational = NM_OPSTATE_NULL;
41 mo->nm_state.availability = NM_AVSTATE_POWER_OFF;
42}
43
Harald Welte850dc6b2011-06-06 20:13:33 +020044static void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts,
45 uint8_t obj_class, uint8_t p1, uint8_t p2, uint8_t p3)
Harald Welte32bc1162011-06-06 18:58:48 +020046{
47 mo->bts = bts;
Harald Welte850dc6b2011-06-06 20:13:33 +020048 mo->obj_class = obj_class;
49 mo->obj_inst.bts_nr = p1;
50 mo->obj_inst.trx_nr = p2;
51 mo->obj_inst.ts_nr = p3;
Harald Welteb7849982011-06-29 16:49:03 +020052 gsm_abis_mo_reset(mo);
Harald Welte32bc1162011-06-06 18:58:48 +020053}
54
Harald Welte3300c012011-06-05 13:31:33 +020055static const struct value_string pchan_names[] = {
56 { GSM_PCHAN_NONE, "NONE" },
57 { GSM_PCHAN_CCCH, "CCCH" },
58 { GSM_PCHAN_CCCH_SDCCH4,"CCCH+SDCCH4" },
59 { GSM_PCHAN_TCH_F, "TCH/F" },
60 { GSM_PCHAN_TCH_H, "TCH/H" },
61 { GSM_PCHAN_SDCCH8_SACCH8C, "SDCCH8" },
62 { GSM_PCHAN_PDCH, "PDCH" },
63 { GSM_PCHAN_TCH_F_PDCH, "TCH/F_PDCH" },
64 { GSM_PCHAN_UNKNOWN, "UNKNOWN" },
65 { 0, NULL }
66};
67
68const char *gsm_pchan_name(enum gsm_phys_chan_config c)
69{
70 return get_value_string(pchan_names, c);
71}
72
73enum gsm_phys_chan_config gsm_pchan_parse(const char *name)
74{
75 return get_string_value(pchan_names, name);
76}
77
78static const struct value_string lchant_names[] = {
79 { GSM_LCHAN_NONE, "NONE" },
80 { GSM_LCHAN_SDCCH, "SDCCH" },
81 { GSM_LCHAN_TCH_F, "TCH/F" },
82 { GSM_LCHAN_TCH_H, "TCH/H" },
83 { GSM_LCHAN_UNKNOWN, "UNKNOWN" },
84 { 0, NULL }
85};
86
87const char *gsm_lchant_name(enum gsm_chan_t c)
88{
89 return get_value_string(lchant_names, c);
90}
91
92static const struct value_string lchan_s_names[] = {
93 { LCHAN_S_NONE, "NONE" },
94 { LCHAN_S_ACT_REQ, "ACTIVATION REQUESTED" },
95 { LCHAN_S_ACTIVE, "ACTIVE" },
96 { LCHAN_S_INACTIVE, "INACTIVE" },
97 { LCHAN_S_REL_REQ, "RELEASE REQUESTED" },
98 { LCHAN_S_REL_ERR, "RELEASE DUE ERROR" },
99 { 0, NULL }
100};
101
102const char *gsm_lchans_name(enum gsm_lchan_state s)
103{
104 return get_value_string(lchan_s_names, s);
105}
106
107static const struct value_string chreq_names[] = {
108 { GSM_CHREQ_REASON_EMERG, "EMERGENCY" },
109 { GSM_CHREQ_REASON_PAG, "PAGING" },
110 { GSM_CHREQ_REASON_CALL, "CALL" },
111 { GSM_CHREQ_REASON_LOCATION_UPD,"LOCATION_UPDATE" },
112 { GSM_CHREQ_REASON_OTHER, "OTHER" },
113 { 0, NULL }
114};
115
116const char *gsm_chreq_name(enum gsm_chreq_reason_t c)
117{
118 return get_value_string(chreq_names, c);
119}
120
121struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
122{
123 struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx);
124 int k;
125
126 if (!trx)
127 return NULL;
128
129 trx->bts = bts;
130 trx->nr = bts->num_trx++;
131 trx->mo.nm_state.administrative = NM_STATE_UNLOCKED;
132
Harald Welte850dc6b2011-06-06 20:13:33 +0200133 gsm_mo_init(&trx->mo, bts, NM_OC_RADIO_CARRIER,
134 bts->nr, trx->nr, 0xff);
135 gsm_mo_init(&trx->bb_transc.mo, bts, NM_OC_BASEB_TRANSC,
136 bts->nr, trx->nr, 0xff);
Harald Welte32bc1162011-06-06 18:58:48 +0200137
Harald Welte3300c012011-06-05 13:31:33 +0200138 for (k = 0; k < TRX_NR_TS; k++) {
139 struct gsm_bts_trx_ts *ts = &trx->ts[k];
140 int l;
141
142 ts->trx = trx;
143 ts->nr = k;
144 ts->pchan = GSM_PCHAN_NONE;
145 ts->tsc = -1;
146
Harald Welte850dc6b2011-06-06 20:13:33 +0200147 gsm_mo_init(&ts->mo, bts, NM_OC_CHANNEL,
148 bts->nr, trx->nr, ts->nr);
Harald Welte32bc1162011-06-06 18:58:48 +0200149
Harald Welte3300c012011-06-05 13:31:33 +0200150 ts->hopping.arfcns.data_len = sizeof(ts->hopping.arfcns_data);
151 ts->hopping.arfcns.data = ts->hopping.arfcns_data;
152 ts->hopping.ma.data_len = sizeof(ts->hopping.ma_data);
153 ts->hopping.ma.data = ts->hopping.ma_data;
154
155 for (l = 0; l < TS_MAX_LCHAN; l++) {
156 struct gsm_lchan *lchan;
157 lchan = &ts->lchan[l];
158
159 lchan->ts = ts;
160 lchan->nr = l;
161 lchan->type = GSM_LCHAN_NONE;
162 }
163 }
164
165 if (trx->nr != 0)
166 trx->nominal_power = bts->c0->nominal_power;
167
168 llist_add_tail(&trx->list, &bts->trx_list);
169
170 return trx;
171}
172
Harald Welte32bc1162011-06-06 18:58:48 +0200173
Harald Welte3300c012011-06-05 13:31:33 +0200174static const uint8_t bts_nse_timer_default[] = { 3, 3, 3, 3, 30, 3, 10 };
175static const uint8_t bts_cell_timer_default[] =
176 { 3, 3, 3, 3, 3, 10, 3, 10, 3, 10, 3 };
177
178struct gsm_bts *gsm_bts_alloc(void *ctx)
179{
180 struct gsm_bts *bts = talloc_zero(ctx, struct gsm_bts);
181 int i;
182
183 if (!bts)
184 return NULL;
185
186 bts->num_trx = 0;
187 INIT_LLIST_HEAD(&bts->trx_list);
188 bts->ms_max_power = 15; /* dBm */
189
Harald Welte850dc6b2011-06-06 20:13:33 +0200190 gsm_mo_init(&bts->mo, bts, NM_OC_BTS,
191 bts->nr, 0xff, 0xff);
192 gsm_mo_init(&bts->site_mgr.mo, bts, NM_OC_SITE_MANAGER,
193 0xff, 0xff, 0xff);
Harald Welte32bc1162011-06-06 18:58:48 +0200194
Harald Welte3300c012011-06-05 13:31:33 +0200195 for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
196 bts->gprs.nsvc[i].bts = bts;
197 bts->gprs.nsvc[i].id = i;
Harald Welte850dc6b2011-06-06 20:13:33 +0200198 gsm_mo_init(&bts->gprs.nsvc[i].mo, bts, NM_OC_GPRS_NSVC,
199 bts->nr, i, 0xff);
Harald Welte3300c012011-06-05 13:31:33 +0200200 }
201 memcpy(&bts->gprs.nse.timer, bts_nse_timer_default,
202 sizeof(bts->gprs.nse.timer));
Harald Welte850dc6b2011-06-06 20:13:33 +0200203 gsm_mo_init(&bts->gprs.nse.mo, bts, NM_OC_GPRS_NSE,
204 bts->nr, 0xff, 0xff);
Harald Welte3300c012011-06-05 13:31:33 +0200205 memcpy(&bts->gprs.cell.timer, bts_cell_timer_default,
206 sizeof(bts->gprs.cell.timer));
Harald Welte850dc6b2011-06-06 20:13:33 +0200207 gsm_mo_init(&bts->gprs.cell.mo, bts, NM_OC_GPRS_CELL,
208 bts->nr, 0xff, 0xff);
Harald Welte3300c012011-06-05 13:31:33 +0200209
210 /* create our primary TRX */
211 bts->c0 = gsm_bts_trx_alloc(bts);
212 if (!bts->c0) {
213 talloc_free(bts);
214 return NULL;
215 }
216 bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
217
218 bts->rach_b_thresh = -1;
219 bts->rach_ldavg_slots = -1;
220 bts->paging.free_chans_need = -1;
221
222 return bts;
223}
224
Harald Welteb7849982011-06-29 16:49:03 +0200225/* reset the state of all MO in the BTS */
226void gsm_bts_mo_reset(struct gsm_bts *bts)
227{
228 struct gsm_bts_trx *trx;
229 unsigned int i;
230
231 gsm_abis_mo_reset(&bts->mo);
232 gsm_abis_mo_reset(&bts->site_mgr.mo);
233 for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++)
234 gsm_abis_mo_reset(&bts->gprs.nsvc[i].mo);
235 gsm_abis_mo_reset(&bts->gprs.nse.mo);
236 gsm_abis_mo_reset(&bts->gprs.cell.mo);
237
238 llist_for_each_entry(trx, &bts->trx_list, list) {
239 gsm_abis_mo_reset(&trx->mo);
240 gsm_abis_mo_reset(&trx->bb_transc.mo);
241
242 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
243 struct gsm_bts_trx_ts *ts = &trx->ts[i];
244 gsm_abis_mo_reset(&ts->mo);
245 }
246 }
247}
248
Harald Welte3300c012011-06-05 13:31:33 +0200249struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num)
250{
251 struct gsm_bts_trx *trx;
252
253 if (num >= bts->num_trx)
254 return NULL;
255
256 llist_for_each_entry(trx, &bts->trx_list, list) {
257 if (trx->nr == num)
258 return trx;
259 }
260
261 return NULL;
262}
263
264static char ts2str[255];
265
266char *gsm_trx_name(struct gsm_bts_trx *trx)
267{
268 snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d)",
269 trx->bts->nr, trx->nr);
270
271 return ts2str;
272}
273
274
275char *gsm_ts_name(struct gsm_bts_trx_ts *ts)
276{
277 snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)",
278 ts->trx->bts->nr, ts->trx->nr, ts->nr);
279
280 return ts2str;
281}
282
283char *gsm_lchan_name(struct gsm_lchan *lchan)
284{
285 struct gsm_bts_trx_ts *ts = lchan->ts;
286
287 snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,ss=%d)",
288 ts->trx->bts->nr, ts->trx->nr, ts->nr, lchan->nr);
289
290 return ts2str;
291}
Harald Welte978714d2011-06-06 18:31:20 +0200292
293/* obtain the MO structure for a given object instance */
294struct gsm_abis_mo *
295gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
296 struct abis_om_obj_inst *obj_inst)
297{
298 struct gsm_bts_trx *trx;
299 struct gsm_abis_mo *mo = NULL;
300
301 switch (obj_class) {
302 case NM_OC_BTS:
303 mo = &bts->mo;
304 break;
305 case NM_OC_RADIO_CARRIER:
306 if (obj_inst->trx_nr >= bts->num_trx) {
307 return NULL;
308 }
309 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
310 mo = &trx->mo;
311 break;
312 case NM_OC_BASEB_TRANSC:
313 if (obj_inst->trx_nr >= bts->num_trx) {
314 return NULL;
315 }
316 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
317 mo = &trx->bb_transc.mo;
318 break;
319 case NM_OC_CHANNEL:
320 if (obj_inst->trx_nr >= bts->num_trx) {
321 return NULL;
322 }
323 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
324 if (obj_inst->ts_nr >= TRX_NR_TS)
325 return NULL;
326 mo = &trx->ts[obj_inst->ts_nr].mo;
327 break;
328 case NM_OC_SITE_MANAGER:
329 mo = &bts->site_mgr.mo;
330 break;
331 case NM_OC_BS11:
332 switch (obj_inst->bts_nr) {
333 case BS11_OBJ_CCLK:
334 mo = &bts->bs11.cclk.mo;
335 break;
336 case BS11_OBJ_BBSIG:
337 if (obj_inst->ts_nr > bts->num_trx)
338 return NULL;
339 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
340 mo = &trx->bs11.bbsig.mo;
341 break;
342 case BS11_OBJ_PA:
343 if (obj_inst->ts_nr > bts->num_trx)
344 return NULL;
345 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
346 mo = &trx->bs11.pa.mo;
347 break;
348 default:
349 return NULL;
350 }
351 case NM_OC_BS11_RACK:
352 mo = &bts->bs11.rack.mo;
353 break;
354 case NM_OC_BS11_ENVABTSE:
355 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
356 return NULL;
357 mo = &bts->bs11.envabtse[obj_inst->trx_nr].mo;
358 break;
359 case NM_OC_GPRS_NSE:
360 mo = &bts->gprs.nse.mo;
361 break;
362 case NM_OC_GPRS_CELL:
363 mo = &bts->gprs.cell.mo;
364 break;
365 case NM_OC_GPRS_NSVC:
366 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
367 return NULL;
368 mo = &bts->gprs.nsvc[obj_inst->trx_nr].mo;
369 break;
370 }
371 return mo;
372}
373
374/* obtain the gsm_nm_state data structure for a given object instance */
375struct gsm_nm_state *
376gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
377 struct abis_om_obj_inst *obj_inst)
378{
379 struct gsm_abis_mo *mo;
380
381 mo = gsm_objclass2mo(bts, obj_class, obj_inst);
382 if (!mo)
383 return NULL;
384
385 return &mo->nm_state;
386}
387
388/* obtain the in-memory data structure of a given object instance */
389void *
390gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
391 struct abis_om_obj_inst *obj_inst)
392{
393 struct gsm_bts_trx *trx;
394 void *obj = NULL;
395
396 switch (obj_class) {
397 case NM_OC_BTS:
398 obj = bts;
399 break;
400 case NM_OC_RADIO_CARRIER:
401 if (obj_inst->trx_nr >= bts->num_trx) {
402 return NULL;
403 }
404 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
405 obj = trx;
406 break;
407 case NM_OC_BASEB_TRANSC:
408 if (obj_inst->trx_nr >= bts->num_trx) {
409 return NULL;
410 }
411 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
412 obj = &trx->bb_transc;
413 break;
414 case NM_OC_CHANNEL:
415 if (obj_inst->trx_nr >= bts->num_trx) {
416 return NULL;
417 }
418 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
419 if (obj_inst->ts_nr >= TRX_NR_TS)
420 return NULL;
421 obj = &trx->ts[obj_inst->ts_nr];
422 break;
423 case NM_OC_SITE_MANAGER:
424 obj = &bts->site_mgr;
425 break;
426 case NM_OC_GPRS_NSE:
427 obj = &bts->gprs.nse;
428 break;
429 case NM_OC_GPRS_CELL:
430 obj = &bts->gprs.cell;
431 break;
432 case NM_OC_GPRS_NSVC:
433 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
434 return NULL;
435 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
436 break;
437 }
438 return obj;
439}
Harald Weltef6093a42011-06-25 10:02:33 +0200440
441/* See Table 10.5.25 of GSM04.08 */
442uint8_t gsm_ts2chan_nr(const struct gsm_bts_trx_ts *ts, uint8_t lchan_nr)
443{
444 uint8_t cbits, chan_nr;
445
446 switch (ts->pchan) {
447 case GSM_PCHAN_TCH_F:
448 case GSM_PCHAN_PDCH:
449 case GSM_PCHAN_TCH_F_PDCH:
450 cbits = 0x01;
451 break;
452 case GSM_PCHAN_TCH_H:
453 cbits = 0x02;
454 cbits += lchan_nr;
455 break;
456 case GSM_PCHAN_CCCH_SDCCH4:
457 cbits = 0x04;
458 cbits += lchan_nr;
459 break;
460 case GSM_PCHAN_SDCCH8_SACCH8C:
461 cbits = 0x08;
462 cbits += lchan_nr;
463 break;
464 default:
465 case GSM_PCHAN_CCCH:
466 cbits = 0x10;
467 break;
468 }
469
470 chan_nr = (cbits << 3) | (ts->nr & 0x7);
471
472 return chan_nr;
473}
474
475uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan)
476{
477 return gsm_ts2chan_nr(lchan->ts, lchan->nr);
478}