From 958f259f9592e3729a2ebf4084d8f37bdba6bf3c Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Sun, 27 May 2018 01:26:31 +0200 Subject: dissolve libbsc: move all to src/osmo-bsc, link .o files Move all of libbsc/ into osmo-bsc/, and separate/move some implementations to allow linking from utils/* and ipaccess/* without pulling in unccessary dependencies. Some utilities use gsm_network and gsm_bts structs, which already include data structures for fairly advanced uses. Move initialization that only osmo-bsc needs into new bsc_network_init() and bsc_bts_alloc_register() functions, so that the leaner tools can use the old gsm_* versions without the need to link everything (e.g. handover and lchan alloc code). In some instances, there need to be stubs if to cut off linking "just before the RSL level" and prevent dependencies from creeping in. - abis_rsl_rcvmsg(): the only program currently interpreting RSL messages is osmo-bsc, the utils are merely concerned with OML, if at all. - paging_flush_bts(): ip.access nanobts models call this when the RSL link is dropped. Only osmo-bsc actually needs to do anything there. - on_gsm_ts_init(): the mechanism to trigger timeslot initialization is related to OML, while this action to take on init would pull in RSL dependencies. utils/ and ipaccess/ each have a stubs.c file to implement these stubs. Tests implement stubs inline where required. From src/utils/, src/ipaccess/ and tests/*/, link in .o files from osmo-bsc/. In order for this to work, the osmo-bsc subdir must be built before the other source trees. (An alternative would be to include the .c files as sources, but that would re-compile them in every source tree. Not a large burden really, but unless linking .o files gives problems, let's have the quicker build.) Minor obvious cleanups creep in with this patch, I will not bother to name them individually now unless code review asks me to. Rationale: 1) libbsc has been separate to use it for osmo-nitb and osmo-bsc in the old openbsc.git. This is no longer required, and spreading over libbsc and osmo-bsc is distracting. 2) Recently, ridiculous linking requirements have made adding new functions cumbersome, because libbsc has started depending on osmo-bsc/*.c implementations: on gscon FSM and bssap functions. For example, neither bs11_config nor ipaccess-config nor bts_test need handover_cfg or BSSMAP message composition. It makes no sense to link the entire osmo-bsc to it, nor do we want to keep adding stubs to each linking realm. Change-Id: I36a586726f5818121abe54d25654819fc451d3bf --- src/osmo-bsc/rest_octets.c | 878 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 878 insertions(+) create mode 100644 src/osmo-bsc/rest_octets.c (limited to 'src/osmo-bsc/rest_octets.c') diff --git a/src/osmo-bsc/rest_octets.c b/src/osmo-bsc/rest_octets.c new file mode 100644 index 000000000..9f2b4c0ab --- /dev/null +++ b/src/osmo-bsc/rest_octets.c @@ -0,0 +1,878 @@ +/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface, + * rest octet handling according to + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ + +/* (C) 2009 by Harald Welte + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* generate SI1 rest octets */ +int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 1; + + if (nch_pos) { + bitvec_set_bit(&bv, H); + bitvec_set_uint(&bv, *nch_pos, 5); + } else + bitvec_set_bit(&bv, L); + + if (is1800_net) + bitvec_set_bit(&bv, L); + else + bitvec_set_bit(&bv, H); + + bitvec_spare_padding(&bv, 6); + return bv.data_len; +} + +/* Append Repeated E-UTRAN Neighbour Cell to bitvec: see 3GPP TS 44.018 Table 10.5.2.33b.1 */ +static inline bool append_eutran_neib_cell(struct bitvec *bv, struct gsm_bts *bts, uint8_t budget) +{ + const struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; + unsigned i, skip = 0; + size_t offset = bts->e_offset; + int16_t rem = budget - 6; /* account for mandatory stop bit and THRESH_E-UTRAN_high */ + uint8_t earfcn_budget; + + if (budget <= 6) + return false; + + OSMO_ASSERT(budget <= SI2Q_MAX_LEN); + + /* first we have to properly adjust budget requirements */ + if (e->prio_valid) /* E-UTRAN_PRIORITY: 3GPP TS 45.008*/ + rem -= 4; + else + rem--; + + if (e->thresh_lo_valid) /* THRESH_E-UTRAN_low: */ + rem -= 6; + else + rem--; + + if (e->qrxlm_valid) /* E-UTRAN_QRXLEVMIN: */ + rem -= 6; + else + rem--; + + if (rem < 0) + return false; + + /* now we can proceed with actually adding EARFCNs within adjusted budget limit */ + for (i = 0; i < e->length; i++) { + if (e->arfcn[i] != OSMO_EARFCN_INVALID) { + if (skip < offset) { + skip++; /* ignore EARFCNs added on previous calls */ + } else { + earfcn_budget = 17; /* compute budget per-EARFCN */ + if (OSMO_EARFCN_MEAS_INVALID == e->meas_bw[i]) + earfcn_budget++; + else + earfcn_budget += 4; + + if (rem - earfcn_budget < 0) + break; + else { + bts->e_offset++; + rem -= earfcn_budget; + + if (rem < 0) + return false; + + bitvec_set_bit(bv, 1); /* EARFCN: */ + bitvec_set_uint(bv, e->arfcn[i], 16); + + if (OSMO_EARFCN_MEAS_INVALID == e->meas_bw[i]) + bitvec_set_bit(bv, 0); + else { /* Measurement Bandwidth: 9.1.54 */ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, e->meas_bw[i], 3); + } + } + } + } + } + + /* stop bit - end of EARFCN + Measurement Bandwidth sequence */ + bitvec_set_bit(bv, 0); + + /* Note: we don't support different EARFCN arrays each with different priority, threshold etc. */ + + if (e->prio_valid) { + /* E-UTRAN_PRIORITY: 3GPP TS 45.008*/ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, e->prio, 3); + } else + bitvec_set_bit(bv, 0); + + /* THRESH_E-UTRAN_high */ + bitvec_set_uint(bv, e->thresh_hi, 5); + + if (e->thresh_lo_valid) { + /* THRESH_E-UTRAN_low: */ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, e->thresh_lo, 5); + } else + bitvec_set_bit(bv, 0); + + if (e->qrxlm_valid) { + /* E-UTRAN_QRXLEVMIN: */ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, e->qrxlm, 5); + } else + bitvec_set_bit(bv, 0); + + return true; +} + +static inline void append_earfcn(struct bitvec *bv, struct gsm_bts *bts, uint8_t budget) +{ + bool appended; + unsigned int old = bv->cur_bit; /* save current position to make rollback possible */ + int rem = budget - 25; + if (rem <= 0) + return; + + OSMO_ASSERT(budget <= SI2Q_MAX_LEN); + + /* Additions in Rel-5: */ + bitvec_set_bit(bv, H); + /* No 3G Additional Measurement Param. Descr. */ + bitvec_set_bit(bv, 0); + /* No 3G ADDITIONAL MEASUREMENT Param. Descr. 2 */ + bitvec_set_bit(bv, 0); + /* Additions in Rel-6: */ + bitvec_set_bit(bv, H); + /* 3G_CCN_ACTIVE */ + bitvec_set_bit(bv, 0); + /* Additions in Rel-7: */ + bitvec_set_bit(bv, H); + /* No 700_REPORTING_OFFSET */ + bitvec_set_bit(bv, 0); + /* No 810_REPORTING_OFFSET */ + bitvec_set_bit(bv, 0); + /* Additions in Rel-8: */ + bitvec_set_bit(bv, H); + + /* Priority and E-UTRAN Parameters Description */ + bitvec_set_bit(bv, 1); + + /* No Serving Cell Priority Parameters Descr. */ + bitvec_set_bit(bv, 0); + /* No 3G Priority Parameters Description */ + bitvec_set_bit(bv, 0); + /* E-UTRAN Parameters Description */ + bitvec_set_bit(bv, 1); + + /* E-UTRAN_CCN_ACTIVE */ + bitvec_set_bit(bv, 0); + /* E-UTRAN_Start: 9.1.54 */ + bitvec_set_bit(bv, 1); + /* E-UTRAN_Stop: 9.1.54 */ + bitvec_set_bit(bv, 1); + + /* No E-UTRAN Measurement Parameters Descr. */ + bitvec_set_bit(bv, 0); + /* No GPRS E-UTRAN Measurement Param. Descr. */ + bitvec_set_bit(bv, 0); + + /* Note: each of next 3 "repeated" structures might be repeated any + (0, 1, 2...) times - we only support 1 and 0 */ + + /* Repeated E-UTRAN Neighbour Cells */ + bitvec_set_bit(bv, 1); + + appended = append_eutran_neib_cell(bv, bts, rem); + if (!appended) { /* appending is impossible within current budget: rollback */ + bv->cur_bit = old; + return; + } + + /* stop bit - end of Repeated E-UTRAN Neighbour Cells sequence: */ + bitvec_set_bit(bv, 0); + + /* Note: following 2 repeated structs are not supported ATM */ + /* stop bit - end of Repeated E-UTRAN Not Allowed Cells sequence: */ + bitvec_set_bit(bv, 0); + /* stop bit - end of Repeated E-UTRAN PCID to TA mapping sequence: */ + bitvec_set_bit(bv, 0); + + /* Priority and E-UTRAN Parameters Description ends here */ + /* No 3G CSG Description */ + bitvec_set_bit(bv, 0); + /* No E-UTRAN CSG Description */ + bitvec_set_bit(bv, 0); + /* No Additions in Rel-9: */ + bitvec_set_bit(bv, L); +} + +static inline int f0_helper(int *sc, size_t length, uint8_t *chan_list) +{ + int w[RANGE_ENC_MAX_ARFCNS] = { 0 }; + + return range_encode(ARFCN_RANGE_1024, sc, length, w, 0, chan_list); +} + +/* Estimate how many bits it'll take to append single FDD UARFCN */ +static inline int append_utran_fdd_length(uint16_t u, const int *sc, size_t sc_len, size_t length) +{ + uint8_t chan_list[16] = { 0 }; + int tmp[sc_len], f0; + + memcpy(tmp, sc, sizeof(tmp)); + + f0 = f0_helper(tmp, length, chan_list); + if (f0 < 0) + return f0; + + return 21 + range1024_p(length); +} + +/* Append single FDD UARFCN */ +static inline int append_utran_fdd(struct bitvec *bv, uint16_t u, int *sc, size_t length) +{ + uint8_t chan_list[16] = { 0 }; + int f0 = f0_helper(sc, length, chan_list); + + if (f0 < 0) + return f0; + + /* Repeated UTRAN FDD Neighbour Cells */ + bitvec_set_bit(bv, 1); + + /* FDD-ARFCN */ + bitvec_set_bit(bv, 0); + bitvec_set_uint(bv, u, 14); + + /* FDD_Indic0: parameter value '0000000000' is a member of the set? */ + bitvec_set_bit(bv, f0); + /* NR_OF_FDD_CELLS */ + bitvec_set_uint(bv, length, 5); + + f0 = bv->cur_bit; + bitvec_add_range1024(bv, (struct gsm48_range_1024 *)chan_list); + bv->cur_bit = f0 + range1024_p(length); + + return 21 + range1024_p(length); +} + +static inline int try_adding_uarfcn(struct bitvec *bv, struct gsm_bts *bts, uint16_t uarfcn, + uint8_t num_sc, uint8_t start_pos, uint8_t budget) +{ + int i, k, rc, a[bts->si_common.uarfcn_length]; + + if (budget < 23) + return -ENOMEM; + + /* copy corresponding Scrambling Codes: range encoder make in-place modifications */ + for (i = start_pos, k = 0; i < num_sc; a[k++] = bts->si_common.data.scramble_list[i++]); + + /* estimate bit length requirements */ + rc = append_utran_fdd_length(uarfcn, a, bts->si_common.uarfcn_length, k); + if (rc < 0) + return rc; /* range encoder failure */ + + if (budget - rc <= 0) + return -ENOMEM; /* we have ran out of budget in current SI2q */ + + /* compute next offset */ + bts->u_offset += k; + + return budget - append_utran_fdd(bv, uarfcn, a, k); +} + +/* Append multiple FDD UARFCNs */ +static inline void append_uarfcns(struct bitvec *bv, struct gsm_bts *bts, uint8_t budget) +{ + const uint16_t *u = bts->si_common.data.uarfcn_list; + int i, rem = budget - 7, st = bts->u_offset; /* account for constant bits right away */ + uint16_t cu = u[bts->u_offset]; /* caller ensures that length is positive */ + + OSMO_ASSERT(budget <= SI2Q_MAX_LEN); + + if (budget <= 7) + return; + + /* 3G Neighbour Cell Description */ + bitvec_set_bit(bv, 1); + /* No Index_Start_3G */ + bitvec_set_bit(bv, 0); + /* No Absolute_Index_Start_EMR */ + bitvec_set_bit(bv, 0); + + /* UTRAN FDD Description */ + bitvec_set_bit(bv, 1); + /* No Bandwidth_FDD */ + bitvec_set_bit(bv, 0); + + for (i = bts->u_offset; i <= bts->si_common.uarfcn_length; i++) + if (u[i] != cu) { /* we've reached new UARFCN */ + rem = try_adding_uarfcn(bv, bts, cu, i, st, rem); + if (rem < 0) + break; + + if (i < bts->si_common.uarfcn_length) { + cu = u[i]; + st = i; + } else + break; + } + + /* stop bit - end of Repeated UTRAN FDD Neighbour Cells */ + bitvec_set_bit(bv, 0); + + /* UTRAN TDD Description */ + bitvec_set_bit(bv, 0); +} + +/* generate SI2quater rest octets: 3GPP TS 44.018 ยง 10.5.2.33b */ +int rest_octets_si2quater(uint8_t *data, struct gsm_bts *bts) +{ + int rc; + struct bitvec bv; + + if (bts->si2q_count < bts->si2q_index) + return -EINVAL; + + bv.data = data; + bv.data_len = 20; + bitvec_zero(&bv); + + /* BA_IND: Set to '0' as that's what we use for SI2xxx type, + * whereas '1' is used for SI5xxx type messages. The point here + * is to be able to correlate whether a given MS measurement + * report was using the neighbor cells advertised in SI2 or in + * SI5, as those two could very well be different */ + bitvec_set_bit(&bv, 0); + /* 3G_BA_IND */ + bitvec_set_bit(&bv, 1); + /* MP_CHANGE_MARK */ + bitvec_set_bit(&bv, 0); + + /* SI2quater_INDEX */ + bitvec_set_uint(&bv, bts->si2q_index, 4); + /* SI2quater_COUNT */ + bitvec_set_uint(&bv, bts->si2q_count, 4); + + /* No Measurement_Parameters Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_Real Time Difference Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_BSIC Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_REPORT PRIORITY Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_MEASUREMENT_Parameters Description */ + bitvec_set_bit(&bv, 0); + /* No NC Measurement Parameters */ + bitvec_set_bit(&bv, 0); + /* No extension (length) */ + bitvec_set_bit(&bv, 0); + + rc = SI2Q_MAX_LEN - (bv.cur_bit + 3); + if (rc > 0 && bts->si_common.uarfcn_length - bts->u_offset > 0) + append_uarfcns(&bv, bts, rc); + else /* No 3G Neighbour Cell Description */ + bitvec_set_bit(&bv, 0); + + /* No 3G Measurement Parameters Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_3G_MEASUREMENT Parameters Descr. */ + bitvec_set_bit(&bv, 0); + + rc = SI2Q_MAX_LEN - bv.cur_bit; + if (rc > 0 && si2q_earfcn_count(&bts->si_common.si2quater_neigh_list) - bts->e_offset > 0) + append_earfcn(&bv, bts, rc); + else /* No Additions in Rel-5: */ + bitvec_set_bit(&bv, L); + + bitvec_spare_padding(&bv, (bv.data_len * 8) - 1); + return bv.data_len; +} + +/* Append selection parameters to bitvec */ +static void append_selection_params(struct bitvec *bv, + const struct gsm48_si_selection_params *sp) +{ + if (sp->present) { + bitvec_set_bit(bv, H); + bitvec_set_bit(bv, sp->cbq); + bitvec_set_uint(bv, sp->cell_resel_off, 6); + bitvec_set_uint(bv, sp->temp_offs, 3); + bitvec_set_uint(bv, sp->penalty_time, 5); + } else + bitvec_set_bit(bv, L); +} + +/* Append power offset to bitvec */ +static void append_power_offset(struct bitvec *bv, + const struct gsm48_si_power_offset *po) +{ + if (po->present) { + bitvec_set_bit(bv, H); + bitvec_set_uint(bv, po->power_offset, 2); + } else + bitvec_set_bit(bv, L); +} + +/* Append GPRS indicator to bitvec */ +static void append_gprs_ind(struct bitvec *bv, + const struct gsm48_si3_gprs_ind *gi) +{ + if (gi->present) { + bitvec_set_bit(bv, H); + bitvec_set_uint(bv, gi->ra_colour, 3); + /* 0 == SI13 in BCCH Norm, 1 == SI13 sent on BCCH Ext */ + bitvec_set_bit(bv, gi->si13_position); + } else + bitvec_set_bit(bv, L); +} + +/* Generate SI2ter Rest Octests 3GPP TS 44.018 Table 10.5.2.33a.1 */ +int rest_octets_si2ter(uint8_t *data) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 4; + + /* No SI2ter_MP_CHANGE_MARK */ + bitvec_set_bit(&bv, L); + + bitvec_spare_padding(&bv, (bv.data_len * 8) - 1); + + return bv.data_len; +} + +/* Generate SI2bis Rest Octests 3GPP TS 44.018 Table 10.5.2.33.1 */ +int rest_octets_si2bis(uint8_t *data) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 1; + + bitvec_spare_padding(&bv, (bv.data_len * 8) - 1); + + return bv.data_len; +} + +/* Generate SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */ +int rest_octets_si3(uint8_t *data, const struct gsm48_si_ro_info *si3) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 4; + + /* Optional Selection Parameters */ + append_selection_params(&bv, &si3->selection_params); + + /* Optional Power Offset */ + append_power_offset(&bv, &si3->power_offset); + + /* Do we have a SI2ter on the BCCH? */ + if (si3->si2ter_indicator) + bitvec_set_bit(&bv, H); + else + bitvec_set_bit(&bv, L); + + /* Early Classmark Sending Control */ + if (si3->early_cm_ctrl) + bitvec_set_bit(&bv, H); + else + bitvec_set_bit(&bv, L); + + /* Do we have a SI Type 9 on the BCCH? */ + if (si3->scheduling.present) { + bitvec_set_bit(&bv, H); + bitvec_set_uint(&bv, si3->scheduling.where, 3); + } else + bitvec_set_bit(&bv, L); + + /* GPRS Indicator */ + append_gprs_ind(&bv, &si3->gprs_ind); + + /* 3G Early Classmark Sending Restriction. If H, then controlled by + * early_cm_ctrl above */ + if (si3->early_cm_restrict_3g) + bitvec_set_bit(&bv, L); + else + bitvec_set_bit(&bv, H); + + if (si3->si2quater_indicator) { + bitvec_set_bit(&bv, H); /* indicator struct present */ + bitvec_set_uint(&bv, 0, 1); /* message is sent on BCCH Norm */ + } + + bitvec_spare_padding(&bv, (bv.data_len*8)-1); + return bv.data_len; +} + +static int append_lsa_params(struct bitvec *bv, + const struct gsm48_lsa_params *lsa_params) +{ + /* FIXME */ + return -1; +} + +/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */ +int rest_octets_si4(uint8_t *data, const struct gsm48_si_ro_info *si4, int len) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = len; + + /* SI4 Rest Octets O */ + append_selection_params(&bv, &si4->selection_params); + append_power_offset(&bv, &si4->power_offset); + append_gprs_ind(&bv, &si4->gprs_ind); + + if (0 /* FIXME */) { + /* H and SI4 Rest Octets S */ + bitvec_set_bit(&bv, H); + + /* LSA Parameters */ + if (si4->lsa_params.present) { + bitvec_set_bit(&bv, H); + append_lsa_params(&bv, &si4->lsa_params); + } else + bitvec_set_bit(&bv, L); + + /* Cell Identity */ + if (1) { + bitvec_set_bit(&bv, H); + bitvec_set_uint(&bv, si4->cell_id, 16); + } else + bitvec_set_bit(&bv, L); + + /* LSA ID Information */ + if (0) { + bitvec_set_bit(&bv, H); + /* FIXME */ + } else + bitvec_set_bit(&bv, L); + } else { + /* L and break indicator */ + bitvec_set_bit(&bv, L); + bitvec_set_bit(&bv, si4->break_ind ? H : L); + } + + return bv.data_len; +} + + +/* GSM 04.18 ETSI TS 101 503 V8.27.0 (2006-05) + + ::= +{L | H } +{L | H } +{ < DTM_support : bit == L > I < DTM_support : bit == H > +< RAC : bit (8) > +< MAX_LAPDm : bit (3) > } +< Band indicator > +{ L | H < GPRS_MS_TXPWR_MAX_CCH : bit (5) > } +; +*/ +int rest_octets_si6(uint8_t *data, bool is1800_net) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 1; + + /* no PCH/NCH info */ + bitvec_set_bit(&bv, L); + /* no VBS/VGCS options */ + bitvec_set_bit(&bv, L); + /* no DTM_support */ + bitvec_set_bit(&bv, L); + /* band indicator */ + if (is1800_net) + bitvec_set_bit(&bv, L); + else + bitvec_set_bit(&bv, H); + /* no GPRS_MS_TXPWR_MAX_CCH */ + bitvec_set_bit(&bv, L); + + bitvec_spare_padding(&bv, (bv.data_len * 8) - 1); + return bv.data_len; +} + +/* GPRS Mobile Allocation as per TS 04.60 Chapter 12.10a: + < GPRS Mobile Allocation IE > ::= + < HSN : bit (6) > + { 0 | 1 < RFL number list : < RFL number list struct > > } + { 0 < MA_LENGTH : bit (6) > + < MA_BITMAP: bit (val(MA_LENGTH) + 1) > + | 1 { 0 | 1 > } } ; + + < RFL number list struct > :: = + < RFL_NUMBER : bit (4) > + { 0 | 1 < RFL number list struct > } ; + < ARFCN index list struct > ::= + < ARFCN_INDEX : bit(6) > + { 0 | 1 < ARFCN index list struct > } ; + */ +static int append_gprs_mobile_alloc(struct bitvec *bv) +{ + /* Hopping Sequence Number */ + bitvec_set_uint(bv, 0, 6); + + if (0) { + /* We want to use a RFL number list */ + bitvec_set_bit(bv, 1); + /* FIXME: RFL number list */ + } else + bitvec_set_bit(bv, 0); + + if (0) { + /* We want to use a MA_BITMAP */ + bitvec_set_bit(bv, 0); + /* FIXME: MA_LENGTH, MA_BITMAP, ... */ + } else { + bitvec_set_bit(bv, 1); + if (0) { + /* We want to provide an ARFCN index list */ + bitvec_set_bit(bv, 1); + /* FIXME */ + } else + bitvec_set_bit(bv, 0); + } + return 0; +} + +static int encode_t3192(unsigned int t3192) +{ + /* See also 3GPP TS 44.060 + Table 12.24.2: GPRS Cell Options information element details */ + if (t3192 == 0) + return 3; + else if (t3192 <= 80) + return 4; + else if (t3192 <= 120) + return 5; + else if (t3192 <= 160) + return 6; + else if (t3192 <= 200) + return 7; + else if (t3192 <= 500) + return 0; + else if (t3192 <= 1000) + return 1; + else if (t3192 <= 1500) + return 2; + else + return -EINVAL; +} + +static int encode_drx_timer(unsigned int drx) +{ + if (drx == 0) + return 0; + else if (drx == 1) + return 1; + else if (drx == 2) + return 2; + else if (drx <= 4) + return 3; + else if (drx <= 8) + return 4; + else if (drx <= 16) + return 5; + else if (drx <= 32) + return 6; + else if (drx <= 64) + return 7; + else + return -EINVAL; +} + +/* GPRS Cell Options as per TS 04.60 Chapter 12.24 + < GPRS Cell Options IE > ::= + < NMO : bit(2) > + < T3168 : bit(3) > + < T3192 : bit(3) > + < DRX_TIMER_MAX: bit(3) > + < ACCESS_BURST_TYPE: bit > + < CONTROL_ACK_TYPE : bit > + < BS_CV_MAX: bit(4) > + { 0 | 1 < PAN_DEC : bit(3) > + < PAN_INC : bit(3) > + < PAN_MAX : bit(3) > + { 0 | 1 < Extension Length : bit(6) > + < bit (val(Extension Length) + 1 + & { < Extension Information > ! { bit ** = } } ; + < Extension Information > ::= + { 0 | 1 < EGPRS_PACKET_CHANNEL_REQUEST : bit > + < BEP_PERIOD : bit(4) > } + < PFC_FEATURE_MODE : bit > + < DTM_SUPPORT : bit > + + ** ; + */ +static int append_gprs_cell_opt(struct bitvec *bv, + const struct gprs_cell_options *gco) +{ + int t3192, drx_timer_max; + + t3192 = encode_t3192(gco->t3192); + if (t3192 < 0) + return t3192; + + drx_timer_max = encode_drx_timer(gco->drx_timer_max); + if (drx_timer_max < 0) + return drx_timer_max; + + bitvec_set_uint(bv, gco->nmo, 2); + + /* See also 3GPP TS 44.060 + Table 12.24.2: GPRS Cell Options information element details */ + bitvec_set_uint(bv, gco->t3168 / 500 - 1, 3); + + bitvec_set_uint(bv, t3192, 3); + bitvec_set_uint(bv, drx_timer_max, 3); + /* ACCESS_BURST_TYPE: Hard-code 8bit */ + bitvec_set_bit(bv, 0); + /* CONTROL_ACK_TYPE: */ + bitvec_set_bit(bv, gco->ctrl_ack_type_use_block); + bitvec_set_uint(bv, gco->bs_cv_max, 4); + + if (0) { + /* hard-code no PAN_{DEC,INC,MAX} */ + bitvec_set_bit(bv, 0); + } else { + /* copied from ip.access BSC protocol trace */ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, 1, 3); /* DEC */ + bitvec_set_uint(bv, 1, 3); /* INC */ + bitvec_set_uint(bv, 15, 3); /* MAX */ + } + + if (!gco->ext_info_present) { + /* no extension information */ + bitvec_set_bit(bv, 0); + } else { + /* extension information */ + bitvec_set_bit(bv, 1); + if (!gco->ext_info.egprs_supported) { + /* 6bit length of extension */ + bitvec_set_uint(bv, (1 + 3)-1, 6); + /* EGPRS supported in the cell */ + bitvec_set_bit(bv, 0); + } else { + /* 6bit length of extension */ + bitvec_set_uint(bv, (1 + 5 + 3)-1, 6); + /* EGPRS supported in the cell */ + bitvec_set_bit(bv, 1); + + /* 1bit EGPRS PACKET CHANNEL REQUEST */ + if (gco->supports_egprs_11bit_rach == 0) { + bitvec_set_bit(bv, + gco->ext_info.use_egprs_p_ch_req); + } else { + bitvec_set_bit(bv, 0); + } + + /* 4bit BEP PERIOD */ + bitvec_set_uint(bv, gco->ext_info.bep_period, 4); + } + bitvec_set_bit(bv, gco->ext_info.pfc_supported); + bitvec_set_bit(bv, gco->ext_info.dtm_supported); + bitvec_set_bit(bv, gco->ext_info.bss_paging_coordination); + } + + return 0; +} + +static void append_gprs_pwr_ctrl_pars(struct bitvec *bv, + const struct gprs_power_ctrl_pars *pcp) +{ + bitvec_set_uint(bv, pcp->alpha, 4); + bitvec_set_uint(bv, pcp->t_avg_w, 5); + bitvec_set_uint(bv, pcp->t_avg_t, 5); + bitvec_set_uint(bv, pcp->pc_meas_chan, 1); + bitvec_set_uint(bv, pcp->n_avg_i, 4); +} + +/* Generate SI13 Rest Octests (04.08 Chapter 10.5.2.37b) */ +int rest_octets_si13(uint8_t *data, const struct gsm48_si13_info *si13) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 20; + + if (0) { + /* No rest octets */ + bitvec_set_bit(&bv, L); + } else { + bitvec_set_bit(&bv, H); + bitvec_set_uint(&bv, si13->bcch_change_mark, 3); + bitvec_set_uint(&bv, si13->si_change_field, 4); + if (1) { + bitvec_set_bit(&bv, 0); + } else { + bitvec_set_bit(&bv, 1); + bitvec_set_uint(&bv, si13->bcch_change_mark, 2); + append_gprs_mobile_alloc(&bv); + } + /* PBCCH not present in cell: + it shall never be indicated according to 3GPP TS 44.018 Table 10.5.2.37b.1 */ + bitvec_set_bit(&bv, 0); + bitvec_set_uint(&bv, si13->rac, 8); + bitvec_set_bit(&bv, si13->spgc_ccch_sup); + bitvec_set_uint(&bv, si13->prio_acc_thr, 3); + bitvec_set_uint(&bv, si13->net_ctrl_ord, 2); + append_gprs_cell_opt(&bv, &si13->cell_opts); + append_gprs_pwr_ctrl_pars(&bv, &si13->pwr_ctrl_pars); + + /* 3GPP TS 44.018 Release 6 / 10.5.2.37b */ + bitvec_set_bit(&bv, H); /* added Release 99 */ + /* claim our SGSN is compatible with Release 99, as EDGE and EGPRS + * was only added in this Release */ + bitvec_set_bit(&bv, 1); + } + bitvec_spare_padding(&bv, (bv.data_len*8)-1); + return bv.data_len; +} -- cgit v1.2.3