From f326267fb7c146a73d93a50e670ea95a2c47f0c1 Mon Sep 17 00:00:00 2001 From: Steffen Neubauer Date: Thu, 26 Nov 2009 12:28:41 +0100 Subject: [SMS] Implement TP-VPF-ENHANCED While doing so, we also restructure/reorganize the vailidity period parsing in general. --- openbsc/src/gsm_04_11.c | 249 ++++++++++++++++++++++++++++++------------------ 1 file changed, 156 insertions(+), 93 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 75ddf9dd9..8e3c64974 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -198,48 +198,172 @@ static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans, return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA); } -static time_t gsm340_scts(u_int8_t *scts); +/* Turn int into semi-octet representation: 98 => 0x89 */ +static u_int8_t bcdify(u_int8_t value) +{ + u_int8_t ret; -static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) + ret = value / 10; + ret |= (value % 10) << 4; + + return ret; +} + +/* Turn semi-octet representation into int: 0x89 => 98 */ +static u_int8_t unbcdify(u_int8_t value) +{ + u_int8_t ret; + + if ((value & 0x0F) > 9 || (value >> 4) > 9) + DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); + + ret = (value&0x0F)*10; + if (ret > 90) + ret += value>>4; + + return ret; +} + +/* Generate 03.40 TP-SCTS */ +static void gsm340_gen_scts(u_int8_t *scts, time_t time) +{ + struct tm *tm = localtime(&time); + + *scts++ = bcdify(tm->tm_year % 100); + *scts++ = bcdify(tm->tm_mon + 1); + *scts++ = bcdify(tm->tm_mday); + *scts++ = bcdify(tm->tm_hour); + *scts++ = bcdify(tm->tm_min); + *scts++ = bcdify(tm->tm_sec); + *scts++ = bcdify(tm->tm_gmtoff/(60*15)); +} + +/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */ +static time_t gsm340_scts(u_int8_t *scts) +{ + struct tm tm; + + u_int8_t yr = unbcdify(*scts++); + + if (yr <= 80) + tm.tm_year = 100 + yr; + else + tm.tm_year = yr; + tm.tm_mon = unbcdify(*scts++) - 1; + tm.tm_mday = unbcdify(*scts++); + tm.tm_hour = unbcdify(*scts++); + tm.tm_min = unbcdify(*scts++); + tm.tm_sec = unbcdify(*scts++); + /* according to gsm 03.40 time zone is + "expressed in quarters of an hour" */ + tm.tm_gmtoff = unbcdify(*scts++) * 15*60; + + return mktime(&tm); +} + +/* Return the default validity period in minutes */ +static unsigned long gsm340_vp_default(void) +{ + unsigned long minutes; + /* Default validity: two days */ + minutes = 24 * 60 * 2; + return minutes; +} + +/* Decode validity period format 'relative' */ +static unsigned long gsm340_vp_relative(u_int8_t *sms_vp) +{ + /* Chapter 9.2.3.12.1 */ + u_int8_t vp; + unsigned long minutes; + + vp = *(sms_vp); + if (vp <= 143) + minutes = vp + 1 * 5; + else if (vp <= 167) + minutes = 12*60 + (vp-143) * 30; + else if (vp <= 196) + minutes = vp-166 * 60 * 24; + else + minutes = vp-192 * 60 * 24 * 7; + return minutes; +} + +/* Decode validity period format 'absolute' */ +static unsigned long gsm340_vp_absolute(u_int8_t *sms_vp) +{ + /* Chapter 9.2.3.12.2 */ + time_t expires, now; + unsigned long minutes; + + expires = gsm340_scts(sms_vp); + now = mktime(gmtime(NULL)); + if (expires <= now) + minutes = 0; + else + minutes = (expires-now)/60; + return minutes; +} + +/* Decode validity period format 'relative in integer representation' */ +static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp) { u_int8_t vp; unsigned long minutes; - time_t expires; - time_t now; + vp = *(sms_vp); + if (vp == 0) { + DEBUGP(DSMS, "reserved relative_integer validity period\n"); + return gsm340_vp_default(); + } + minutes = vp/60; + return minutes; +} + +/* Decode validity period format 'relative in semi-octet representation' */ +static unsigned long gsm340_vp_relative_semioctet(u_int8_t *sms_vp) +{ + unsigned long minutes; + minutes = unbcdify(*sms_vp++)*60; /* hours */ + minutes += unbcdify(*sms_vp++); /* minutes */ + minutes += unbcdify(*sms_vp++)/60; /* seconds */ + return minutes; +} + +/* decode validity period. return minutes */ +static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) +{ + u_int8_t fi; /* functionality indicator */ switch (sms_vpf) { case GSM340_TP_VPF_RELATIVE: - /* Chapter 9.2.3.12.1 */ - vp = *(sms_vp); - if (vp <= 143) - minutes = vp + 1 * 5; - else if (vp <= 167) - minutes = 12*60 + (vp-143) * 30; - else if (vp <= 196) - minutes = vp-166 * 60 * 24; - else - minutes = vp-192 * 60 * 24 * 7; - break; + return gsm340_vp_relative(sms_vp); case GSM340_TP_VPF_ABSOLUTE: - /* Chapter 9.2.3.12.2 */ - expires = gsm340_scts(sms_vp); - now = mktime(gmtime(NULL)); - if (expires <= now) - minutes = 0; - else - minutes = (expires-now)/60; - break; + return gsm340_vp_absolute(sms_vp); case GSM340_TP_VPF_ENHANCED: /* Chapter 9.2.3.12.3 */ - /* FIXME: implementation */ - DEBUGP(DSMS, "VPI enhanced not implemented yet\n"); - break; + fi = *sms_vp++; + /* ignore additional fi */ + if (fi & (1<<7)) sms_vp++; + /* read validity period format */ + switch (fi & 0b111) { + case 0b000: + return gsm340_vp_default(); /* no vpf specified */ + case 0b001: + return gsm340_vp_relative(sms_vp); + case 0b010: + return gsm340_vp_relative_integer(sms_vp); + case 0b011: + return gsm340_vp_relative_semioctet(sms_vp); + default: + /* The GSM spec says that the SC should reject any + unsupported and/or undefined values. FIXME */ + DEBUGP(DSMS, "Reserved enhanced validity period format\n"); + return gsm340_vp_default(); + } case GSM340_TP_VPF_NONE: - /* Default validity: two days */ - minutes = 24 * 60 * 2; - break; + default: + return gsm340_vp_default(); } - return minutes; } /* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */ @@ -307,69 +431,6 @@ static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len, return len_in_bytes; } -/* Turn int into semi-octet representation: 98 => 0x89 */ -static u_int8_t bcdify(u_int8_t value) -{ - u_int8_t ret; - - ret = value / 10; - ret |= (value % 10) << 4; - - return ret; -} - -/* Turn semi-octet representation into int: 0x89 => 98 */ -static u_int8_t unbcdify(u_int8_t value) -{ - u_int8_t ret; - - if ((value & 0x0F) > 9 || (value >> 4) > 9) - DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); - - ret = (value&0x0F)*10; - if (ret > 90) - ret += value>>4; - - return ret; -} - -/* Generate 03.40 TP-SCTS */ -static void gsm340_gen_scts(u_int8_t *scts, time_t time) -{ - struct tm *tm = localtime(&time); - - *scts++ = bcdify(tm->tm_year % 100); - *scts++ = bcdify(tm->tm_mon + 1); - *scts++ = bcdify(tm->tm_mday); - *scts++ = bcdify(tm->tm_hour); - *scts++ = bcdify(tm->tm_min); - *scts++ = bcdify(tm->tm_sec); - *scts++ = bcdify(tm->tm_gmtoff/(60*15)); -} - -/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */ -static time_t gsm340_scts(u_int8_t *scts) -{ - struct tm tm; - - u_int8_t yr = unbcdify(*scts++); - - if (yr <= 80) - tm.tm_year = 100 + yr; - else - tm.tm_year = yr; - tm.tm_mon = unbcdify(*scts++) - 1; - tm.tm_mday = unbcdify(*scts++); - tm.tm_hour = unbcdify(*scts++); - tm.tm_min = unbcdify(*scts++); - tm.tm_sec = unbcdify(*scts++); - /* according to gsm 03.40 time zone is - "expressed in quarters of an hour" */ - tm.tm_gmtoff = unbcdify(*scts++) * 15*60; - - return mktime(&tm); -} - /* generate a msgb containing a TPDU derived from struct gsm_sms, * returns total size of TPDU */ static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms) @@ -499,6 +560,8 @@ static int gsm340_rx_tpdu(struct msgb *msg) case GSM340_TP_VPF_ABSOLUTE: case GSM340_TP_VPF_ENHANCED: sms_vp = smsp; + /* the additional functionality indicator... */ + if (*smsp & (1<<7)) smsp++; smsp += 7; break; case GSM340_TP_VPF_NONE: -- cgit v1.2.3 From 1a79d364401dfad2a71f1e61ff13a3861e3da46e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 27 Nov 2009 08:55:16 +0100 Subject: RSL: catch inconsistent parameters ofr channel_mode_from_lchan() --- openbsc/src/abis_rsl.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 692536c50..219b01aa0 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -488,6 +488,11 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, /* set TCH Speech/Data */ cm->spd_ind = lchan->rsl_cmode; + if (lchan->rsl_cmode == RSL_CMOD_SPD_SIGN && + lchan->tch_mode != GSM48_CMODE_SIGN) + DEBUGP(DRSL, "unsupported: rsl_mode == signalling, " + "but tch_mode != signalling\n"); + switch (lchan->type) { case GSM_LCHAN_SDCCH: cm->chan_rt = RSL_CMOD_CRT_SDCCH; -- cgit v1.2.3 From 3c7dc6ed50e8baa05a8aea26c72319530e747317 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 19:07:28 +0100 Subject: New complete measurement result/report handling This patch extends struct gsm_meas_rep into a complete structure containing all information from both uplink and downlink measurement results/reports. This is a first step to provide this complete measurement data as a C structure into a to-be-implemented handover decision algorithm. --- openbsc/src/abis_rsl.c | 112 ++++++++++++++++++++++++++++++++++++------------ openbsc/src/gsm_04_08.c | 60 ++++++++++++-------------- 2 files changed, 111 insertions(+), 61 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 219b01aa0..743dc5f2b 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -38,6 +38,7 @@ #include #include #include +#include #define RSL_ALLOC_SIZE 1024 #define RSL_ALLOC_HEADROOM 128 @@ -949,47 +950,102 @@ static int rsl_rx_conn_fail(struct msgb *msg) return rsl_rf_chan_release(msg->lchan); } +static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru, + const char *prefix) +{ + DEBUGPC(DMEAS, "RXL-FULL-%s=%d RXL-SUB-%s=%d ", + prefix, mru->full.rx_lev, prefix, mru->sub.rx_lev); + DEBUGPC(DMEAS, "RXQ-FULL-%s=%d RXQ-SUB-%s=%d ", + prefix, mru->full.rx_qual, prefix, mru->sub.rx_qual); +} + +static void print_meas_rep(struct gsm_meas_rep *mr) +{ + DEBUGP(DMEAS, "MEASUREMENT RESULT NR=%d ", mr->nr); + + if (mr->flags & MEAS_REP_F_DL_DTX) + DEBUGPC(DMEAS, "DTXd "); + + print_meas_rep_uni(&mr->ul, "ul"); + DEBUGPC(DMEAS, "BS_POWER=%d ", mr->bs_power); + if (mr->flags & MEAS_REP_F_MS_TO) + DEBUGPC(DMEAS, "MS_TO=%d ", mr->ms_timing_offset); + + if (mr->flags & MEAS_REP_F_MS_L1) { + DEBUGPC(DMEAS, "L1_MS_PWR=%ddBm ", mr->ms_l1.pwr); + DEBUGPC(DMEAS, "L1_FPC=%u ", + mr->flags & MEAS_REP_F_FPC ? 1 : 0); + DEBUGPC(DMEAS, "L1_TA=%u ", mr->ms_l1.ta); + } + + if (mr->flags & MEAS_REP_F_UL_DTX) + DEBUGPC(DMEAS, "DTXu "); + if (mr->flags & MEAS_REP_F_BA1) + DEBUGPC(DMEAS, "BA1 "); + if (!(mr->flags & MEAS_REP_F_DL_VALID)) + DEBUGPC(DMEAS, "NOT VALID "); + else + print_meas_rep_uni(&mr->dl, "dl"); + + DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", mr->num_cell); +} + static int rsl_rx_meas_res(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; + struct gsm_meas_rep mr; + u_int8_t len; + const u_int8_t *val; + int rc; + + memset(&mr, 0, sizeof(mr)); - DEBUGPC(DMEAS, "MEASUREMENT RESULT "); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); - if (TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR)) - DEBUGPC(DMEAS, "NR=%d ", *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR)); - if (TLVP_PRESENT(&tp, RSL_IE_UPLINK_MEAS)) { - u_int8_t len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS); - const u_int8_t *val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS); - if (len >= 3) { - if (val[0] & 0x40) - DEBUGPC(DMEAS, "DTXd "); - DEBUGPC(DMEAS, "RXL-FULL-up=%d RXL-SUB-up=%d ", - val[0] & 0x3f, val[1] & 0x3f); - DEBUGPC(DMEAS, "RXQ-FULL-up=%d RXQ-SUB-up=%d ", - val[2]>>3 & 0x7, val[2] & 0x7); - } + if (!TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR) || + !TLVP_PRESENT(&tp, RSL_IE_UPLINK_MEAS) || + !TLVP_PRESENT(&tp, RSL_IE_BS_POWER)) + return -EIO; + + /* Mandatory Parts */ + mr.nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR); + + len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS); + val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS); + if (len >= 3) { + if (val[0] & 0x40) + mr.flags |= MEAS_REP_F_DL_DTX; + mr.ul.full.rx_lev = val[0] & 0x3f; + mr.ul.sub.rx_lev = val[1] & 0x3f; + mr.ul.full.rx_qual = val[2]>>3 & 0x7; + mr.ul.sub.rx_qual = val[2] & 0x7; } - if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER)) - DEBUGPC(DMEAS, "BS_POWER=%d ", *TLVP_VAL(&tp, RSL_IE_BS_POWER)); + + mr.bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER); + + /* Optional Parts */ if (TLVP_PRESENT(&tp, RSL_IE_MS_TIMING_OFFSET)) - DEBUGPC(DMEAS, "MS_TO=%d ", - *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET)); + mr.ms_timing_offset = + *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET); + if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) { - const u_int8_t *val = TLVP_VAL(&tp, RSL_IE_L1_INFO); - u_int8_t pwr_lvl = val[0] >> 3; - DEBUGPC(DMEAS, "L1_MS_PWR=%ddBm ", - ms_pwr_dbm(msg->trx->bts->band, pwr_lvl)); - DEBUGPC(DMEAS, "L1_FPC=%u ", val[0] & 0x04 ? 1 : 0); - DEBUGPC(DMEAS, "L1_TA=%u ", val[1]); + val = TLVP_VAL(&tp, RSL_IE_L1_INFO); + mr.flags |= MEAS_REP_F_MS_L1; + mr.ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3); + if (val[0] & 0x04) + mr.flags |= MEAS_REP_F_FPC; + mr.ms_l1.ta = val[1]; } if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) { - DEBUGPC(DMEAS, "L3\n"); msg->l3h = (u_int8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO); - return gsm0408_rcvmsg(msg, 0); - } else - DEBUGPC(DMEAS, "\n"); + rc = gsm48_parse_meas_rep(&mr, msg); + if (rc < 0) + return rc; + } + + /* FIXME: do something with the actual result*/ + print_meas_rep(&mr); return 0; } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 1f8235411..c9e543378 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -166,25 +166,30 @@ static const char *rr_cause_name(u_int8_t cause) return strbuf; } -static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data, - int len) +int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) { - memset(rep, 0, sizeof(*rep)); + struct gsm48_hdr *gh = msgb_l3(msg); + unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); + u_int8_t *data = gh->data; + + if (gh->msg_type != GSM48_MT_RR_MEAS_REP) + return -EINVAL; if (data[0] & 0x80) rep->flags |= MEAS_REP_F_BA1; if (data[0] & 0x40) - rep->flags |= MEAS_REP_F_DTX; + rep->flags |= MEAS_REP_F_UL_DTX; if ((data[1] & 0x40) == 0x00) - rep->flags |= MEAS_REP_F_VALID; + rep->flags |= MEAS_REP_F_DL_VALID; + + rep->dl.full.rx_lev = data[0] & 0x3f; + rep->dl.sub.rx_lev = data[1] & 0x3f; + rep->dl.full.rx_qual = (data[3] >> 4) & 0x7; + rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; - rep->rxlev_full = data[0] & 0x3f; - rep->rxlev_sub = data[1] & 0x3f; - rep->rxqual_full = (data[3] >> 4) & 0x7; - rep->rxqual_sub = (data[3] >> 1) & 0x7; rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2); if (rep->num_cell < 1) - return; + return 0; /* an encoding nightmare in perfection */ @@ -192,35 +197,37 @@ static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data, rep->cell[0].bcch_freq = data[5] >> 2; rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5); if (rep->num_cell < 2) - return; + return 0; rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7); rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f; rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4); if (rep->num_cell < 3) - return; + return 0; rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6); rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f; rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3); if (rep->num_cell < 4) - return; + return 0; rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5); rep->cell[3].bcch_freq = data[11] & 0x1f; rep->cell[3].bsic = data[12] >> 2; if (rep->num_cell < 5) - return; + return 0; rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4); rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7); rep->cell[4].bsic = (data[14] >> 1) & 0x3f; if (rep->num_cell < 6) - return; + return 0; rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3); rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6); rep->cell[5].bsic = data[16] & 0x3f; + + return 0; } int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi); @@ -1528,26 +1535,13 @@ static int gsm48_rx_rr_status(struct msgb *msg) static int gsm48_rx_rr_meas_rep(struct msgb *msg) { - struct gsm48_hdr *gh = msgb_l3(msg); - unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); static struct gsm_meas_rep meas_rep; - DEBUGP(DMEAS, "MEASUREMENT REPORT "); - parse_meas_rep(&meas_rep, gh->data, payload_len); - if (meas_rep.flags & MEAS_REP_F_DTX) - DEBUGPC(DMEAS, "DTX "); - if (meas_rep.flags & MEAS_REP_F_BA1) - DEBUGPC(DMEAS, "BA1 "); - if (!(meas_rep.flags & MEAS_REP_F_VALID)) - DEBUGPC(DMEAS, "NOT VALID "); - else - DEBUGPC(DMEAS, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ", - meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub, - meas_rep.rxqual_sub); - - DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", meas_rep.num_cell); - - /* FIXME: put the results somwhere */ + /* This shouldn't actually end up here, as RSL treats + * L3 Info of 08.58 MEASUREMENT REPORT different by calling + * directly into gsm48_parse_meas_rep */ + DEBUGP(DMEAS, "DIRECT GSM48 MEASUREMENT REPORT ?!? "); + gsm48_parse_meas_rep(&meas_rep, msg); return 0; } -- cgit v1.2.3 From ccd5a8892ded0832bd378fb33a24412b92920963 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 20:02:20 +0100 Subject: print debug statement in case of HANDOVER COMPLETE or HANDOVER FAILED --- openbsc/src/gsm_04_08.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index c9e543378..eeeb739f1 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1596,6 +1596,14 @@ static int gsm0408_rcv_rr(struct msgb *msg) DEBUGP(DRR, "CIPHERING MODE COMPLETE\n"); /* FIXME: check for MI (if any) */ break; + case GSM48_MT_RR_HANDO_COMPL: + DEBUGP(DRR, "HANDOVER COMPLETE\n"); + /* FIXME: release old channel */ + break; + case GSM48_MT_RR_HANDO_FAIL: + DEBUGP(DRR, "HANDOVER FAILED\n"); + /* FIXME: release allocated new channel */ + break; default: fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n", gh->msg_type); -- cgit v1.2.3 From 8c83af65c1902811d8e9823153af09cc59f4d9f6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 20:02:53 +0100 Subject: [handover] Implement 04.08 HANDOVER COMMAND This is needed by a yet-to-be-implemented handover algorithm, after it has allocated a new lchan for the MS. Also missing: handling the actual HANDOVER COMPLETE / FAIL messages in response. --- openbsc/src/gsm_04_08_utils.c | 51 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index ad038fba6..d3e4689b5 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -519,6 +519,50 @@ int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv) return rsl_encryption_cmd(msg); } +static void gsm48_cell_desc(struct gsm48_cell_desc *cd, + const struct gsm_bts *bts) +{ + cd->ncc = (bts->bsic >> 3 & 0x7); + cd->bcc = (bts->bsic & 0x7); + cd->arfcn_hi = bts->c0->arfcn >> 8; + cd->arfcn_lo = bts->c0->arfcn & 0xff; +} + +static void gsm48_chan_desc(struct gsm48_chan_desc *cd, + const struct gsm_lchan *lchan) +{ + u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; + + cd->chan_nr = lchan2chan_nr(lchan); + cd->h0.tsc = lchan->ts->trx->bts->tsc; + cd->h0.h = 0; + cd->h0.arfcn_high = arfcn >> 8; + cd->h0.arfcn_low = arfcn & 0xff; +} + +/* Chapter 9.1.15: Handover Command */ +int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, + struct gsm_lchan *new_lchan, u_int8_t power_command) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + struct gsm48_ho_cmd *ho = + (struct gsm48_ho_cmd *) msgb_put(msg, sizeof(*ho)); + static u_int8_t ho_ref; + + msg->lchan = old_lchan; + + /* mandatory bits */ + gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts); + gsm48_chan_desc(&ho->chan_desc, new_lchan); + ho->ho_ref = ho_ref++; + ho->power_command = power_command; + + /* FIXME: optional bits for type of synchronization? */ + + return gsm48_sendmsg(msg, NULL); +} + /* Chapter 9.1.2: Assignment Command */ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) { @@ -526,7 +570,6 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); struct gsm48_ass_cmd *ass = (struct gsm48_ass_cmd *) msgb_put(msg, sizeof(*ass)); - u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode); @@ -542,11 +585,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) * the chan_desc. But as long as multi-slot configurations * are not used we seem to be fine. */ - ass->chan_desc.chan_nr = lchan2chan_nr(lchan); - ass->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc; - ass->chan_desc.h0.h = 0; - ass->chan_desc.h0.arfcn_high = arfcn >> 8; - ass->chan_desc.h0.arfcn_low = arfcn & 0xff; + gsm48_chan_desc(&ass->chan_desc, lchan); ass->power_command = power_command; /* in case of multi rate we need to attach a config */ -- cgit v1.2.3 From d011e8b958f3d5a09d1c66852292974d9dc52786 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 22:45:52 +0100 Subject: [handover] Introduce new handover related LCHAN signals This introduces the signals S_LCHAN_ACTIVATE_{ACK,NACK} and S_LCAN_HANDOVER_{FAIL,COMPL,DETECT} as well as code that actually issues those signals. The signals are relevant for a yet-to-be-written handover control logic. --- openbsc/src/abis_rsl.c | 30 +++++++++++++++++++++++++++++- openbsc/src/gsm_04_08.c | 33 +++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 5 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 743dc5f2b..8033a3c74 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -907,7 +907,9 @@ static int rsl_rx_chan_act_ack(struct msgb *msg) * to assign the activated channel to the MS */ if (rslh->ie_chan != RSL_IE_CHAN_NR) return -EINVAL; - + + dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan); + return 0; } @@ -926,6 +928,8 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); + dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan); + lchan_free(msg->lchan); return 0; } @@ -1050,6 +1054,27 @@ static int rsl_rx_meas_res(struct msgb *msg) return 0; } +/* Chapter 8.4.7 */ +static int rsl_rx_hando_det(struct msgb *msg) +{ + struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); + struct tlv_parsed tp; + + DEBUGP(DRSL, "HANDOVER DETECT "); + + rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); + + if (TLVP_PRESENT(&tp, RSL_IE_ACCESS_DELAY)) + DEBUGPC(DRSL, "access delay = %u\n", + *TLVP_VAL(&tp, RSL_IE_ACCESS_DELAY)); + else + DEBUGPC(DRSL, "\n"); + + dispatch_signal(SS_LCHAN, S_LCHAN_HANDOVER_DETECT, msg->lchan); + + return 0; +} + static int abis_rsl_rx_dchan(struct msgb *msg) { struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg); @@ -1077,6 +1102,9 @@ static int abis_rsl_rx_dchan(struct msgb *msg) case RSL_MT_MEAS_RES: rc = rsl_rx_meas_res(msg); break; + case RSL_MT_HANDO_DET: + rc = rsl_rx_hando_det(msg); + break; case RSL_MT_RF_CHAN_REL_ACK: DEBUGPC(DRSL, "RF CHANNEL RELEASE ACK\n"); lchan_free(msg->lchan); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index eeeb739f1..e225bf3a1 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1563,6 +1563,33 @@ static int gsm48_rx_rr_app_info(struct msgb *msg) return db_apdu_blob_store(msg->lchan->subscr, apdu_id_flags, apdu_len, apdu_data); } +/* Chapter 9.1.16 Handover complete */ +static gsm48_rx_rr_ho_compl(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + DEBUGP(DRR, "HANDOVER COMPLETE cause = %s\n", + rr_cause_name(gh->data[0])); + + dispatch_signal(SS_LCHAN, S_LCHAN_HANDOVER_COMPL, msg->lchan); + /* FIXME: release old channel */ + + return 0; +} + +/* Chapter 9.1.17 Handover Failure */ +static gsm48_rx_rr_ho_fail(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + DEBUGP(DRR, "HANDOVER FAILED cause = %s\n", + rr_cause_name(gh->data[0])); + + dispatch_signal(SS_LCHAN, S_LCHAN_HANDOVER_FAIL, msg->lchan); + /* FIXME: release allocated new channel */ + + return 0; +} /* Receive a GSM 04.08 Radio Resource (RR) message */ static int gsm0408_rcv_rr(struct msgb *msg) @@ -1597,12 +1624,10 @@ static int gsm0408_rcv_rr(struct msgb *msg) /* FIXME: check for MI (if any) */ break; case GSM48_MT_RR_HANDO_COMPL: - DEBUGP(DRR, "HANDOVER COMPLETE\n"); - /* FIXME: release old channel */ + rc = gsm48_rx_rr_ho_compl(msg); break; case GSM48_MT_RR_HANDO_FAIL: - DEBUGP(DRR, "HANDOVER FAILED\n"); - /* FIXME: release allocated new channel */ + rc = gsm48_rx_rr_ho_fail(msg); break; default: fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n", -- cgit v1.2.3 From 798418a068fcc95f8f5bcad5ba923ab065d7fa86 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 Nov 2009 22:56:14 +0100 Subject: [handover] Implement handover control logic Code to implement handover control logic. A yet-to-be-implemented handover algorithm will call bsc_handover_start(old_lchan, new_bts) to start the handover process. --- openbsc/src/Makefile.am | 2 +- openbsc/src/handover_logic.c | 251 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 openbsc/src/handover_logic.c (limited to 'openbsc/src') diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 9c8fa7b4d..4d18692db 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -7,7 +7,7 @@ noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ - msgb.c select.c chan_alloc.c timer.c debug.c \ + msgb.c select.c chan_alloc.c timer.c debug.c handover_logic.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c new file mode 100644 index 000000000..d4a888487 --- /dev/null +++ b/openbsc/src/handover_logic.c @@ -0,0 +1,251 @@ +/* Handover Logic for Inter-BTS (Intra-BSC) Handover. This does not + * actually implement the handover algorithm/decision, but executes a + * handover decision */ + +/* (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 General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bsc_handover { + struct llist_head list; + + struct gsm_lchan *old_lchan; + struct gsm_lchan *new_lchan; + + struct timer_list T3103; + + u_int8_t ho_ref; +}; + +static LLIST_HEAD(bsc_handovers); + +static struct bsc_handover *bsc_ho_by_new_lchan(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + + llist_for_each_entry(ho, &bsc_handovers, list) { + if (ho->new_lchan == new_lchan) + return ho; + } + + return NULL; +} + +static struct bsc_handover *bsc_ho_by_old_lchan(struct gsm_lchan *old_lchan) +{ + struct bsc_handover *ho; + + llist_for_each_entry(ho, &bsc_handovers, list) { + if (ho->old_lchan == old_lchan) + return ho; + } + + return NULL; +} + +/* Hand over the specified logical channel to the specified new BTS. + * This is the main entry point for the actual handover algorithm, + * after it has decided it wants to initiate HO to a specific BTS */ +int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) +{ + struct gsm_lchan *new_lchan; + struct bsc_handover *ho; + int rc; + + new_lchan = lchan_alloc(bts, old_lchan->type); + if (!new_lchan) + return -ENOSPC; + + ho = talloc_zero(NULL, struct bsc_handover); + if (!ho) { + lchan_free(new_lchan); + return -ENOMEM; + } + ho->old_lchan = old_lchan; + ho->new_lchan = new_lchan; + + /* FIXME: do we have a better idea of the timing advance? */ + rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0); + if (rc < 0) { + talloc_free(ho); + lchan_free(new_lchan); + return rc; + } + + llist_add(&ho->list, &bsc_handovers); + /* we continue in the SS_LCHAN handler / ho_chan_activ_ack */ + + return 0; +} + +/* T3103 expired: Handover has failed without HO COMPLETE or HO FAIL */ +static void ho_T3103_cb(void *_ho) +{ + struct bsc_handover *ho = _ho; + + lchan_free(ho->new_lchan); + llist_del(&ho->list); + talloc_free(ho); +} + +/* RSL has acknowledged activation of the new lchan */ +static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + int rc; + + ho = bsc_ho_by_new_lchan(new_lchan); + if (!ho) + return -ENODEV; + + /* we can now send the 04.08 HANDOVER COMMAND to the MS + * using the old lchan */ + + rc = gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0); + + /* start T3103. We can continue either with T3103 expiration, + * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */ + ho->T3103.cb = ho_T3103_cb; + bsc_schedule_timer(&ho->T3103, 10, 0); + + return 0; +} + +/* RSL has not acknowledged activation of the new lchan */ +static int ho_chan_activ_nack(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + + ho = bsc_ho_by_new_lchan(new_lchan); + if (!ho) + return -ENODEV; + + llist_del(&ho->list); + talloc_free(ho); + + /* FIXME: maybe we should try to allocate a new LCHAN here? */ + + return 0; +} + +/* GSM 04.08 HANDOVER COMPLETE has been received on new channel */ +static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + + ho = bsc_ho_by_new_lchan(new_lchan); + if (!ho) + return -ENODEV; + + bsc_del_timer(&ho->T3103); + llist_del(&ho->list); + + /* do something to re-route the actual speech frames ! */ + //tch_remap(ho->old_lchan, ho->new_lchan); + + /* release old lchan */ + put_lchan(ho->old_lchan); + + talloc_free(ho); + + return 0; +} + +/* GSM 04.08 HANDOVER FAIL has been received */ +static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) +{ + struct bsc_handover *ho; + + ho = bsc_ho_by_old_lchan(old_lchan); + if (!ho) + return -ENODEV; + + bsc_del_timer(&ho->T3103); + llist_del(&ho->list); + put_lchan(ho->new_lchan); + talloc_free(ho); + + return 0; +} + +/* GSM 08.58 HANDOVER DETECT has been received */ +static int ho_rsl_detect(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + + ho = bsc_ho_by_old_lchan(new_lchan); + if (!ho) + return -ENODEV; + + /* FIXME: do we actually want to do something here ? */ + + return 0; +} + +static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct gsm_lchan *lchan; + + switch (subsys) { + case SS_LCHAN: + lchan = signal_data; + switch (signal) { + case S_LCHAN_ACTIVATE_ACK: + return ho_chan_activ_ack(lchan); + case S_LCHAN_ACTIVATE_NACK: + return ho_chan_activ_nack(lchan); + case S_LCHAN_HANDOVER_DETECT: + return ho_rsl_detect(lchan); + case S_LCHAN_HANDOVER_COMPL: + return ho_gsm48_ho_compl(lchan); + case S_LCHAN_HANDOVER_FAIL: + return ho_gsm48_ho_fail(lchan); + } + break; + default: + break; + } + + return 0; +} + +static __attribute__((constructor)) void on_dso_load_ho_logic(void) +{ + register_signal_handler(SS_LCHAN, ho_logic_sig_cb, NULL); +} -- cgit v1.2.3 From dbb1d883594ba8796acbc7831d4ad042c7070d12 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 30 Nov 2009 19:16:47 +0100 Subject: [handover] export measurement reports via signal This patch introduces the S_LCHAN_MEAS_REP signal which is used to export measurement reports as input to the yet-to-be-written handover algorithm. --- openbsc/src/abis_rsl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 8033a3c74..b049c3c8a 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1005,6 +1005,8 @@ static int rsl_rx_meas_res(struct msgb *msg) memset(&mr, 0, sizeof(mr)); + mr.lchan = msg->lchan; + rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); if (!TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR) || @@ -1048,9 +1050,10 @@ static int rsl_rx_meas_res(struct msgb *msg) return rc; } - /* FIXME: do something with the actual result*/ print_meas_rep(&mr); + dispatch_signal(SS_LCHAN, S_LCHAN_MEAS_REP, &mr); + return 0; } -- cgit v1.2.3 From b84ddfc22f60ed42c0c0ee5367c42a56157a7c75 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 1 Dec 2009 17:36:54 +0530 Subject: Assign default values for T3101 and T3113 Without those default values, old config files will no longer work after commit 23975e718fd456ff8be7effbb915903f1bc173be --- openbsc/src/gsm_data.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 8212346ec..88de4c462 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -198,6 +198,9 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c net->country_code = country_code; net->network_code = network_code; net->num_bts = 0; + net->T3101 = GSM_T3101_DEFAULT; + net->T3113 = GSM_T3113_DEFAULT; + /* FIXME: initialize all other timers! */ INIT_LLIST_HEAD(&net->trans_list); INIT_LLIST_HEAD(&net->upqueue); -- cgit v1.2.3 From 3961fcc0313f1d87ab64806638e416f2603e7345 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 30 Nov 2009 19:37:18 +0100 Subject: Introduce new S_GLOBAL_SHUTDOWN signal This is used to notify various parts of OpenBSC that we're shutting down. --- openbsc/src/bsc_hack.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index c256f864e..ee37a6115 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -35,6 +35,7 @@ #include #include #include +#include /* MCC and MNC for the Location Area Identifier */ struct gsm_network *bsc_gsmnet = 0; @@ -143,6 +144,7 @@ static void signal_handler(int signal) switch (signal) { case SIGINT: bsc_shutdown_net(bsc_gsmnet); + dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL); sleep(3); exit(0); break; -- cgit v1.2.3 From 29b9cf844686b84c5f19ee9b6d62fe921d68f3fc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 30 Nov 2009 19:43:54 +0100 Subject: make use of new S_GLOBAL_SHUTDOWN signal to properly close pcap_fd This avoids broken pcap files with partial packets due to non-flushed buffers. --- openbsc/src/e1_input.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index e46533838..15495fbbb 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #define NUM_E1_TS 32 @@ -523,8 +524,24 @@ int e1inp_line_update(struct e1inp_line *line) return mi_e1_line_update(line); } +static int e1i_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + if (subsys != SS_GLOBAL || + signal != S_GLOBAL_SHUTDOWN) + return 0; + + if (pcap_fd) { + close(pcap_fd); + pcap_fd = -1; + } + + return 0; +} + static __attribute__((constructor)) void on_dso_load_e1_inp(void) { tall_sigl_ctx = talloc_named_const(tall_bsc_ctx, 1, "e1inp_sign_link"); + register_signal_handler(SS_GLOBAL, e1i_sig_cb, NULL); } -- cgit v1.2.3 From a43f789a0a124c322146280ab00935b75f505617 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 1 Dec 2009 18:04:30 +0530 Subject: Replace template-based SYSTEM INFORMATION with real implementation Before this commit, OpenBSC used templates for the SYSTEM INFO 1, 2, 3, 4, 5 and 6 messages. Those templates were patched in various places to reflect the network config like ARFCN. Now, we actually generate those SI messages ourselves, using values from the configuration file, and even calculating neighbor cell lists. All bts'es that you have configured in OpenBSC will end up in the neighbor cell list - which should be more than sufficient for the current small-single-site networks. --- openbsc/src/Makefile.am | 2 +- openbsc/src/abis_rsl.c | 10 +- openbsc/src/bitvec.c | 123 +++++++++++ openbsc/src/bsc_init.c | 329 +++++------------------------- openbsc/src/paging.c | 2 +- openbsc/src/rest_octets.c | 393 +++++++++++++++++++++++++++++++++++ openbsc/src/system_information.c | 427 +++++++++++++++++++++++++++++++++++++++ openbsc/src/vty_interface.c | 7 +- 8 files changed, 1006 insertions(+), 287 deletions(-) create mode 100644 openbsc/src/bitvec.c create mode 100644 openbsc/src/rest_octets.c create mode 100644 openbsc/src/system_information.c (limited to 'openbsc/src') diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 4d18692db..f22582122 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -11,7 +11,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ - talloc_ctx.c + talloc_ctx.c system_information.c bitvec.c rest_octets.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index b049c3c8a..1d41d2b5d 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1729,11 +1729,11 @@ int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf) /* From Table 10.5.33 of GSM 04.08 */ int rsl_number_of_paging_subchannels(struct gsm_bts *bts) { - if (bts->chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) { - return MAX(1, (3 - bts->chan_desc.bs_ag_blks_res)) - * (bts->chan_desc.bs_pa_mfrms + 2); + if (bts->si_common.chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) { + return MAX(1, (3 - bts->si_common.chan_desc.bs_ag_blks_res)) + * (bts->si_common.chan_desc.bs_pa_mfrms + 2); } else { - return (9 - bts->chan_desc.bs_ag_blks_res) - * (bts->chan_desc.bs_pa_mfrms + 2); + return (9 - bts->si_common.chan_desc.bs_ag_blks_res) + * (bts->si_common.chan_desc.bs_pa_mfrms + 2); } } diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c new file mode 100644 index 000000000..ac2554475 --- /dev/null +++ b/openbsc/src/bitvec.c @@ -0,0 +1,123 @@ +/* bit vector utility routines */ + +/* (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 General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#include +#include + +#include + +#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit) + +static inline unsigned int bytenum_from_bitnum(unsigned int bitnum) +{ + unsigned int bytenum = bitnum / 8; + + return bytenum; +} + +int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, + enum bit_value bit) +{ + unsigned int bytenum = bytenum_from_bitnum(bitnr); + unsigned int bitnum = 7 - (bitnr % 8); + u_int8_t bitval; + + if (bytenum >= bv->data_len) + return -EINVAL; + + switch (bit) { + case ZERO: + bitval = (0 << bitnum); + break; + case ONE: + bitval = (1 << bitnum); + break; + case L: + bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum)); + break; + case H: + bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum)); + break; + default: + return -EINVAL; + } + + /* first clear the bit */ + bv->data[bytenum] &= ~(1 << bitnum); + + /* then set it to desired value */ + bv->data[bytenum] |= bitval; + + return 0; +} + +int bitvec_set_bit(struct bitvec *bv, enum bit_value bit) +{ + int rc; + + rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit); + if (!rc) + bv->cur_bit++; + + return rc; +} + +int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count) +{ + int i, rc; + + for (i = 0; i < count; i++) { + rc = bitvec_set_bit(bv, bits[i]); + if (rc) + return rc; + } + + return 0; +} + +int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits) +{ + int i, rc; + + for (i = 0; i < num_bits; i++) { + int bit = 0; + if (ui & (1 << (num_bits - i - 1))) + bit = 1; + rc = bitvec_set_bit(bv, bit); + if (rc) + return rc; + } + + return 0; +} + +/* pad all remaining bits up to num_bits */ +int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit) +{ + unsigned int i; + + for (i = bv->cur_bit; i <= up_to_bit; i++) + bitvec_set_bit(bv, L); + + return 0; +} diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 153e024e4..d21f71a0c 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,6 @@ extern struct gsm_network *bsc_gsmnet; extern int ipacc_rtp_direct; static void patch_nm_tables(struct gsm_bts *bts); -static void patch_si_tables(struct gsm_bts *bts); /* The following definitions are for OM and NM packets that we cannot yet * generate by code but we just pass on */ @@ -667,219 +667,42 @@ int bsc_shutdown_net(struct gsm_network *net) return 0; } -struct bcch_info { - u_int8_t type; - u_int8_t len; - const u_int8_t *data; -}; - -/* -SYSTEM INFORMATION TYPE 1 - Cell channel description - Format-ID bit map 0 - CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 - RACH Control Parameters - maximum 7 retransmissions - 8 slots used to spread transmission - cell not barred for access - call reestablishment not allowed - Access Control Class = 0000 -*/ -static u_int8_t si1[] = { - /* header */0x55, 0x06, 0x19, - /* ccdesc */0x04 /*0x00*/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*0x01*/, - /* rach */0xD5, 0x04, 0x00, - /* s1 reset*/0x2B -}; - -/* - SYSTEM INFORMATION TYPE 2 - Neighbour Cells Description - EXT-IND: Carries the complete BA - BA-IND = 0 - Format-ID bit map 0 - CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - NCC permitted (NCC) = FF - RACH Control Parameters - maximum 7 retransmissions - 8 slots used to spread transmission - cell not barred for access - call reestablishment not allowed - Access Control Class = 0000 -*/ -static u_int8_t si2[] = { - /* header */0x59, 0x06, 0x1A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ncc */0xFF, - /* rach*/0xD5, 0x04, 0x00 -}; - -/* -SYSTEM INFORMATION TYPE 3 - Cell identity = 00001 (1h) - Location area identification - Mobile Country Code (MCC): 001 - Mobile Network Code (MNC): 01 - Location Area Code (LAC): 00001 (1h) - Control Channel Description - Attach-detach: MSs in the cell are not allowed to apply IMSI attach /detach - 0 blocks reserved for access grant - 1 channel used for CCCH, with SDCCH - 5 multiframes period for PAGING REQUEST - Time-out T3212 = 0 - Cell Options BCCH - Power control indicator: not set - MSs shall not use uplink DTX - Radio link timeout = 36 - Cell Selection Parameters - Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection - max.TX power level MS may use for CCH = 2 <- according to GSM05.05 39dBm (max) - Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters - Half rate support (NECI): New establishment causes are not supported - min.RX signal level for MS = 0 - RACH Control Parameters - maximum 7 retransmissions - 8 slots used to spread transmission - cell not barred for access - call reestablishment not allowed - Access Control Class = 0000 - SI 3 Rest Octets (not present) -*/ -static u_int8_t si3[] = { - /* header */0x49, 0x06, 0x1B, - /* cell */0x00, 0x01, - /* lai */0x00, 0xF1, 0x10, 0x00, 0x01, - /* desc */0x01, 0x03, 0x00, - /* option*/0x28, - /* selection*/0x62, 0x00, - /* rach */0xD5, 0x04, 0x00, - /* rest */ 0x2B, 0x2B, 0x2B, 0x2B -}; - -/* -SYSTEM INFORMATION TYPE 4 - Location area identification - Mobile Country Code (MCC): 001 - Mobile Network Code (MNC): 01 - Location Area Code (LAC): 00001 (1h) - Cell Selection Parameters - Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection - max.TX power level MS may use for CCH = 2 - Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters - Half rate support (NECI): New establishment causes are not supported - min.RX signal level for MS = 0 - RACH Control Parameters - maximum 7 retransmissions - 8 slots used to spread transmission - cell not barred for access - call reestablishment not allowed - Access Control Class = 0000 - CBCH Channel Description - Type = SDCCH/4[2] - Timeslot Number: 0 - Training Sequence Code: 7h - ARFCN: 1 - SI Rest Octets (not present) -*/ -static u_int8_t si4[] = { - /* header */0x41, 0x06, 0x1C, - /* lai */0x00, 0xF1, 0x10, 0x00, 0x01, - /* sel */0x62, 0x00, - /* rach*/0xD5, 0x04, 0x00, - /* cbch chan desc */ 0x64, 0x30, 0xE0, HARDCODED_ARFCN/*0x01*/, - /* rest octets */ 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B -}; - -/* - SYSTEM INFORMATION TYPE 5 - Neighbour Cells Description - EXT-IND: Carries the complete BA - BA-IND = 0 - Format-ID bit map 0 - CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -*/ - -static u_int8_t si5[] = { - /* header without l2 len*/0x06, 0x1D, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -// SYSTEM INFORMATION TYPE 6 - -/* -SACCH FILLING - System Info Type: SYSTEM INFORMATION 6 - L3 Information (Hex): 06 1E 00 01 xx xx 10 00 01 28 FF - -SYSTEM INFORMATION TYPE 6 - Cell identity = 00001 (1h) - Location area identification - Mobile Country Code (MCC): 001 - Mobile Network Code (MNC): 01 - Location Area Code (LAC): 00001 (1h) - Cell Options SACCH - Power control indicator: not set - MSs shall not use uplink DTX on a TCH-F. MS shall not use uplink DTX on TCH-H. - Radio link timeout = 36 - NCC permitted (NCC) = FF -*/ - -static u_int8_t si6[] = { - /* header */0x06, 0x1E, - /* cell id*/ 0x00, 0x01, - /* lai */ 0x00, 0xF1, 0x10, 0x00, 0x01, - /* options */ 0x28, - /* ncc */ 0xFF, -}; - - - -static const struct bcch_info bcch_infos[] = { - { - .type = RSL_SYSTEM_INFO_1, - .len = sizeof(si1), - .data = si1, - }, { - .type = RSL_SYSTEM_INFO_2, - .len = sizeof(si2), - .data = si2, - }, { - .type = RSL_SYSTEM_INFO_3, - .len = sizeof(si3), - .data = si3, - }, { - .type = RSL_SYSTEM_INFO_4, - .len = sizeof(si4), - .data = si4, - }, -}; - -static_assert(sizeof(si1) == sizeof(struct gsm48_system_information_type_1), type1) -static_assert(sizeof(si2) == sizeof(struct gsm48_system_information_type_2), type2) -static_assert(sizeof(si3) == sizeof(struct gsm48_system_information_type_3), type3) -static_assert(sizeof(si4) >= sizeof(struct gsm48_system_information_type_4), type4) -static_assert(sizeof(si5) == sizeof(struct gsm48_system_information_type_5), type5) -static_assert(sizeof(si6) >= sizeof(struct gsm48_system_information_type_6), type6) - /* set all system information types */ static int set_system_infos(struct gsm_bts_trx *trx) { - int i; + int i, rc; + u_int8_t si_tmp[23]; if (trx == trx->bts->c0) { - for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) { - rsl_bcch_info(trx, bcch_infos[i].type, - bcch_infos[i].data, - bcch_infos[i].len); + for (i = 1; i <= 4; i++) { + rc = gsm_generate_si(si_tmp, trx->bts, i); + if (rc < 0) + goto err_out; + rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } } - rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5)); - rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6)); +#ifdef GPRS + rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); + if (rc < 0) + goto err_out; + rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); +#endif + rc = gsm_generate_si(si_tmp, trx->bts, 5); + if (rc < 0) + goto err_out; + rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si_tmp, rc); + + rc = gsm_generate_si(si_tmp, trx->bts, 6); + if (rc < 0) + goto err_out; + rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si_tmp, rc); return 0; +err_out: + fprintf(stderr, "Cannot generate SI for BTS %u, most likely " + "a problem with neighbor cell list generation\n", + trx->bts->nr); + return rc; } /* @@ -913,81 +736,12 @@ static void patch_nm_tables(struct gsm_bts *bts) nanobts_attr_radio[1] = bts->c0->max_power_red / 2; } -/* - * Patch the various SYSTEM INFORMATION tables to update - * the LAI - */ -static void patch_si_tables(struct gsm_bts *bts) -{ - u_int8_t arfcn_low = bts->c0->arfcn & 0xff; - u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f; - - /* covert the raw packet to the struct */ - struct gsm48_system_information_type_1 *type_1 = - (struct gsm48_system_information_type_1*)&si1; - struct gsm48_system_information_type_2 *type_2 = - (struct gsm48_system_information_type_2*)&si2; - struct gsm48_system_information_type_3 *type_3 = - (struct gsm48_system_information_type_3*)&si3; - struct gsm48_system_information_type_4 *type_4 = - (struct gsm48_system_information_type_4*)&si4; - struct gsm48_system_information_type_6 *type_6 = - (struct gsm48_system_information_type_6*)&si6; - struct gsm48_loc_area_id lai; - - gsm0408_generate_lai(&lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); - - /* assign the MCC and MNC */ - type_3->lai = lai; - type_4->lai = lai; - type_6->lai = lai; - - /* set the CI */ - type_3->cell_identity = htons(bts->cell_identity); - type_6->cell_identity = htons(bts->cell_identity); - - type_4->data[2] &= 0xf0; - type_4->data[2] |= arfcn_high; - type_4->data[3] = arfcn_low; - - /* patch Control Channel Description 10.5.2.11 */ - type_3->control_channel_desc = bts->chan_desc; - - /* patch TSC */ - si4[15] &= ~0xe0; - si4[15] |= (bts->tsc & 7) << 5; - - /* patch MS max power for CCH */ - type_4->cell_sel_par.ms_txpwr_max_ccch = - ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); - - /* Set NECI to influence channel request */ - type_3->cell_sel_par.neci = bts->network->neci; - type_4->cell_sel_par.neci = bts->network->neci; - - if (bts->cell_barred) { - type_1->rach_control.cell_bar = 1; - type_2->rach_control.cell_bar = 1; - type_3->rach_control.cell_bar = 1; - type_4->rach_control.cell_bar = 1; - } else { - type_1->rach_control.cell_bar = 0; - type_2->rach_control.cell_bar = 0; - type_3->rach_control.cell_bar = 0; - type_4->rach_control.cell_bar = 0; - } -} - - static void bootstrap_rsl(struct gsm_bts_trx *trx) { fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) " "using MCC=%u MNC=%u BSIC=%u TSC=%u\n", trx->bts->nr, trx->nr, bsc_gsmnet->country_code, bsc_gsmnet->network_code, trx->bts->bsic, trx->bts->tsc); - patch_si_tables(trx->bts); set_system_infos(trx); } @@ -1042,11 +796,32 @@ static int bootstrap_bts(struct gsm_bts *bts) } /* Control Channel Description */ - bts->chan_desc.att = 1; - bts->chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; - bts->chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; + bts->si_common.chan_desc.att = 1; + bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; + bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; + if (bts->cell_barred) + bts->si_common.rach_control.cell_bar = 1; /* T3212 is set from vty/config */ + /* some defaults for our system information */ + bts->si_common.rach_control.re = 1; /* no re-establishment */ + bts->si_common.rach_control.tx_integer = 5; /* 8 slots spread */ + bts->si_common.rach_control.max_trans = 3; /* 7 retransmissions */ + bts->si_common.rach_control.t2 = 4; /* no emergency calls */ + + bts->si_common.cell_options.radio_link_timeout = 2; /* 12 */ + bts->si_common.cell_options.dtx = 2; /* MS shall not use upplink DTX */ + bts->si_common.cell_options.pwrc = 0; /* PWRC not set */ + + bts->si_common.cell_sel_par.ms_txpwr_max_ccch = + ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); + bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */ + bts->si_common.cell_sel_par.rxlev_acc_min = 0; + bts->si_common.cell_sel_par.acs = 0; + bts->si_common.cell_sel_par.neci = bts->network->neci; + + bts->si_common.ncc_permitted = 0xff; + paging_init(bts); return 0; diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index fe6ea52d1..b273419c3 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -55,7 +55,7 @@ static unsigned int calculate_group(struct gsm_bts *bts, struct gsm_subscriber * int blocks; unsigned int group; - ccch_conf = bts->chan_desc.ccch_conf; + ccch_conf = bts->si_common.chan_desc.ccch_conf; bs_cc_chans = rsl_ccch_conf_to_bs_cc_chans(ccch_conf); /* code word + 2, as 2 channels equals 0x0 */ blocks = rsl_number_of_paging_subchannels(bts); diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c new file mode 100644 index 000000000..6efd47515 --- /dev/null +++ b/openbsc/src/rest_octets.c @@ -0,0 +1,393 @@ +/* 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 General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +#include +#include +#include + +/* generate SI1 rest octets */ +int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 2; + + if (nch_pos) { + bitvec_set_bit(&bv, H); + bitvec_set_uint(&bv, *nch_pos, 5); + } else + bitvec_set_bit(&bv, L); + + bitvec_spare_padding(&bv, 15); + return 0; +} + +/* 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 SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */ +int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 5; + + /* 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); + + return bitvec_spare_padding(&bv, (bv.data_len*8)-1); +} + +static int append_lsa_params(struct bitvec *bv, + const struct gsm48_lsa_params *lsa_params) +{ + /* FIXME */ +} + +/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */ +int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 11; /* FIXME: up to ? */ + + /* 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 0; +} + +/* 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) +{ + 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, 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); + bitvec_set_uint(bv, gco->t3168 / 500, 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: Hard-code to RLC/MAC control block */ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, gco->bs_cv_max, 4); + + /* hard-code no PAN_{DEC,INC,MAX} */ + bitvec_set_bit(bv, 0); + + /* no extension information (EDGE) */ + bitvec_set_bit(bv, 0); + + return 0; +} + +static void append_gprs_pwr_ctrl_pars(struct bitvec *bv, + 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 (Chapter 10.5.2.37b) */ +int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13) +{ + struct bitvec bv; + + memset(&bv, 0, sizeof(bv)); + bv.data = data; + bv.data_len = 21; + + 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 (0) { + 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); + } + if (!si13->pbcch_present) { + /* PBCCH not present in cell */ + bitvec_set_bit(&bv, 0); + bitvec_set_uint(&bv, si13->no_pbcch.rac, 8); + bitvec_set_bit(&bv, si13->no_pbcch.spgc_ccch_sup); + bitvec_set_uint(&bv, si13->no_pbcch.prio_acc_thr, 3); + bitvec_set_uint(&bv, si13->no_pbcch.net_ctrl_ord, 2); + append_gprs_cell_opt(&bv, &si13->cell_opts); + append_gprs_pwr_ctrl_pars(&bv, &si13->pwr_ctrl_pars); + } else { + /* PBCCH present in cell */ + bitvec_set_bit(&bv, 1); + bitvec_set_uint(&bv, si13->pbcch.psi1_rep_per, 4); + /* PBCCH Descripiton */ + bitvec_set_uint(&bv, si13->pbcch.pb, 4); + bitvec_set_uint(&bv, si13->pbcch.tsc, 3); + bitvec_set_uint(&bv, si13->pbcch.tn, 3); + switch (si13->pbcch.carrier_type) { + case PBCCH_BCCH: + bitvec_set_bit(&bv, 0); + bitvec_set_bit(&bv, 0); + break; + case PBCCH_ARFCN: + bitvec_set_bit(&bv, 0); + bitvec_set_bit(&bv, 1); + bitvec_set_uint(&bv, si13->pbcch.arfcn, 10); + break; + case PBCCH_MAIO: + bitvec_set_bit(&bv, 1); + bitvec_set_uint(&bv, si13->pbcch.maio, 6); + break; + } + } + } + return bitvec_spare_padding(&bv, (bv.data_len*8)-1); +} diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c new file mode 100644 index 000000000..d6d166c79 --- /dev/null +++ b/openbsc/src/system_information.c @@ -0,0 +1,427 @@ +/* GSM 04.08 System Information (SI) encoding and decoding + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ + +/* (C) 2008-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 General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define GSM48_CELL_CHAN_DESC_SIZE 16 +#define GSM_MACBLOCK_LEN 23 +#define GSM_MACBLOCK_PADDING 0x2b + +static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) +{ + unsigned int byte, bit; + + if (arfcn > 124) + return -EINVAL; + + byte = arfcn / 8; + bit = arfcn % 8; + + chan_list[GSM48_CELL_CHAN_DESC_SIZE-byte] |= (1 << bit); + + return 0; +} + +static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) +{ + unsigned int byte, bit; + unsigned int min_arfcn; + unsigned int bitno; + + min_arfcn = (chan_list[0] & 1) << 9; + min_arfcn |= chan_list[1] << 1; + min_arfcn |= (chan_list[2] >> 7) & 1; + + /* The lower end of our bitmaks is always implicitly included */ + if (arfcn == min_arfcn) + return 0; + + if (arfcn < min_arfcn) + return -EINVAL; + if (arfcn > min_arfcn + 111) + return -EINVAL; + + bitno = (arfcn - min_arfcn); + byte = bitno / 8; + bit = bitno % 8; + + chan_list[2 + byte] |= 1 << (7 - bit); + + return 0; +} + +/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ +static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts) +{ + struct gsm_bts_trx *trx; + int rc, min = 1024, max = 0; + + memset(chan_list, 0, 16); + + /* GSM900-only handsets only support 'bit map 0 format' */ + if (bts->band == GSM_BAND_900) { + chan_list[0] = 0; + llist_for_each_entry(trx, &bts->trx_list, list) { + rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); + if (rc < 0) + return rc; + } + return 0; + } + + /* We currently only support the 'Variable bitmap format' */ + chan_list[0] = 0x8e; + + llist_for_each_entry(trx, &bts->trx_list, list) { + if (trx->arfcn < min) + min = trx->arfcn; + if (trx->arfcn > max) + max = trx->arfcn; + } + + if ((max - min) > 111) + return -EINVAL; + + chan_list[0] |= (min >> 9) & 1; + chan_list[1] = (min >> 1); + chan_list[2] = (min & 1) << 7; + + llist_for_each_entry(trx, &bts->trx_list, list) { + rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn); + if (rc < 0) + return rc; + } + + return 0; +} + +/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ +static int generate_bcch_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts) +{ + struct gsm_bts *cur_bts; + struct gsm_bts_trx *trx; + int rc, min = 1024, max = 0; + + memset(chan_list, 0, 16); + + /* GSM900-only handsets only support 'bit map 0 format' */ + if (bts->band == GSM_BAND_900) { + chan_list[0] = 0; + llist_for_each_entry(cur_bts, &bts->list, list) { + trx = cur_bts->c0; + rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); + if (rc < 0) + return rc; + } + return 0; + } + + /* We currently only support the 'Variable bitmap format' */ + chan_list[0] = 0x8e; + + llist_for_each_entry(cur_bts, &bts->list, list) { + if (&cur_bts->list == &bts->network->bts_list) + continue; + trx = cur_bts->c0; + if (trx->arfcn < min) + min = trx->arfcn; + if (trx->arfcn > max) + max = trx->arfcn; + } + + if ((max - min) > 111) + return -EINVAL; + + chan_list[0] |= (min >> 9) & 1; + chan_list[1] = (min >> 1); + chan_list[2] = (min & 1) << 7; + + llist_for_each_entry(cur_bts, &bts->list, list) { + if (&cur_bts->list == &bts->network->bts_list) + continue; + trx = cur_bts->c0; + rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn); + if (rc < 0) + return rc; + } + + return 0; +} + +static int generate_si1(u_int8_t *output, const struct gsm_bts *bts) +{ + int rc; + struct gsm48_system_information_type_1 *si1 = + (struct gsm48_system_information_type_1 *) output; + + memset(si1, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si1->header.l2_plen = (21 << 2) | 1; + si1->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si1->header.skip_indicator = 0; + si1->header.system_information = GSM48_MT_RR_SYSINFO_1; + + rc = generate_cell_chan_list(si1->cell_channel_description, bts); + if (rc < 0) + return rc; + + si1->rach_control = bts->si_common.rach_control; + + /* SI1 Rest Octets (10.5.2.32), contains NCH position */ + rest_octets_si1(si1->rest_octets, NULL); + + return GSM_MACBLOCK_LEN; +} + +static int generate_si2(u_int8_t *output, const struct gsm_bts *bts) +{ + int rc; + struct gsm48_system_information_type_2 *si2 = + (struct gsm48_system_information_type_2 *) output; + + memset(si2, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si2->header.l2_plen = (22 << 2) | 1; + si2->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si2->header.skip_indicator = 0; + si2->header.system_information = GSM48_MT_RR_SYSINFO_2; + + rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts); + if (rc < 0) + return rc; + + si2->ncc_permitted = bts->si_common.ncc_permitted; + si2->rach_control = bts->si_common.rach_control; + + return GSM_MACBLOCK_LEN; +} + +struct gsm48_si_ro_info si_info = { + .selection_params = { + .present = 0, + }, + .power_offset = { + .present = 0, + }, + .si2ter_indicator = 0, + .early_cm_ctrl = 1, + .scheduling = { + .present = 0, + }, + .gprs_ind = { + .si13_position = 0, + .ra_colour = 0, + .present = 0, + }, + .lsa_params = { + .present = 0, + }, + .cell_id = 0, /* FIXME: doesn't the bts have this? */ + .break_ind = 0, +}; + +static int generate_si3(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_3 *si3 = + (struct gsm48_system_information_type_3 *) output; + + memset(si3, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si3->header.l2_plen = (18 << 2) | 1; + si3->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si3->header.skip_indicator = 0; + si3->header.system_information = GSM48_MT_RR_SYSINFO_3; + + si3->cell_identity = htons(bts->cell_identity); + gsm0408_generate_lai(&si3->lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); + si3->control_channel_desc = bts->si_common.chan_desc; + si3->cell_options = bts->si_common.cell_options; + si3->cell_sel_par = bts->si_common.cell_sel_par; + si3->rach_control = bts->si_common.rach_control; + + /* SI3 Rest Octets (10.5.2.34), containing + CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME + Power Offset, 2ter Indicator, Early Classmark Sending, + Scheduling if and WHERE, GPRS Indicator, SI13 position */ + rest_octets_si3(si3->rest_octets, &si_info); + + return GSM_MACBLOCK_LEN; +} + +static int generate_si4(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_4 *si4 = + (struct gsm48_system_information_type_4 *) output; + + /* length of all IEs present except SI4 rest octets and l2_plen */ + int l2_plen = sizeof(*si4) - 1; + + memset(si4, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si4->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si4->header.skip_indicator = 0; + si4->header.system_information = GSM48_MT_RR_SYSINFO_4; + + gsm0408_generate_lai(&si4->lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); + si4->cell_sel_par = bts->si_common.cell_sel_par; + si4->rach_control = bts->si_common.rach_control; + + /* Optional: CBCH Channel Description + CBCH Mobile Allocation */ + + si4->header.l2_plen = (l2_plen << 2) | 1; + + /* SI4 Rest Octets (10.5.2.35), containing + Optional Power offset, GPRS Indicator, + Cell Identity, LSA ID, Selection Parameter */ + rest_octets_si4(si4->data, &si_info); + + return GSM_MACBLOCK_LEN; +} + +static int generate_si5(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_5 *si5 = + (struct gsm48_system_information_type_5 *) output; + int rc; + + memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + /* l2 pseudo length, not part of msg: 18 */ + si5->rr_protocol_discriminator = GSM48_PDISC_RR; + si5->skip_indicator = 0; + si5->system_information = GSM48_MT_RR_SYSINFO_5; + rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts); + if (rc < 0) + return rc; + + /* 04.08 9.1.37: L2 Pseudo Length of 18 */ + return 18; +} + +static int generate_si6(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_6 *si6 = + (struct gsm48_system_information_type_6 *) output; + + memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + /* l2 pseudo length, not part of msg: 11 */ + si6->rr_protocol_discriminator = GSM48_PDISC_RR; + si6->skip_indicator = 0; + si6->system_information = GSM48_MT_RR_SYSINFO_6; + si6->cell_identity = htons(bts->cell_identity); + gsm0408_generate_lai(&si6->lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); + si6->cell_options = bts->si_common.cell_options; + si6->ncc_permitted = bts->si_common.ncc_permitted; + + /* SI6 Rest Octets: 10.5.2.35a: PCH / NCH info, VBS/VGCS options */ + + return 18; +} + +static struct gsm48_si13_info si13_default = { + .cell_opts = { + .nmo = GPRS_NMO_III, + .t3168 = 1000, + .t3192 = 1000, + .drx_timer_max = 1, + .bs_cv_max = 15, + }, + .pwr_ctrl_pars = { + .alpha = 10, /* a = 1.0 */ + .t_avg_w = 25, + .t_avg_t = 25, + .pc_meas_chan = 0, /* downling measured on CCCH */ + .n_avg_i = 15, + }, + .bcch_change_mark = 0, + .si_change_field = 0, + .pbcch_present = 0, + { + .no_pbcch = { + .rac = 0, + .spgc_ccch_sup = 0, + .net_ctrl_ord = 0, + .prio_acc_thr = 0, + }, + }, +}; + +static int generate_si13(u_int8_t *output, const struct gsm_bts *bts) +{ + struct gsm48_system_information_type_13 *si13 = + (struct gsm48_system_information_type_13 *) output; + int ret; + + memset(si13, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si13->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si13->header.skip_indicator = 0; + si13->header.system_information = GSM48_MT_RR_SYSINFO_13; + + ret = rest_octets_si13(si13->rest_octets, &si13_default); + if (ret < 0) + return ret; + + si13->header.l2_plen = ret & 0xff; + + return GSM_MACBLOCK_LEN; +} + +int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type) +{ + switch (type) { + case RSL_SYSTEM_INFO_1: + return generate_si1(output, bts); + case RSL_SYSTEM_INFO_2: + return generate_si2(output, bts); + case RSL_SYSTEM_INFO_3: + return generate_si3(output, bts); + case RSL_SYSTEM_INFO_4: + return generate_si4(output, bts); + case RSL_SYSTEM_INFO_5: + return generate_si5(output, bts); + case RSL_SYSTEM_INFO_6: + return generate_si6(output, bts); + case RSL_SYSTEM_INFO_13: + return generate_si13(output, bts); + default: + return -EINVAL; + } + + return 0; +} diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 066dfd5a9..3b150b2ea 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -234,9 +234,9 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE); vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE); vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE); - if (bts->chan_desc.t3212) + if (bts->si_common.chan_desc.t3212) vty_out(vty, " periodic location update %u%s", - bts->chan_desc.t3212 * 10, VTY_NEWLINE); + bts->si_common.chan_desc.t3212 * 10, VTY_NEWLINE); vty_out(vty, " channel allocator %s%s", bts->chan_alloc_reverse ? "descending" : "ascending", VTY_NEWLINE); @@ -951,6 +951,7 @@ DEFUN(cfg_bts_lac, return CMD_SUCCESS; } + DEFUN(cfg_bts_tsc, cfg_bts_tsc_cmd, "training_sequence_code <0-255>", @@ -1094,7 +1095,7 @@ DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd, { struct gsm_bts *bts = vty->index; - bts->chan_desc.t3212 = atoi(argv[0]) / 10; + bts->si_common.chan_desc.t3212 = atoi(argv[0]) / 10; return CMD_SUCCESS; } -- cgit v1.2.3 From 2c828991352f94c1be7d860d0d151f719c1ecc6f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 2 Dec 2009 01:56:49 +0530 Subject: move RTP socket information from timeslot to lchan With ip.access, in case of TCH/H, we have one RTP stream for each half-slot (lchan), not just one per on-air timeslot. This is quite different from a classic BTS where the TRAU frames of the two TCH/H channels would be part of the same 16k sub-slot in a E1 timeslot. --- openbsc/src/abis_rsl.c | 12 +++++----- openbsc/src/gsm_04_08.c | 55 ++++++++++++++++++++------------------------- openbsc/src/vty_interface.c | 19 ++++++++-------- 3 files changed, 39 insertions(+), 47 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 1d41d2b5d..e7be9baa4 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1555,7 +1555,7 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; - struct gsm_bts_trx_ts *ts = msg->lchan->ts; + struct gsm_lchan *lchan = msg->lchan; struct in_addr ip; u_int16_t port, attr_f8; @@ -1578,16 +1578,16 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) inet_ntoa(ip), ntohs(port), ntohs(attr_f8)); if (TLVP_PRESENT(&tv, RSL_IE_IPAC_RTP_PAYLOAD2)) { - ts->abis_ip.rtp_payload2 = + lchan->abis_ip.rtp_payload2 = *TLVP_VAL(&tv, RSL_IE_IPAC_RTP_PAYLOAD2); DEBUGPC(DRSL, "RTP_PAYLOAD2=0x%02x ", - ts->abis_ip.rtp_payload2); + lchan->abis_ip.rtp_payload2); } /* update our local information about this TS */ - ts->abis_ip.bound_ip = ntohl(ip.s_addr); - ts->abis_ip.bound_port = ntohs(port); - ts->abis_ip.conn_id = ntohs(attr_f8); + lchan->abis_ip.bound_ip = ntohl(ip.s_addr); + lchan->abis_ip.bound_port = ntohs(port); + lchan->abis_ip.conn_id = ntohs(attr_f8); dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index e225bf3a1..f262dbebf 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1844,7 +1844,6 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { struct gsm_lchan *lchan = signal_data; - struct gsm_bts_trx_ts *ts; int rc; if (subsys != SS_ABISIP) @@ -1854,32 +1853,30 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, if (ipacc_rtp_direct) return 0; - ts = lchan->ts; - switch (signal) { case S_ABISIP_CRCX_ACK: /* the BTS has successfully bound a TCH to a local ip/port, * which means we can connect our UDP socket to it */ - if (ts->abis_ip.rtp_socket) { - rtp_socket_free(ts->abis_ip.rtp_socket); - ts->abis_ip.rtp_socket = NULL; + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; } - ts->abis_ip.rtp_socket = rtp_socket_create(); - if (!ts->abis_ip.rtp_socket) + lchan->abis_ip.rtp_socket = rtp_socket_create(); + if (!lchan->abis_ip.rtp_socket) goto out_err; - rc = rtp_socket_connect(ts->abis_ip.rtp_socket, - ts->abis_ip.bound_ip, - ts->abis_ip.bound_port); + rc = rtp_socket_connect(lchan->abis_ip.rtp_socket, + lchan->abis_ip.bound_ip, + lchan->abis_ip.bound_port); if (rc < 0) goto out_err; break; case S_ABISIP_DLCX_IND: /* the BTS tells us a RTP stream has been disconnected */ - if (ts->abis_ip.rtp_socket) { - rtp_socket_free(ts->abis_ip.rtp_socket); - ts->abis_ip.rtp_socket = NULL; + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; } break; } @@ -1893,15 +1890,14 @@ out_err: /* bind rtp proxy to local IP/port and tell BTS to connect to it */ static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan) { - struct gsm_bts_trx_ts *ts = lchan->ts; - struct rtp_socket *rs = ts->abis_ip.rtp_socket; + struct rtp_socket *rs = lchan->abis_ip.rtp_socket; int rc; rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), ntohs(rs->rtp.sin_local.sin_port), - ts->abis_ip.conn_id, + lchan->abis_ip.conn_id, /* FIXME: use RTP payload of bound socket, not BTS*/ - ts->abis_ip.rtp_payload2); + lchan->abis_ip.rtp_payload2); return rc; } @@ -1911,7 +1907,6 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) { struct gsm_bts *bts = lchan->ts->trx->bts; struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts; - struct gsm_bts_trx_ts *ts; int rc; DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n", @@ -1933,22 +1928,20 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) rc = ipacc_connect_proxy_bind(remote_lchan); /* connect them with each other */ - rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket, - remote_lchan->ts->abis_ip.rtp_socket); + rtp_socket_proxy(lchan->abis_ip.rtp_socket, + remote_lchan->abis_ip.rtp_socket); } else { /* directly connect TCH RTP streams to each other */ - ts = remote_lchan->ts; - rc = rsl_ipacc_mdcx(lchan, ts->abis_ip.bound_ip, - ts->abis_ip.bound_port, - lchan->ts->abis_ip.conn_id, - ts->abis_ip.rtp_payload2); + rc = rsl_ipacc_mdcx(lchan, remote_lchan->abis_ip.bound_ip, + remote_lchan->abis_ip.bound_port, + lchan->abis_ip.conn_id, + remote_lchan->abis_ip.rtp_payload2); if (rc < 0) return rc; - ts = lchan->ts; - rc = rsl_ipacc_mdcx(remote_lchan, ts->abis_ip.bound_ip, - ts->abis_ip.bound_port, - remote_lchan->ts->abis_ip.conn_id, - ts->abis_ip.rtp_payload2); + rc = rsl_ipacc_mdcx(remote_lchan, lchan->abis_ip.bound_ip, + lchan->abis_ip.bound_port, + remote_lchan->abis_ip.conn_id, + lchan->abis_ip.rtp_payload2); } break; case GSM_BTS_TYPE_BS11: diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 3b150b2ea..39fc41429 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -365,24 +365,15 @@ DEFUN(show_trx, static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts) { - struct in_addr ia; - vty_out(vty, "Timeslot %u of TRX %u in BTS %u, phys cfg %s%s", ts->nr, ts->trx->nr, ts->trx->bts->nr, gsm_pchan_name(ts->pchan), VTY_NEWLINE); vty_out(vty, " NM State: "); net_dump_nmstate(vty, &ts->nm_state); - if (is_ipaccess_bts(ts->trx->bts)) { - ia.s_addr = ts->abis_ip.bound_ip; - vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s", - inet_ntoa(ia), ts->abis_ip.bound_port, - ts->abis_ip.rtp_payload2, ts->abis_ip.conn_id, - VTY_NEWLINE); - } else { + if (!is_ipaccess_bts(ts->trx->bts)) vty_out(vty, " E1 Line %u, Timeslot %u, Subslot %u%s", ts->e1_link.e1_nr, ts->e1_link.e1_ts, ts->e1_link.e1_ts_ss, VTY_NEWLINE); - } } DEFUN(show_ts, @@ -471,6 +462,14 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) subscr_dump_vty(vty, lchan->subscr); } else vty_out(vty, " No Subscriber%s", VTY_NEWLINE); + if (is_ipaccess_bts(lchan->ts->trx->bts)) { + struct in_addr ia; + ia.s_addr = lchan->abis_ip.bound_ip; + vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s", + inet_ntoa(ia), lchan->abis_ip.bound_port, + lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id, + VTY_NEWLINE); + } } #if 0 -- cgit v1.2.3 From 0603c9d9e58b5d29105361a89ab8cb295da29366 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 2 Dec 2009 01:58:23 +0530 Subject: ip.access speech mode for TCH/H channels --- openbsc/src/abis_rsl.c | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index e7be9baa4..8a4ed9b76 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1442,19 +1442,40 @@ static int abis_rsl_rx_rll(struct msgb *msg) return rc; } -static u_int8_t ipa_smod_s_for_tch_mode(u_int8_t tch_mode) +static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan) { - switch (tch_mode) { + switch (lchan->tch_mode) { case GSM48_CMODE_SPEECH_V1: - return 0x00; + switch (lchan->type) { + case GSM_LCHAN_TCH_F: + return 0x00; + case GSM_LCHAN_TCH_H: + return 0x03; + default: + break; + } case GSM48_CMODE_SPEECH_EFR: - return 0x01; + switch (lchan->type) { + case GSM_LCHAN_TCH_F: + return 0x01; + /* there's no half-rate EFR */ + default: + break; + } case GSM48_CMODE_SPEECH_AMR: - return 0x02; - /* FIXME: Type1 half-rate and type3 half-rate */ + switch (lchan->type) { + case GSM_LCHAN_TCH_F: + return 0x02; + case GSM_LCHAN_TCH_H: + return 0x05; + default: + break; + } + default: + break; } DEBUGPC(DRSL, "Cannot determine ip.access speech mode for " - "tch_mode == 0x%02x\n", tch_mode); + "tch_mode == 0x%02x\n", lchan->tch_mode); return 0; } @@ -1471,7 +1492,7 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan) dh->chan_nr = lchan2chan_nr(lchan); /* 0x1- == receive-only, 0x-1 == EFR codec */ - speech_mode = 0x10 | ipa_smod_s_for_tch_mode(lchan->tch_mode); + speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan); msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode); DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND " @@ -1498,7 +1519,7 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, dh->chan_nr = lchan2chan_nr(lchan); /* 0x0- == both directions, 0x-1 == EFR codec */ - speech_mode = 0x00 | ipa_smod_s_for_tch_mode(lchan->tch_mode); + speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan); ia.s_addr = htonl(ip); DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_MDCX " -- cgit v1.2.3 From d6575f9d29ff279ab843333a88c43a5ce40888b9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 2 Dec 2009 02:45:23 +0530 Subject: ip.access: add nanoBTS channel combination constraints --- openbsc/src/abis_nm.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index b1fe97ddf..30b3ec632 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1755,7 +1755,8 @@ static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) /* As it turns out, the BS-11 has some very peculiar restrictions * on the channel combinations it allows */ - if (ts->trx->bts->type == GSM_BTS_TYPE_BS11) { + switch (ts->trx->bts->type) { + case GSM_BTS_TYPE_BS11: switch (chan_comb) { case NM_CHANC_TCHHalf: case NM_CHANC_TCHHalf2: @@ -1801,6 +1802,83 @@ static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) /* FIXME: only one CBCH allowed per cell */ break; } + break; + case GSM_BTS_TYPE_NANOBTS: + switch (ts->nr) { + case 0: + if (ts->trx->nr == 0) { + /* only on TRX0 */ + switch (chan_comb) { + case NM_CHANC_BCCH: + case NM_CHANC_mainBCCH: + case NM_CHANC_BCCHComb: + return 0; + break; + default: + return -EINVAL; + } + } else { + switch (chan_comb) { + case NM_CHANC_TCHFull: + case NM_CHANC_TCHHalf: + case NM_CHANC_IPAC_TCHFull_TCHHalf: + return 0; + default: + return -EINVAL; + } + } + break; + case 1: + if (ts->trx->nr == 0) { + switch (chan_comb) { + case NM_CHANC_SDCCH_CBCH: + if (ts->trx->ts[0].nm_chan_comb == + NM_CHANC_mainBCCH) + return 0; + return -EINVAL; + case NM_CHANC_SDCCH: + case NM_CHANC_TCHFull: + case NM_CHANC_TCHHalf: + case NM_CHANC_IPAC_TCHFull_TCHHalf: + case NM_CHANC_IPAC_TCHFull_PDCH: + return 0; + } + } else { + switch (chan_comb) { + case NM_CHANC_SDCCH: + case NM_CHANC_TCHFull: + case NM_CHANC_TCHHalf: + case NM_CHANC_IPAC_TCHFull_TCHHalf: + return 0; + default: + return -EINVAL; + } + } + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + switch (chan_comb) { + case NM_CHANC_TCHFull: + case NM_CHANC_TCHHalf: + case NM_CHANC_IPAC_TCHFull_TCHHalf: + return 0; + case NM_CHANC_IPAC_PDCH: + case NM_CHANC_IPAC_TCHFull_PDCH: + if (ts->trx->nr == 0) + return 0; + else + return -EINVAL; + } + break; + } + return -EINVAL; + default: + /* unknown BTS type */ + return 0; } return 0; } -- cgit v1.2.3 From 1dfd0e254acdb44b150c53c1dd029ce25780f2f2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 4 Dec 2009 11:23:12 +0530 Subject: [BS11] don't put invalid channel combination into the config file --- openbsc/src/openbsc.cfg.1-1 | 2 +- openbsc/src/openbsc.cfg.2-2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/openbsc.cfg.1-1 b/openbsc/src/openbsc.cfg.1-1 index d312843b0..a25804f63 100644 --- a/openbsc/src/openbsc.cfg.1-1 +++ b/openbsc/src/openbsc.cfg.1-1 @@ -31,7 +31,7 @@ network phys_chan_config CCCH+SDCCH4 e1 line 0 timeslot 1 sub-slot full timeslot 1 - phys_chan_config SDCCH8 + phys_chan_config TCH/F e1 line 0 timeslot 2 sub-slot 1 timeslot 2 phys_chan_config TCH/F diff --git a/openbsc/src/openbsc.cfg.2-2 b/openbsc/src/openbsc.cfg.2-2 index c1468a647..9ae800342 100644 --- a/openbsc/src/openbsc.cfg.2-2 +++ b/openbsc/src/openbsc.cfg.2-2 @@ -31,7 +31,7 @@ network phys_chan_config CCCH+SDCCH4 e1 line 0 timeslot 1 sub-slot full timeslot 1 - phys_chan_config SDCCH8 + phys_chan_config TCH/F e1 line 0 timeslot 2 sub-slot 1 timeslot 2 phys_chan_config TCH/F -- cgit v1.2.3 From a897bf3dedfa0e9ce83434389c23993b84079656 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 5 Dec 2009 11:58:24 +0530 Subject: [system_information] fix BCCH list generation for GSM900 We have to make sure to skip the global list header --- openbsc/src/system_information.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index d6d166c79..30d15ac65 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -136,6 +136,8 @@ static int generate_bcch_chan_list(u_int8_t *chan_list, const struct gsm_bts *bt if (bts->band == GSM_BAND_900) { chan_list[0] = 0; llist_for_each_entry(cur_bts, &bts->list, list) { + if (&cur_bts->list == &bts->network->bts_list) + continue; trx = cur_bts->c0; rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); if (rc < 0) -- cgit v1.2.3 From ad69d7f8b2f4dff55b6244cad506113f33eed65c Mon Sep 17 00:00:00 2001 From: Steffen Neubauer Date: Thu, 26 Nov 2009 23:38:41 +0100 Subject: [sms] trivial: Removed unneeded double check in unbcdify --- openbsc/src/gsm_04_11.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 8e3c64974..4930e5c85 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -218,8 +218,7 @@ static u_int8_t unbcdify(u_int8_t value) DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); ret = (value&0x0F)*10; - if (ret > 90) - ret += value>>4; + ret += value>>4; return ret; } -- cgit v1.2.3 From f49fac278544f321456dcf96912b68059ad8d1af Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 24 Nov 2009 20:06:41 +0100 Subject: [bsc_hack] Ignore the sigpipe... We might read or write on the OML link when the BTS is reset and will get SIGPIPE interrupt and be gone... Just ignore the SIGPIPE we will get the "exception" on the next run of bsc_select and kill the (old) OML link. --- openbsc/src/bsc_hack.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index ee37a6115..0033e1c50 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -193,6 +193,7 @@ int main(int argc, char **argv) signal(SIGINT, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); + signal(SIGPIPE, SIG_IGN); while (1) { bsc_upqueue(bsc_gsmnet); -- cgit v1.2.3 From 1085c097e3abc7b76f71e33c01f0e2f87c031e74 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 18 Nov 2009 20:33:19 +0100 Subject: location updating reject cause now specified on VTY rather than command line argument --- openbsc/src/bsc_hack.c | 5 ----- openbsc/src/gsm_04_08.c | 9 ++------- openbsc/src/vty_interface.c | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 12 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 0033e1c50..1dd5e1020 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -73,7 +73,6 @@ static void print_help() printf(" -s --disable-color\n"); printf(" -c --config-file filename The config file to use.\n"); printf(" -l --database db-name The database to use\n"); - printf(" -r --reject-cause number The reject cause for LOCATION UPDATING REJECT.\n"); printf(" -p --pcap file The filename of the pcap file\n"); printf(" -T --timestamp Prefix every log line with a timestamp\n"); } @@ -89,7 +88,6 @@ static void handle_options(int argc, char** argv) {"disable-color", 0, 0, 's'}, {"database", 1, 0, 'l'}, {"authorize-everyone", 0, 0, 'a'}, - {"reject-cause", 1, 0, 'r'}, {"pcap", 1, 0, 'p'}, {"timestamp", 0, 0, 'T'}, {"rtp-proxy", 0, 0, 'P'}, @@ -118,9 +116,6 @@ static void handle_options(int argc, char** argv) case 'c': config_file = strdup(optarg); break; - case 'r': - gsm0408_set_reject_cause(atoi(optarg)); - break; case 'p': create_pcap_file(optarg); break; diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index f262dbebf..a8e8bd76a 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -241,12 +241,6 @@ struct gsm_lai { u_int16_t lac; }; -static int reject_cause = 0; -void gsm0408_set_reject_cause(int cause) -{ - reject_cause = cause; -} - static u_int32_t new_callref = 0x80000001; static int authorize_subscriber(struct gsm_loc_updating_operation *loc, @@ -978,9 +972,10 @@ static int mm_rx_id_resp(struct msgb *msg) static void loc_upd_rej_cb(void *data) { struct gsm_lchan *lchan = data; + struct gsm_bts *bts = lchan->ts->trx->bts; release_loc_updating_req(lchan); - gsm0408_loc_upd_rej(lchan, reject_cause); + gsm0408_loc_upd_rej(lchan, bts->network->reject_cause); lchan_auto_release(lchan); } diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 39fc41429..0ebd2bd9d 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -85,6 +85,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) net->name_short, VTY_NEWLINE); vty_out(vty, " Authentication policy: %s%s", gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE); + vty_out(vty, " Location updating reject cause: %u%s", + net->reject_cause, VTY_NEWLINE); vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption, VTY_NEWLINE); vty_out(vty, " NECI (TCH/H): %u%s", net->neci, @@ -273,6 +275,8 @@ static int config_write_net(struct vty *vty) vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE); vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE); vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE); + vty_out(vty, " location updating reject cause %u%s", + gsmnet->reject_cause, VTY_NEWLINE); vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); @@ -792,6 +796,16 @@ DEFUN(cfg_net_auth_policy, return CMD_SUCCESS; } +DEFUN(cfg_net_reject_cause, + cfg_net_reject_cause_cmd, + "location updating reject cause <2-111>", + "Set the reject cause of location updating reject\n") +{ + gsmnet->reject_cause = atoi(argv[0]); + + return CMD_SUCCESS; +} + DEFUN(cfg_net_encryption, cfg_net_encryption_cmd, "encryption a5 (0|1|2)", @@ -1292,6 +1306,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_name_short_cmd); install_element(GSMNET_NODE, &cfg_net_name_long_cmd); install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd); + install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd); install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); -- cgit v1.2.3 From 7bcb893eb78148250ed2b513e5e2a06fef7d47f3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 6 Dec 2009 12:23:47 +0530 Subject: remove execute permission from abis_nm.c --- openbsc/src/abis_nm.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 openbsc/src/abis_nm.c (limited to 'openbsc/src') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c old mode 100755 new mode 100644 -- cgit v1.2.3 From 24766091d8e389b5e5f55124ef00e73c160ed5da Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 9 Dec 2009 19:18:32 +0100 Subject: mark lchan2chan_nr() using a 'const' parameter which fixes some compile warnings at some callers. --- openbsc/src/abis_rsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 8a4ed9b76..d5c883e57 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -241,7 +241,7 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) } /* See Table 10.5.25 of GSM04.08 */ -u_int8_t lchan2chan_nr(struct gsm_lchan *lchan) +u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan) { struct gsm_bts_trx_ts *ts = lchan->ts; u_int8_t cbits, chan_nr; -- cgit v1.2.3 From 4669f3d9c8743305e1f808f084064d98feaccd77 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 9 Dec 2009 19:19:45 +0100 Subject: fix compile warning in db.c --- openbsc/src/db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 369505a2c..5dfefb53f 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -265,7 +265,7 @@ static int get_equipment_by_subscr(struct gsm_subscriber *subscr) { dbi_result result; const char *string; - unsigned int cm1; + unsigned char cm1; const unsigned char *cm2, *cm3; struct gsm_equipment *equip = &subscr->equipment; -- cgit v1.2.3 From d6aa52488a19674fb142e9619b579f600b2fec9a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 13:44:19 +0100 Subject: add warning about accept-all network on non-barred cells --- openbsc/src/bsc_init.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index d21f71a0c..c46fb2cdc 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -795,6 +795,14 @@ static int bootstrap_bts(struct gsm_bts *bts) return -EINVAL; } + if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL && + !bts->cell_barred) + fprintf(stderr, "\nWARNING: You are running an 'accept-all' " + "network on a BTS that is not barred. This " + "configuration is likely to interfere with production " + "GSM networks and should only be used in a RF " + "shielded environment such as a faraday cage!\n\n"); + /* Control Channel Description */ bts->si_common.chan_desc.att = 1; bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; -- cgit v1.2.3 From 854b9b33afc1b9719ef91624fbb1f4861bfdc1f1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 14:21:16 +0100 Subject: fix some integer underflows in MS power calculation --- openbsc/src/gsm_utils.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_utils.c b/openbsc/src/gsm_utils.c index ddfd7f3de..fe0b496bf 100644 --- a/openbsc/src/gsm_utils.c +++ b/openbsc/src/gsm_utils.c @@ -90,8 +90,10 @@ int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm) return 0; else if (dbm < 5) return 19; - else + else { + /* we are guaranteed to have (5 <= dbm < 39) */ return 2 + ((39 - dbm) / 2); + } break; case GSM_BAND_1800: if (dbm >= 36) @@ -100,16 +102,24 @@ int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm) return 30; else if (dbm >= 32) return 31; - else + else if (dbm == 31) + return 0; + else { + /* we are guaranteed to have (0 <= dbm < 31) */ return (30 - dbm) / 2; + } break; case GSM_BAND_1900: if (dbm >= 33) return 30; else if (dbm >= 32) return 31; - else + else if (dbm == 31) + return 0; + else { + /* we are guaranteed to have (0 <= dbm < 31) */ return (30 - dbm) / 2; + } break; } return -EINVAL; -- cgit v1.2.3 From 4bb4738d217596582a689169d12fdd6eb1ed8785 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 15:37:54 +0100 Subject: utility functions to convert RXLEV into dBm and vice versa --- openbsc/src/gsm_utils.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_utils.c b/openbsc/src/gsm_utils.c index fe0b496bf..9439993db 100644 --- a/openbsc/src/gsm_utils.c +++ b/openbsc/src/gsm_utils.c @@ -160,6 +160,28 @@ int ms_pwr_dbm(enum gsm_band band, u_int8_t lvl) return -EINVAL; } +/* According to TS 08.05 Chapter 8.1.4 */ +int rxlev2dbm(u_int8_t rxlev) +{ + if (rxlev > 63) + rxlev = 63; + + return -110 + rxlev; +} + +/* According to TS 08.05 Chapter 8.1.4 */ +u_int8_t dbm2rxlev(int dbm) +{ + int rxlev = dbm + 110; + + if (rxlev > 63) + rxlev = 63; + else if (rxlev < 0) + rxlev = 0; + + return rxlev; +} + void generate_backtrace() { int i, nptrs; -- cgit v1.2.3 From 1d8dbc4630b7d3e23aad8b5ebf043579afe2baa5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 15:38:16 +0100 Subject: print some more RF related information about BTS in VTY --- openbsc/src/vty_interface.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 0ebd2bd9d..809598fa4 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -128,6 +128,12 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) bts->cell_identity, bts->location_area_code, bts->bsic, bts->tsc, bts->num_trx, VTY_NEWLINE); + vty_out(vty, "MS Max power: %u dBm%s", bts->ms_max_power, VTY_NEWLINE); + vty_out(vty, "Minimum Rx Level for Access: %u dBm%s", + rxlev2dbm(bts->si_common.cell_sel_par.rxlev_acc_min), + VTY_NEWLINE); + vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s", + bts->si_common.cell_sel_par.cell_resel_hyst, VTY_NEWLINE); if (bts->cell_barred) vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) -- cgit v1.2.3 From 7322528ca1a331dc8cf404aae23aa8c2984a9190 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 18:17:25 +0100 Subject: [VTY] add more cell reselection parameters to VTY allow setting of 'cell reselection hysteresis' and 'rxlev access min' from VTY for experiments with cell reselection. --- openbsc/src/bsc_init.c | 2 -- openbsc/src/gsm_data.c | 2 ++ openbsc/src/vty_interface.c | 39 +++++++++++++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 6 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index c46fb2cdc..54aeb28cb 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -823,8 +823,6 @@ static int bootstrap_bts(struct gsm_bts *bts) bts->si_common.cell_sel_par.ms_txpwr_max_ccch = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); - bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */ - bts->si_common.cell_sel_par.rxlev_acc_min = 0; bts->si_common.cell_sel_par.acs = 0; bts->si_common.cell_sel_par.neci = bts->network->neci; diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 88de4c462..fef1127eb 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -167,6 +167,8 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, bts->num_trx = 0; INIT_LLIST_HEAD(&bts->trx_list); bts->ms_max_power = 15; /* dBm */ + bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */ + bts->si_common.cell_sel_par.rxlev_acc_min = 0; for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { bts->gprs.nsvc[i].bts = bts; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 809598fa4..529b0d481 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -129,11 +129,11 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) bts->location_area_code, bts->bsic, bts->tsc, bts->num_trx, VTY_NEWLINE); vty_out(vty, "MS Max power: %u dBm%s", bts->ms_max_power, VTY_NEWLINE); - vty_out(vty, "Minimum Rx Level for Access: %u dBm%s", + vty_out(vty, "Minimum Rx Level for Access: %i dBm%s", rxlev2dbm(bts->si_common.cell_sel_par.rxlev_acc_min), VTY_NEWLINE); vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s", - bts->si_common.cell_sel_par.cell_resel_hyst, VTY_NEWLINE); + bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); if (bts->cell_barred) vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) @@ -242,6 +242,10 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE); vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE); vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE); + vty_out(vty, " cell reselection hysteresis %u%s", + bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); + vty_out(vty, " rxlev access min %u%s", + bts->si_common.cell_sel_par.rxlev_acc_min, VTY_NEWLINE); if (bts->si_common.chan_desc.t3212) vty_out(vty, " periodic location update %u%s", bts->si_common.chan_desc.t3212 * 10, VTY_NEWLINE); @@ -465,8 +469,11 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) lchan->ts->trx->bts->nr, gsm_lchan_name(lchan->type), VTY_NEWLINE); vty_out(vty, " Use Count: %u%s", lchan->use_count, VTY_NEWLINE); - vty_out(vty, " BS Power %u, MS Power %u%s", lchan->bs_power, - lchan->ms_power, VTY_NEWLINE); + vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s", + lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red + - lchan->bs_power*2, + ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power), + VTY_NEWLINE); if (lchan->subscr) { vty_out(vty, " Subscriber:%s", VTY_NEWLINE); subscr_dump_vty(vty, lchan->subscr); @@ -1108,6 +1115,28 @@ DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd, return CMD_SUCCESS; } +DEFUN(cfg_bts_cell_resel_hyst, cfg_bts_cell_resel_hyst_cmd, + "cell reselection hysteresis <0-14>", + "Cell Re-Selection Hysteresis in dB") +{ + struct gsm_bts *bts = vty->index; + + bts->si_common.cell_sel_par.cell_resel_hyst = atoi(argv[0])/2; + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_rxlev_acc_min, cfg_bts_rxlev_acc_min_cmd, + "rxlev access min <0-63>", + "Minimum RxLev needed for cell access (better than -110dBm)") +{ + struct gsm_bts *bts = vty->index; + + bts->si_common.cell_sel_par.rxlev_acc_min = atoi(argv[0]); + + return CMD_SUCCESS; +} + DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd, "periodic location update <0-1530>", "Periodic Location Updating Interval in Minutes") @@ -1344,6 +1373,8 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_cell_barred_cmd); install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd); install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd); + install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd); + install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd); install_element(BTS_NODE, &cfg_trx_cmd); -- cgit v1.2.3 From 9e2748ed3a2e8fa3d2939d145129937da7bcf785 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 20:53:23 +0100 Subject: [RSL] print human-readable channel type during channel allocation failure --- openbsc/src/abis_rsl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index d5c883e57..c6675c840 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1236,8 +1236,8 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { - DEBUGP(DRSL, "CHAN RQD: no resources for %u 0x%x\n", - lctype, rqd_ref->ra); + DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n", + gsm_lchan_name(lctype), rqd_ref->ra); /* FIXME: send some kind of reject ?!? */ return -ENOMEM; } -- cgit v1.2.3 From 9385c1172791e2bd1cdd4081648ad55ffa4b6f28 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 20:57:52 +0100 Subject: If we establish a TCH/H voice call, the reason is CALL, not OTHER --- openbsc/src/gsm_04_08_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index d3e4689b5..8497fa842 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -308,7 +308,7 @@ static const enum gsm_chreq_reason_t reason_by_chreq[] = { [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL, [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER, [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_CALL, [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD, [CHREQ_T_PAG_R_ANY_NECI1] = GSM_CHREQ_REASON_PAG, -- cgit v1.2.3 From 210c850a3663eaf333ad44270415220aa1fe9d70 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 20:58:20 +0100 Subject: If we're trying to allocate TCH/H but don't have it, fallback to TCH/F The rationale is as following: If we have NECI=1, then the phone will request a channel with CHREQ "0100xxxx Originating speech call from dual-rate mobile station when TCH/H is sufficient and supported by the MS for speech calls", then we will try to allocate a TCH/H [as it is sufficient]. However, if there are no free TCH/H slots on the BTS, we abandon and can't handle the MO call at all :( --- openbsc/src/chan_alloc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 7ba679c87..6bf65f325 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -203,6 +203,9 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) break; case GSM_LCHAN_TCH_H: lchan =_lc_find_bts(bts, GSM_PCHAN_TCH_H); + /* If we don't have TCH/H available, fall-back to TCH/F */ + if (!lchan) + lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); break; default: fprintf(stderr, "Unknown gsm_chan_t %u\n", type); -- cgit v1.2.3 From b83d938565d3f47d8b6f813e5f326429bc31857d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 21:00:48 +0100 Subject: [04.08] use lchan_auto_release to quickly close channel In some cases, we can try to close the lchan a bit faster than our lchan release timeout: * After we've sent LOC UPD ACCEPT and MM INFO * After a phone has confirmed the RELEASE of a call --- openbsc/src/gsm_04_08.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index a8e8bd76a..a1fa5462b 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -299,11 +299,16 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg) db_subscriber_alloc_tmsi(lchan->subscr); release_loc_updating_req(lchan); rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi); + /* send MM INFO with network name */ + rc = gsm48_tx_mm_info(msg->lchan); + /* call subscr_update after putting the loc_upd_acc * in the transmit queue, since S_SUBSCR_ATTACHED might * trigger further action like SMS delivery */ subscr_update(lchan->subscr, msg->trx->bts, GSM_SUBSCRIBER_UPDATE_ATTACHED); + /* try to close channel ASAP */ + lchan_auto_release(lchan); return rc; } @@ -885,7 +890,6 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) struct gsm48_hdr *gh; struct gsm48_loc_area_id *lai; u_int8_t *mid; - int ret; msg->lchan = lchan; @@ -902,12 +906,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - ret = gsm48_sendmsg(msg, NULL); - - /* send MM INFO with network name */ - ret = gsm48_tx_mm_info(lchan); - - return ret; + return gsm48_sendmsg(msg, NULL); } /* Transmit Chapter 9.2.10 Identity Request */ @@ -1374,6 +1373,8 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) } else DEBUGP(DMM, "Unknown Subscriber ?!?\n"); + /* subscriber is detached: should we release lchan? */ + return 0; } @@ -2726,6 +2727,9 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg) case GSM_CSTATE_RELEASE_REQ: rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel); + /* FIXME: in case of multiple calls, we can't simply + * hang up here ! */ + lchan_auto_release(msg->lchan); break; default: rc = mncc_recvmsg(trans->subscr->net, trans, -- cgit v1.2.3 From 487e6befb85a8e6f114d916045b65174c35810a8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 21:16:38 +0100 Subject: make speech calls with NECI=1 work Fix minor bug with speech calls in case of NECI=1 --- openbsc/src/chan_alloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 6bf65f325..2f0d7b93f 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -204,8 +204,10 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) case GSM_LCHAN_TCH_H: lchan =_lc_find_bts(bts, GSM_PCHAN_TCH_H); /* If we don't have TCH/H available, fall-back to TCH/F */ - if (!lchan) + if (!lchan) { lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); + type = GSM_LCHAN_TCH_F; + } break; default: fprintf(stderr, "Unknown gsm_chan_t %u\n", type); -- cgit v1.2.3 From 09b7e7fa43c74d35e8ea935f3096993e3360f33a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 12 Dec 2009 21:36:53 +0100 Subject: Gracefully reject non-speech calls As we currently really only deal with voice/speech calls and don't support FAX and DATA (CSD) calls, we now gracefully reject them. --- openbsc/src/gsm_04_08.c | 54 +++++++++++++++++++++++++++++++------------------ openbsc/src/mncc.c | 33 +++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 25 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index a1fa5462b..e1374c9ae 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -439,18 +439,29 @@ static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap, bcap->coding = (lv[1] & 0x10) >> 4; bcap->radio = (lv[1] & 0x60) >> 5; - i = 1; - s = 0; - while(!(lv[i] & 0x80)) { - i++; /* octet 3a etc */ - if (in_len < i) - return 0; - bcap->speech_ver[s++] = lv[i] & 0x0f; - bcap->speech_ver[s] = -1; /* end of list */ - if (i == 2) /* octet 3a */ - bcap->speech_ctm = (lv[i] & 0x20) >> 5; - if (s == 7) /* maximum speech versions + end of list */ - return 0; + if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) { + i = 1; + s = 0; + while(!(lv[i] & 0x80)) { + i++; /* octet 3a etc */ + if (in_len < i) + return 0; + bcap->speech_ver[s++] = lv[i] & 0x0f; + bcap->speech_ver[s] = -1; /* end of list */ + if (i == 2) /* octet 3a */ + bcap->speech_ctm = (lv[i] & 0x20) >> 5; + if (s == 7) /* maximum speech versions + end of list */ + return 0; + } + } else { + i = 1; + while (!(lv[i] & 0x80)) { + i++; /* octet 3a etc */ + if (in_len < i) + return 0; + /* ignore them */ + } + /* FIXME: implement OCTET 4+ parsing */ } return 0; @@ -461,21 +472,24 @@ static int encode_bearer_cap(struct msgb *msg, int lv_only, const struct gsm_mncc_bearer_cap *bcap) { u_int8_t lv[32 + 1]; - int i, s; + int i = 1, s; lv[1] = bcap->transfer; lv[1] |= bcap->mode << 3; lv[1] |= bcap->coding << 4; lv[1] |= bcap->radio << 5; - i = 1; - for (s = 0; bcap->speech_ver[s] >= 0; s++) { - i++; /* octet 3a etc */ - lv[i] = bcap->speech_ver[s]; - if (i == 2) /* octet 3a */ - lv[i] |= bcap->speech_ctm << 5; + if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) { + for (s = 0; bcap->speech_ver[s] >= 0; s++) { + i++; /* octet 3a etc */ + lv[i] = bcap->speech_ver[s]; + if (i == 2) /* octet 3a */ + lv[i] |= bcap->speech_ctm << 5; + } + lv[i] |= 0x80; /* last IE of octet 3 etc */ + } else { + /* FIXME: implement OCTET 4+ encoding */ } - lv[i] |= 0x80; /* last IE of octet 3 etc */ lv[0] = i; if (lv_only) diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index f62541c05..de1765761 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -136,19 +137,36 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, struct gsm_mncc mncc; struct gsm_call *remote; + memset(&mncc, 0, sizeof(struct gsm_mncc)); + mncc.callref = call->callref; + /* already have remote call */ if (call->remote_ref) return 0; + /* transfer mode 1 would be packet mode, which was never specified */ + if (setup->bearer_cap.mode != 0) { + DEBUGP(DMNCC, "(call %x) We don't support packet mode\n", + call->callref); + mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); + goto out_reject; + } + + /* we currently only do speech */ + if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) { + DEBUGP(DMNCC, "(call %x) We only support voice calls\n", + call->callref); + mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, + GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); + goto out_reject; + } + /* create remote call */ if (!(remote = talloc(tall_call_ctx, struct gsm_call))) { - memset(&mncc, 0, sizeof(struct gsm_mncc)); - mncc.callref = call->callref; mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_RESOURCE_UNAVAIL); - mncc_send(call->net, MNCC_REJ_REQ, &mncc); - free_call(call); - return 0; + goto out_reject; } llist_add_tail(&remote->entry, &call_list); remote->net = call->net; @@ -179,6 +197,11 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, setup->callref = remote->callref; DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref); return mncc_send(remote->net, MNCC_SETUP_REQ, setup); + +out_reject: + mncc_send(call->net, MNCC_REJ_REQ, &mncc); + free_call(call); + return 0; } static int mncc_alert_ind(struct gsm_call *call, int msg_type, -- cgit v1.2.3 From eab84a112c3ef8c35835a2ba23fa978fff4d218b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 13 Dec 2009 10:53:12 +0100 Subject: [RRLP] make RRLP mode configurable from config file We now support different RRLP modes (including "none" to disable RRLP), you can configure it via "rrlp mode" in the "network" section of openbsc.cfg. --- openbsc/src/gsm_data.c | 23 +++++++++++++++++++++++ openbsc/src/rrlp.c | 44 +++++++++++++++++++++++++++++++++++++------- openbsc/src/vty_interface.c | 14 ++++++++++++++ 3 files changed, 74 insertions(+), 7 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index fef1127eb..cdaba9e52 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -367,3 +367,26 @@ const char *gsm_auth_policy_name(enum gsm_auth_policy policy) return gsm_auth_policy_names[policy]; } +static const char *rrlp_mode_names[] = { + [RRLP_MODE_NONE] = "none", + [RRLP_MODE_MS_BASED] = "ms-based", + [RRLP_MODE_MS_PREF] = "ms-preferred", + [RRLP_MODE_ASS_PREF] = "ass-preferred", +}; + +enum rrlp_mode rrlp_mode_parse(const char *arg) +{ + int i; + for (i = 0; i < ARRAY_SIZE(rrlp_mode_names); i++) { + if (!strcmp(arg, rrlp_mode_names[i])) + return i; + } + return RRLP_MODE_NONE; +} + +const char *rrlp_mode_name(enum rrlp_mode mode) +{ + if (mode > ARRAY_SIZE(rrlp_mode_names)) + return "none"; + return rrlp_mode_names[mode]; +} diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c index 523b53f0b..60ce750ad 100644 --- a/openbsc/src/rrlp.c +++ b/openbsc/src/rrlp.c @@ -1,4 +1,4 @@ - +/* Radio Resource LCS (Location) Protocol, GMS TS 04.31 */ /* (C) 2009 by Harald Welte * @@ -28,9 +28,42 @@ #include #include -/* RRLP MS based position request */ +/* RRLP msPositionReq, nsBased, + * Accuracy=60, Method=gps, ResponseTime=2, oneSet */ static const u_int8_t ms_based_pos_req[] = { 0x40, 0x01, 0x78, 0xa8 }; +/* RRLP msPositionReq, msBasedPref, + Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */ +static const u_int8_t ms_pref_pos_req[] = { 0x40, 0x02, 0x79, 0x50 }; + +/* RRLP msPositionReq, msAssistedPref, + Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */ +static const u_int8_t ass_pref_pos_req[] = { 0x40, 0x03, 0x79, 0x50 }; + +static int send_rrlp_req(struct gsm_lchan *lchan) +{ + struct gsm_network *net = lchan->ts->trx->bts->network; + const u_int8_t *req; + + switch (net->rrlp.mode) { + case RRLP_MODE_MS_BASED: + req = ms_based_pos_req; + break; + case RRLP_MODE_MS_PREF: + req = ms_pref_pos_req; + break; + case RRLP_MODE_ASS_PREF: + req = ass_pref_pos_req; + break; + case RRLP_MODE_NONE: + default: + return 0; + } + + return gsm48_send_rr_app_info(lchan, 0x00, + sizeof(ms_based_pos_req), req); +} + static int subscr_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { @@ -44,8 +77,7 @@ static int subscr_sig_cb(unsigned int subsys, unsigned int signal, lchan = lchan_for_subscr(subscr); if (!lchan) break; - gsm48_send_rr_app_info(lchan, 0x00, sizeof(ms_based_pos_req), - ms_based_pos_req); + send_rrlp_req(lchan); break; } return 0; @@ -59,9 +91,7 @@ static int paging_sig_cb(unsigned int subsys, unsigned int signal, switch (signal) { case S_PAGING_COMPLETED: /* A subscriber has attached. */ - gsm48_send_rr_app_info(psig_data->lchan, 0x00, - sizeof(ms_based_pos_req), - ms_based_pos_req); + send_rrlp_req(psig_data->lchan); break; } return 0; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 529b0d481..adef1480a 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -91,6 +91,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) VTY_NEWLINE); vty_out(vty, " NECI (TCH/H): %u%s", net->neci, VTY_NEWLINE); + vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode), + VTY_NEWLINE); } DEFUN(show_net, show_net_cmd, "show network", @@ -289,6 +291,8 @@ static int config_write_net(struct vty *vty) gsmnet->reject_cause, VTY_NEWLINE); vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); + vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), + VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); @@ -838,6 +842,15 @@ DEFUN(cfg_net_neci, return CMD_SUCCESS; } +DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd, + "rrlp mode (none|ms-based|ms-preferred|ass-preferred)", + "Set the Radio Resource Location Protocol Mode") +{ + gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]); + + return CMD_SUCCESS; +} + #define DECLARE_TIMER(number) \ DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ @@ -1344,6 +1357,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd); install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); + install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd); -- cgit v1.2.3 From 7659de1bcbd22f48c41f76ea9e41dc71c9ed1cee Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 13 Dec 2009 12:39:18 +0100 Subject: introduce new signal every time we get a mobile identity --- openbsc/src/gsm_04_08.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index e1374c9ae..ce93f0130 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -954,6 +954,8 @@ static int mm_rx_id_resp(struct msgb *msg) DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n", mi_type, mi_string); + dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, gh->data); + switch (mi_type) { case GSM_MI_TYPE_IMSI: /* look up subscriber based on IMSI, create if not found */ @@ -1034,6 +1036,8 @@ static int mm_rx_loc_upd_req(struct msgb *msg) DEBUGPC(DMM, "mi_type=0x%02x MI(%s) type=%s ", mi_type, mi_string, lupd_name(lu->type)); + dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, &lu->mi_len); + /* * Pseudo Spoof detection: Just drop a second/concurrent * location updating request. @@ -1317,6 +1321,8 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg) DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n", req->cm_service_type, mi_type, mi_string); + dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, (classmark2 + classmark2_len)); + if (is_siemens_bts(bts)) send_siemens_mrpci(msg->lchan, classmark2-1); -- cgit v1.2.3 From 37600be76cb022dbd51d768500613d9a8066990f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 13 Dec 2009 12:56:47 +0100 Subject: fix segfault in token_auth on SS_SUBSCR != ATTACH --- openbsc/src/token_auth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/token_auth.c b/openbsc/src/token_auth.c index 0931007ef..f6be0bc98 100644 --- a/openbsc/src/token_auth.c +++ b/openbsc/src/token_auth.c @@ -60,10 +60,10 @@ static int token_subscr_cb(unsigned int subsys, unsigned int signal, struct gsm_sms *sms; int rc = 0; - if (subscr->net->auth_policy != GSM_AUTH_POLICY_TOKEN) + if (signal != S_SUBSCR_ATTACHED) return 0; - if (signal != S_SUBSCR_ATTACHED) + if (subscr->net->auth_policy != GSM_AUTH_POLICY_TOKEN) return 0; if (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) { -- cgit v1.2.3 From 648b6ce083e3826b5df912de61214961f4950321 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 09:00:24 +0100 Subject: Add VTY setting for whether or not to sending MM INFO --- openbsc/src/gsm_04_08.c | 6 ++++-- openbsc/src/vty_interface.c | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index ce93f0130..9e01d9c70 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -299,8 +299,10 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg) db_subscriber_alloc_tmsi(lchan->subscr); release_loc_updating_req(lchan); rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi); - /* send MM INFO with network name */ - rc = gsm48_tx_mm_info(msg->lchan); + if (lchan->ts->trx->bts->network->send_mm_info) { + /* send MM INFO with network name */ + rc = gsm48_tx_mm_info(msg->lchan); + } /* call subscr_update after putting the loc_upd_acc * in the transmit queue, since S_SUBSCR_ATTACHED might diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index adef1480a..7b7f4d158 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -93,6 +93,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) VTY_NEWLINE); vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode), VTY_NEWLINE); + vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off", + VTY_NEWLINE); } DEFUN(show_net, show_net_cmd, "show network", @@ -293,6 +295,7 @@ static int config_write_net(struct vty *vty) vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), VTY_NEWLINE); + vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); @@ -851,6 +854,15 @@ DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd, return CMD_SUCCESS; } +DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd, + "mm info (0|1)", + "Whether to send MM INFO after LOC UPD ACCEPT") +{ + gsmnet->send_mm_info = atoi(argv[0]); + + return CMD_SUCCESS; +} + #define DECLARE_TIMER(number) \ DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ -- cgit v1.2.3 From 3d23db43a486994e4ab1709955775da854f89537 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 17:49:15 +0100 Subject: [PATCH] fix MM INFO parsing in vty_interface --- openbsc/src/vty_interface.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc/src') diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 7b7f4d158..d5344edac 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1370,6 +1370,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd); + install_element(GSMNET_NODE, &cfg_net_mm_info_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd); -- cgit v1.2.3 From ade7a14e750116ebe6a9de431772ff84df845fbe Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 17:49:52 +0100 Subject: make sure BSIC is patched into NM tables before initializing BS11 --- openbsc/src/bsc_init.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 54aeb28cb..ef68ef936 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -575,6 +575,7 @@ static void nm_reconfig_bts(struct gsm_bts *bts) switch (bts->type) { case GSM_BTS_TYPE_BS11: + patch_nm_tables(bts); abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/ abis_nm_set_bts_attr(bts, bs11_attr_bts, sizeof(bs11_attr_bts)); abis_nm_raw_msg(bts, sizeof(msg_3), msg_3); /* set BTS handover attr */ -- cgit v1.2.3 From 1e191c59f6130c04b4e02a27dbd91900078e1c14 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 17:51:15 +0100 Subject: fix compiler warnings in gsm_04_08.c --- openbsc/src/gsm_04_08.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 9e01d9c70..88b1b6900 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1582,7 +1582,7 @@ static int gsm48_rx_rr_app_info(struct msgb *msg) } /* Chapter 9.1.16 Handover complete */ -static gsm48_rx_rr_ho_compl(struct msgb *msg) +static int gsm48_rx_rr_ho_compl(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); @@ -1596,7 +1596,7 @@ static gsm48_rx_rr_ho_compl(struct msgb *msg) } /* Chapter 9.1.17 Handover Failure */ -static gsm48_rx_rr_ho_fail(struct msgb *msg) +static int gsm48_rx_rr_ho_fail(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); -- cgit v1.2.3 From da760d3d19bc6da3ef676a2fbaa65fb841cd5af5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 20:25:05 +0100 Subject: [system_information] fix bit map 0 frequency list generation Our frequency lists for GSM900 were completely wrong, as the bit map 0 encoding was not used correctly. This patch should fix it. --- openbsc/src/system_information.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 30d15ac65..60a8219b2 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -35,21 +35,28 @@ #define GSM_MACBLOCK_LEN 23 #define GSM_MACBLOCK_PADDING 0x2b +/* Frequency Lists as per TS 04.08 10.5.2.13 */ + +/* 10.5.2.13.2: Bit map 0 format */ static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; - if (arfcn > 124) + if (arfcn > 124 || arfcn < 1) return -EINVAL; + /* the bitmask is from 1..124, not from 0..123 */ + arfcn--; + byte = arfcn / 8; bit = arfcn % 8; - chan_list[GSM48_CELL_CHAN_DESC_SIZE-byte] |= (1 << bit); + chan_list[GSM48_CELL_CHAN_DESC_SIZE-1-byte] |= (1 << bit); return 0; } +/* 10.5.2.13.7: Variable bit map format */ static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; -- cgit v1.2.3 From d57f163bd4040cddf59cb145affba2c2d2570c42 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:04:31 +0100 Subject: bitvec updates and code simplification * introduce a new bitvec_get_bit_pos() function to determine the bit value at a given position inside a bit vector * make sure bitvec_{get,set}_bit_pos() share code as possible --- openbsc/src/bitvec.c | 49 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c index ac2554475..8c82b8776 100644 --- a/openbsc/src/bitvec.c +++ b/openbsc/src/bitvec.c @@ -35,15 +35,10 @@ static inline unsigned int bytenum_from_bitnum(unsigned int bitnum) return bytenum; } -int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, - enum bit_value bit) +/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */ +static u_int8_t bitval2mask(enum bit_value bit, u_int8_t bitnum) { - unsigned int bytenum = bytenum_from_bitnum(bitnr); - unsigned int bitnum = 7 - (bitnr % 8); - u_int8_t bitval; - - if (bytenum >= bv->data_len) - return -EINVAL; + int bitval; switch (bit) { case ZERO: @@ -59,8 +54,41 @@ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum)); break; default: - return -EINVAL; + return 0; } + return bitval; +} + +/* check if the bit is 0 or 1 for a given position inside a bitvec */ +enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr) +{ + unsigned int bytenum = bytenum_from_bitnum(bitnr); + unsigned int bitnum = 7 - (bitnr % 8); + u_int8_t bitval; + + if (bytenum >= bv->data_len) + return -EINVAL; + + bitval = bitval2mask(ONE, bitnum); + + if (bv->data[bytenum] & bitval) + return ONE; + + return ZERO; +} + +/* set the bit at a given position inside a bitvec */ +int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, + enum bit_value bit) +{ + unsigned int bytenum = bytenum_from_bitnum(bitnr); + unsigned int bitnum = 7 - (bitnr % 8); + u_int8_t bitval; + + if (bytenum >= bv->data_len) + return -EINVAL; + + bitval = bitval2mask(ONE, bitnum); /* first clear the bit */ bv->data[bytenum] &= ~(1 << bitnum); @@ -71,6 +99,7 @@ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, return 0; } +/* set the next bit inside a bitvec */ int bitvec_set_bit(struct bitvec *bv, enum bit_value bit) { int rc; @@ -82,6 +111,7 @@ int bitvec_set_bit(struct bitvec *bv, enum bit_value bit) return rc; } +/* set multiple bits (based on array of bitvals) at current pos */ int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count) { int i, rc; @@ -95,6 +125,7 @@ int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count) return 0; } +/* set multiple bits (based on numeric value) at current pos */ int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits) { int i, rc; -- cgit v1.2.3 From 6c40def716b757a1aa683d9414b2320d3fc20c8a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:07:14 +0100 Subject: system_information: use bitvec to generate frequency lists We use a 1024-bit-sized bitvec to generate the BA and neighbor frequency list. This bitvec is still generated from the list of all BTS's inside the BSC, but this patch is the first step to generalize this, i.e. generate arbitrary neighbor lists. --- openbsc/src/gsm_data.c | 6 ++ openbsc/src/system_information.c | 115 +++++++++++++++++---------------------- 2 files changed, 55 insertions(+), 66 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index cdaba9e52..3cf9e3c4d 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -169,6 +169,12 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, bts->ms_max_power = 15; /* dBm */ bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */ bts->si_common.cell_sel_par.rxlev_acc_min = 0; + bts->si_common.neigh_list.data = bts->si_common.data.neigh_list; + bts->si_common.neigh_list.data_len = + sizeof(bts->si_common.data.neigh_list); + bts->si_common.cell_alloc.data = bts->si_common.data.cell_alloc; + bts->si_common.cell_alloc.data_len = + sizeof(bts->si_common.data.cell_alloc); for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { bts->gprs.nsvc[i].bts = bts; diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 60a8219b2..2d4ba20a4 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #define GSM48_CELL_CHAN_DESC_SIZE 16 #define GSM_MACBLOCK_LEN 23 @@ -38,7 +40,7 @@ /* Frequency Lists as per TS 04.08 10.5.2.13 */ /* 10.5.2.13.2: Bit map 0 format */ -static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) +static int freq_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; @@ -57,7 +59,7 @@ static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) } /* 10.5.2.13.7: Variable bit map format */ -static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) +static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; unsigned int min_arfcn; @@ -86,20 +88,23 @@ static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) } /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ -static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts) +static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv, + const struct gsm_bts *bts) { - struct gsm_bts_trx *trx; - int rc, min = 1024, max = 0; + int i, rc, min = 1024, max = 0; memset(chan_list, 0, 16); /* GSM900-only handsets only support 'bit map 0 format' */ if (bts->band == GSM_BAND_900) { chan_list[0] = 0; - llist_for_each_entry(trx, &bts->trx_list, list) { - rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); - if (rc < 0) - return rc; + + for (i = 0; i < bv->data_len*8; i++) { + if (bitvec_get_bit_pos(bv, i)) { + rc = freq_list_bm0_set_arfcn(chan_list, i); + if (rc < 0) + return rc; + } } return 0; } @@ -107,11 +112,13 @@ static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bt /* We currently only support the 'Variable bitmap format' */ chan_list[0] = 0x8e; - llist_for_each_entry(trx, &bts->trx_list, list) { - if (trx->arfcn < min) - min = trx->arfcn; - if (trx->arfcn > max) - max = trx->arfcn; + for (i = 0; i < bv->data_len*8; i++) { + if (bitvec_get_bit_pos(bv, i)) { + if (i < min) + min = i; + if (i > max) + max = i; + } } if ((max - min) > 111) @@ -121,8 +128,8 @@ static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bt chan_list[1] = (min >> 1); chan_list[2] = (min & 1) << 7; - llist_for_each_entry(trx, &bts->trx_list, list) { - rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn); + for (i = 0; i < bv->data_len*8; i++) { + rc = freq_list_bmrel_set_arfcn(chan_list, i); if (rc < 0) return rc; } @@ -131,61 +138,37 @@ static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bt } /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ -static int generate_bcch_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts) +static int generate_cell_chan_list(u_int8_t *chan_list, struct gsm_bts *bts) { - struct gsm_bts *cur_bts; struct gsm_bts_trx *trx; - int rc, min = 1024, max = 0; - - memset(chan_list, 0, 16); - - /* GSM900-only handsets only support 'bit map 0 format' */ - if (bts->band == GSM_BAND_900) { - chan_list[0] = 0; - llist_for_each_entry(cur_bts, &bts->list, list) { - if (&cur_bts->list == &bts->network->bts_list) - continue; - trx = cur_bts->c0; - rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn); - if (rc < 0) - return rc; - } - return 0; - } - - /* We currently only support the 'Variable bitmap format' */ - chan_list[0] = 0x8e; + struct bitvec *bv = &bts->si_common.cell_alloc; - llist_for_each_entry(cur_bts, &bts->list, list) { - if (&cur_bts->list == &bts->network->bts_list) - continue; - trx = cur_bts->c0; - if (trx->arfcn < min) - min = trx->arfcn; - if (trx->arfcn > max) - max = trx->arfcn; - } + /* first we generate a bitvec of all TRX ARFCN's in our BTS */ + llist_for_each_entry(trx, &bts->trx_list, list) + bitvec_set_bit_pos(bv, trx->arfcn, 1); - if ((max - min) > 111) - return -EINVAL; + /* then we generate a GSM 04.08 frequency list from the bitvec */ + return bitvec2freq_list(chan_list, bv, bts); +} - chan_list[0] |= (min >> 9) & 1; - chan_list[1] = (min >> 1); - chan_list[2] = (min & 1) << 7; +/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ +static int generate_bcch_chan_list(u_int8_t *chan_list, struct gsm_bts *bts) +{ + struct gsm_bts *cur_bts; + struct bitvec *bv = &bts->si_common.neigh_list; - llist_for_each_entry(cur_bts, &bts->list, list) { - if (&cur_bts->list == &bts->network->bts_list) + /* first we generate a bitvec of the BCCH ARFCN's in our BSC */ + llist_for_each_entry(cur_bts, &bts->network->bts_list, list) { + if (cur_bts == bts) continue; - trx = cur_bts->c0; - rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn); - if (rc < 0) - return rc; + bitvec_set_bit_pos(bv, cur_bts->c0->arfcn, 1); } - return 0; + /* then we generate a GSM 04.08 frequency list from the bitvec */ + return bitvec2freq_list(chan_list, bv, bts); } -static int generate_si1(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si1(u_int8_t *output, struct gsm_bts *bts) { int rc; struct gsm48_system_information_type_1 *si1 = @@ -210,7 +193,7 @@ static int generate_si1(u_int8_t *output, const struct gsm_bts *bts) return GSM_MACBLOCK_LEN; } -static int generate_si2(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si2(u_int8_t *output, struct gsm_bts *bts) { int rc; struct gsm48_system_information_type_2 *si2 = @@ -257,7 +240,7 @@ struct gsm48_si_ro_info si_info = { .break_ind = 0, }; -static int generate_si3(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si3(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_3 *si3 = (struct gsm48_system_information_type_3 *) output; @@ -287,7 +270,7 @@ static int generate_si3(u_int8_t *output, const struct gsm_bts *bts) return GSM_MACBLOCK_LEN; } -static int generate_si4(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si4(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_4 *si4 = (struct gsm48_system_information_type_4 *) output; @@ -319,7 +302,7 @@ static int generate_si4(u_int8_t *output, const struct gsm_bts *bts) return GSM_MACBLOCK_LEN; } -static int generate_si5(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si5(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_5 *si5 = (struct gsm48_system_information_type_5 *) output; @@ -339,7 +322,7 @@ static int generate_si5(u_int8_t *output, const struct gsm_bts *bts) return 18; } -static int generate_si6(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si6(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_6 *si6 = (struct gsm48_system_information_type_6 *) output; @@ -390,7 +373,7 @@ static struct gsm48_si13_info si13_default = { }, }; -static int generate_si13(u_int8_t *output, const struct gsm_bts *bts) +static int generate_si13(u_int8_t *output, struct gsm_bts *bts) { struct gsm48_system_information_type_13 *si13 = (struct gsm48_system_information_type_13 *) output; -- cgit v1.2.3 From 7f73a1ac58d6b9f2f8ec793123bf0ee3038fb3a4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:23:27 +0100 Subject: bitvec: Introduce bitvec_get_nth_set_bit() function This is particularly important for determining the ARFCN for cells reported in 04.08 MEAS REP. --- openbsc/src/bitvec.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c index 8c82b8776..ad03958f3 100644 --- a/openbsc/src/bitvec.c +++ b/openbsc/src/bitvec.c @@ -77,6 +77,22 @@ enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr) return ZERO; } +/* get the Nth set bit inside the bit vector */ +unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n) +{ + unsigned int i, k = 0; + + for (i = 0; i < bv->data_len*8; i++) { + if (bitvec_get_bit_pos(bv, i) == ONE) { + k++; + if (k == n) + return i; + } + } + + return 0; +} + /* set the bit at a given position inside a bitvec */ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, enum bit_value bit) -- cgit v1.2.3 From f1dae1924a80e614982513707b4ee568d2126e1b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:24:28 +0100 Subject: 04.08 MEAS REP: Convert relative cell number to ARFCN Since we are keeping a bitvec of the neighbor cells, we can now use bitvec_get_nth_set_bit() to determine the ARFCN for each reported cell in the 04.08 MEASUREMENT REPORT. --- openbsc/src/gsm_04_08.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 88b1b6900..6d05a20ad 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -171,6 +172,8 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) struct gsm48_hdr *gh = msgb_l3(msg); unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); u_int8_t *data = gh->data; + struct gsm_bts *bts = msg->lchan->ts->trx->bts; + struct bitvec *nbv = &bts->si_common.neigh_list; if (gh->msg_type != GSM48_MT_RR_MEAS_REP) return -EINVAL; @@ -194,37 +197,39 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) /* an encoding nightmare in perfection */ rep->cell[0].rxlev = data[4] & 0x3f; - rep->cell[0].bcch_freq = data[5] >> 2; + rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[5] >> 2); rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5); if (rep->num_cell < 2) return 0; rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7); - rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f; + rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[7] >> 2) & 0x1f); rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4); if (rep->num_cell < 3) return 0; rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6); - rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f; + rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[9] >> 1) & 0x1f); rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3); if (rep->num_cell < 4) return 0; rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5); - rep->cell[3].bcch_freq = data[11] & 0x1f; + rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[11] & 0x1f); rep->cell[3].bsic = data[12] >> 2; if (rep->num_cell < 5) return 0; rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4); - rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7); + rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv, + ((data[13] & 0xf) << 1) | (data[14] >> 7)); rep->cell[4].bsic = (data[14] >> 1) & 0x3f; if (rep->num_cell < 6) return 0; rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3); - rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6); + rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv, + ((data[15] & 0x07) << 2) | (data[16] >> 6)); rep->cell[5].bsic = data[16] & 0x3f; return 0; -- cgit v1.2.3 From 84874c9005fd568d423f6fde9caedd36dc5bff57 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 14 Dec 2009 22:33:02 +0100 Subject: Implement gsm_bts_neighbor() function to determine neighbor BTS We will need this for the actual handover algorithm implementation, as we will only know the current BTS and the BCCH ARFCN of the strongest cell in the measurement reports. Using this new function, we can resolve the matching gsm_bts. --- openbsc/src/gsm_data.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 3cf9e3c4d..9fb4526f0 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -234,6 +234,23 @@ struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num) return NULL; } +/* Get reference to a neighbor cell on a given BCCH ARFCN */ +struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, u_int16_t arfcn) +{ + struct gsm_bts *neigh; + /* FIXME: use some better heuristics here to determine which cell + * using this ARFCN really is closest to the target cell. For + * now we simply assume that each ARFCN will only be used by one + * cell */ + + llist_for_each_entry(neigh, &bts->network->bts_list, list) { + if (neigh->c0->arfcn == arfcn) + return neigh; + } + + return NULL; +} + struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num) { struct gsm_bts_trx *trx; -- cgit v1.2.3 From 0b12103965c824b0dae1ae10df00d87d4ef1ec7b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 15 Dec 2009 00:21:31 +0100 Subject: add BSIC parameter to gsm_bts_neighbor() When looking for the gsm_bts of a neighbor cell, use BSIC and ARFCN tuple rather than just ARFCN for better identification purpose. --- openbsc/src/gsm_data.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 9fb4526f0..91a854f46 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -235,7 +235,8 @@ struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num) } /* Get reference to a neighbor cell on a given BCCH ARFCN */ -struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, u_int16_t arfcn) +struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, + u_int16_t arfcn, u_int8_t bsic) { struct gsm_bts *neigh; /* FIXME: use some better heuristics here to determine which cell @@ -244,7 +245,8 @@ struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, u_int16_t arfcn) * cell */ llist_for_each_entry(neigh, &bts->network->bts_list, list) { - if (neigh->c0->arfcn == arfcn) + if (neigh->c0->arfcn == arfcn && + neigh->bsic == bsic) return neigh; } -- cgit v1.2.3 From d12b0fdf51b76f906d5ee5f5b7f266fe791eb800 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 15 Dec 2009 21:36:05 +0100 Subject: introduce cache of 6 last recently received measurement reports for each lchan --- openbsc/src/abis_rsl.c | 36 +++++++++++++++++------------------- openbsc/src/chan_alloc.c | 9 +++++++++ openbsc/src/gsm_04_08.c | 4 ++-- openbsc/src/gsm_data.c | 13 +++++++++++++ 4 files changed, 41 insertions(+), 21 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index c6675c840..51d524459 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -998,14 +998,12 @@ static int rsl_rx_meas_res(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; - struct gsm_meas_rep mr; + struct gsm_meas_rep *mr = lchan_next_meas_rep(msg->lchan); u_int8_t len; const u_int8_t *val; int rc; - memset(&mr, 0, sizeof(mr)); - - mr.lchan = msg->lchan; + memset(mr, 0, sizeof(*mr)); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1015,44 +1013,44 @@ static int rsl_rx_meas_res(struct msgb *msg) return -EIO; /* Mandatory Parts */ - mr.nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR); + mr->nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR); len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS); val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS); if (len >= 3) { if (val[0] & 0x40) - mr.flags |= MEAS_REP_F_DL_DTX; - mr.ul.full.rx_lev = val[0] & 0x3f; - mr.ul.sub.rx_lev = val[1] & 0x3f; - mr.ul.full.rx_qual = val[2]>>3 & 0x7; - mr.ul.sub.rx_qual = val[2] & 0x7; + mr->flags |= MEAS_REP_F_DL_DTX; + mr->ul.full.rx_lev = val[0] & 0x3f; + mr->ul.sub.rx_lev = val[1] & 0x3f; + mr->ul.full.rx_qual = val[2]>>3 & 0x7; + mr->ul.sub.rx_qual = val[2] & 0x7; } - mr.bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER); + mr->bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER); /* Optional Parts */ if (TLVP_PRESENT(&tp, RSL_IE_MS_TIMING_OFFSET)) - mr.ms_timing_offset = + mr->ms_timing_offset = *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET); if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) { val = TLVP_VAL(&tp, RSL_IE_L1_INFO); - mr.flags |= MEAS_REP_F_MS_L1; - mr.ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3); + mr->flags |= MEAS_REP_F_MS_L1; + mr->ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3); if (val[0] & 0x04) - mr.flags |= MEAS_REP_F_FPC; - mr.ms_l1.ta = val[1]; + mr->flags |= MEAS_REP_F_FPC; + mr->ms_l1.ta = val[1]; } if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) { msg->l3h = (u_int8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO); - rc = gsm48_parse_meas_rep(&mr, msg); + rc = gsm48_parse_meas_rep(mr, msg); if (rc < 0) return rc; } - print_meas_rep(&mr); + print_meas_rep(mr); - dispatch_signal(SS_LCHAN, S_LCHAN_MEAS_REP, &mr); + dispatch_signal(SS_LCHAN, S_LCHAN_MEAS_REP, mr); return 0; } diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 2f0d7b93f..0a2984773 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -235,6 +235,8 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) /* Free a logical channel */ void lchan_free(struct gsm_lchan *lchan) { + int i; + lchan->type = GSM_LCHAN_NONE; if (lchan->subscr) { subscr_put(lchan->subscr); @@ -250,6 +252,13 @@ void lchan_free(struct gsm_lchan *lchan) /* stop the timer */ bsc_del_timer(&lchan->release_timer); + /* clear cached measuement reports */ + lchan->meas_rep_idx = 0; + for (i = 0; i < ARRAY_SIZE(lchan->meas_rep); i++) { + lchan->meas_rep[i].flags = 0; + lchan->meas_rep[i].nr = 0; + } + /* FIXME: ts_free() the timeslot, if we're the last logical * channel using it */ } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 6d05a20ad..ef29b29cc 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1558,13 +1558,13 @@ static int gsm48_rx_rr_status(struct msgb *msg) static int gsm48_rx_rr_meas_rep(struct msgb *msg) { - static struct gsm_meas_rep meas_rep; + struct gsm_meas_rep *meas_rep = lchan_next_meas_rep(msg->lchan); /* This shouldn't actually end up here, as RSL treats * L3 Info of 08.58 MEASUREMENT REPORT different by calling * directly into gsm48_parse_meas_rep */ DEBUGP(DMEAS, "DIRECT GSM48 MEASUREMENT REPORT ?!? "); - gsm48_parse_meas_rep(&meas_rep, msg); + gsm48_parse_meas_rep(meas_rep, msg); return 0; } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 91a854f46..94ed91ba5 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -415,3 +415,16 @@ const char *rrlp_mode_name(enum rrlp_mode mode) return "none"; return rrlp_mode_names[mode]; } + +struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) +{ + struct gsm_meas_rep *meas_rep; + + meas_rep = &lchan->meas_rep[lchan->meas_rep_idx]; + memset(meas_rep, 0, sizeof(*meas_rep)); + meas_rep->lchan = lchan; + lchan->meas_rep_idx = (lchan->meas_rep_idx + 1) + % ARRAY_SIZE(lchan->meas_rep); + + return meas_rep; +} -- cgit v1.2.3 From 152b6261f88ac085cd96b63374ad5847ac7b3ce2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 11:57:48 +0100 Subject: [system_information] Print more debugging about what's going on --- openbsc/src/bsc_init.c | 16 +++++++++++----- openbsc/src/system_information.c | 21 +++++++++++++++------ 2 files changed, 26 insertions(+), 11 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index ef68ef936..aed0dad42 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -684,25 +684,31 @@ static int set_system_infos(struct gsm_bts_trx *trx) } #ifdef GPRS rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); - if (rc < 0) + if (rc < 0) { + i = 13; goto err_out; + } rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); #endif rc = gsm_generate_si(si_tmp, trx->bts, 5); - if (rc < 0) + if (rc < 0) { + i = 5; goto err_out; + } rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si_tmp, rc); rc = gsm_generate_si(si_tmp, trx->bts, 6); - if (rc < 0) + if (rc < 0) { + i = 6; goto err_out; + } rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si_tmp, rc); return 0; err_out: - fprintf(stderr, "Cannot generate SI for BTS %u, most likely " + fprintf(stderr, "Cannot generate SI %u for BTS %u, most likely " "a problem with neighbor cell list generation\n", - trx->bts->nr); + i, trx->bts->nr); return rc; } diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 2d4ba20a4..644abb432 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -32,6 +32,7 @@ #include #include #include +#include #define GSM48_CELL_CHAN_DESC_SIZE 16 #define GSM_MACBLOCK_LEN 23 @@ -73,10 +74,14 @@ static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) if (arfcn == min_arfcn) return 0; - if (arfcn < min_arfcn) + if (arfcn < min_arfcn) { + DEBUGP(DRR, "arfcn(%u) < min(%u)\n", arfcn, min_arfcn); return -EINVAL; - if (arfcn > min_arfcn + 111) + } + if (arfcn > min_arfcn + 111) { + DEBUGP(DRR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn); return -EINVAL; + } bitno = (arfcn - min_arfcn); byte = bitno / 8; @@ -121,17 +126,21 @@ static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv, } } - if ((max - min) > 111) + if ((max - min) > 111) { + DEBUGP(DRR, "min_arfcn=%u, max_arfcn=%u, distance > 111\n", min, max); return -EINVAL; + } chan_list[0] |= (min >> 9) & 1; chan_list[1] = (min >> 1); chan_list[2] = (min & 1) << 7; for (i = 0; i < bv->data_len*8; i++) { - rc = freq_list_bmrel_set_arfcn(chan_list, i); - if (rc < 0) - return rc; + if (bitvec_get_bit_pos(bv, i)) { + rc = freq_list_bmrel_set_arfcn(chan_list, i); + if (rc < 0) + return rc; + } } return 0; -- cgit v1.2.3 From 680e2eccef2bffb462e5854db87139126fb1920d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 15:59:24 +0100 Subject: fix bug in bitvec resulting in all bits being set to 0xff --- openbsc/src/bitvec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bitvec.c b/openbsc/src/bitvec.c index ad03958f3..d6f5679cf 100644 --- a/openbsc/src/bitvec.c +++ b/openbsc/src/bitvec.c @@ -104,12 +104,12 @@ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, if (bytenum >= bv->data_len) return -EINVAL; - bitval = bitval2mask(ONE, bitnum); - /* first clear the bit */ - bv->data[bytenum] &= ~(1 << bitnum); + bitval = bitval2mask(ONE, bitnum); + bv->data[bytenum] &= ~bitval; /* then set it to desired value */ + bitval = bitval2mask(bit, bitnum); bv->data[bytenum] |= bitval; return 0; -- cgit v1.2.3 From a2f74b847782a2578fe5b0a79f5479379493d4ba Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 16:49:21 +0100 Subject: 04.08: fix off-by-one error while parsing measurement results --- openbsc/src/gsm_04_08.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index ef29b29cc..0815d6dde 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -190,47 +190,47 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) rep->dl.full.rx_qual = (data[3] >> 4) & 0x7; rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; - rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2); + rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2); if (rep->num_cell < 1) return 0; /* an encoding nightmare in perfection */ - rep->cell[0].rxlev = data[4] & 0x3f; - rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[5] >> 2); - rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5); + rep->cell[0].rxlev = data[3] & 0x3f; + rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2); + rep->cell[0].bsic = ((data[4] & 0x03) << 3) | (data[5] >> 5); if (rep->num_cell < 2) return 0; - rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7); - rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[7] >> 2) & 0x1f); - rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4); + rep->cell[1].rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); + rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f); + rep->cell[1].bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); if (rep->num_cell < 3) return 0; - rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6); - rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[9] >> 1) & 0x1f); - rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3); + rep->cell[2].rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); + rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f); + rep->cell[2].bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); if (rep->num_cell < 4) return 0; - rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5); - rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[11] & 0x1f); - rep->cell[3].bsic = data[12] >> 2; + rep->cell[3].rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); + rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f); + rep->cell[3].bsic = data[11] >> 2; if (rep->num_cell < 5) return 0; - rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4); + rep->cell[4].rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv, - ((data[13] & 0xf) << 1) | (data[14] >> 7)); - rep->cell[4].bsic = (data[14] >> 1) & 0x3f; + ((data[12] & 0xf) << 1) | (data[13] >> 7)); + rep->cell[4].bsic = (data[13] >> 1) & 0x3f; if (rep->num_cell < 6) return 0; - rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3); + rep->cell[5].rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv, - ((data[15] & 0x07) << 2) | (data[16] >> 6)); - rep->cell[5].bsic = data[16] & 0x3f; + ((data[14] & 0x07) << 2) | (data[15] >> 6)); + rep->cell[5].bsic = data[15] & 0x3f; return 0; } -- cgit v1.2.3 From 6739dfb7053a4a8d788f15c018ccca39b119f831 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 16:52:07 +0100 Subject: print measurement reports more verbosely --- openbsc/src/abis_rsl.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 51d524459..37b9a47dc 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -957,14 +957,17 @@ static int rsl_rx_conn_fail(struct msgb *msg) static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru, const char *prefix) { - DEBUGPC(DMEAS, "RXL-FULL-%s=%d RXL-SUB-%s=%d ", - prefix, mru->full.rx_lev, prefix, mru->sub.rx_lev); + DEBUGPC(DMEAS, "RXL-FULL-%s=%3ddBm RXL-SUB-%s=%3ddBm ", + prefix, rxlev2dbm(mru->full.rx_lev), + prefix, rxlev2dbm(mru->sub.rx_lev)); DEBUGPC(DMEAS, "RXQ-FULL-%s=%d RXQ-SUB-%s=%d ", prefix, mru->full.rx_qual, prefix, mru->sub.rx_qual); } static void print_meas_rep(struct gsm_meas_rep *mr) { + int i; + DEBUGP(DMEAS, "MEASUREMENT RESULT NR=%d ", mr->nr); if (mr->flags & MEAS_REP_F_DL_DTX) @@ -976,7 +979,7 @@ static void print_meas_rep(struct gsm_meas_rep *mr) DEBUGPC(DMEAS, "MS_TO=%d ", mr->ms_timing_offset); if (mr->flags & MEAS_REP_F_MS_L1) { - DEBUGPC(DMEAS, "L1_MS_PWR=%ddBm ", mr->ms_l1.pwr); + DEBUGPC(DMEAS, "L1_MS_PWR=%3ddBm ", mr->ms_l1.pwr); DEBUGPC(DMEAS, "L1_FPC=%u ", mr->flags & MEAS_REP_F_FPC ? 1 : 0); DEBUGPC(DMEAS, "L1_TA=%u ", mr->ms_l1.ta); @@ -992,6 +995,11 @@ static void print_meas_rep(struct gsm_meas_rep *mr) print_meas_rep_uni(&mr->dl, "dl"); DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", mr->num_cell); + for (i = 0; i < mr->num_cell; i++) { + struct gsm_meas_rep_cell *mrc = &mr->cell[i]; + DEBUGP(DMEAS, "ARFCN=%u BSIC=%u => %d dBm\n", mrc->arfcn, mrc->bsic, + rxlev2dbm(mrc->rxlev)); + } } static int rsl_rx_meas_res(struct msgb *msg) -- cgit v1.2.3 From 88a412ac80e182fc8a1fa470f846783d79ab7d52 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 17:32:37 +0100 Subject: ip.access: Keep OML/RSL up/down state per-bts for multi-BTS setups --- openbsc/src/input/ipaccess.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 2d9f51ef9..143712e1c 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -247,9 +247,8 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, return 0; } -/* FIXME: this is per BTS */ -static int oml_up = 0; -static int rsl_up = 0; +#define OML_UP 0x0001 +#define RSL_UP 0x0002 /* * read one ipa message from the socket @@ -348,16 +347,16 @@ static int handle_ts1_read(struct bsc_fd *bfd) switch (link->type) { case E1INP_SIGN_RSL: - if (!rsl_up) { + if (!(msg->trx->bts->ip_access.flags & RSL_UP)) { e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); - rsl_up = 1; + msg->trx->bts->ip_access.flags |= RSL_UP; } ret = abis_rsl_rcvmsg(msg); break; case E1INP_SIGN_OML: - if (!oml_up) { + if (!(msg->trx->bts->ip_access.flags & OML_UP)) { e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); - oml_up = 1; + msg->trx->bts->ip_access.flags |= OML_UP; } ret = abis_nm_rcvmsg(msg); break; -- cgit v1.2.3 From 73ddaeddd2b4666abe90843e5ff89f00d6b1c934 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 23:29:12 +0100 Subject: measurement report: correctly parse BSIC of first neighbor cell --- openbsc/src/gsm_04_08.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 0815d6dde..5fea6bfbf 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -198,7 +198,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) rep->cell[0].rxlev = data[3] & 0x3f; rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2); - rep->cell[0].bsic = ((data[4] & 0x03) << 3) | (data[5] >> 5); + rep->cell[0].bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); if (rep->num_cell < 2) return 0; -- cgit v1.2.3 From 33e65977204c4d35deb7c48069bf504353618da5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 16 Dec 2009 23:29:34 +0100 Subject: assign measurement report lchan member after memset'ing it --- openbsc/src/abis_rsl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 37b9a47dc..1fbea837d 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1012,6 +1012,7 @@ static int rsl_rx_meas_res(struct msgb *msg) int rc; memset(mr, 0, sizeof(*mr)); + mr->lchan = msg->lchan; rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); -- cgit v1.2.3 From 7a7a0d54289114e6a49087a555b7a4f1e6cb3016 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 00:25:18 +0100 Subject: make handover reference a function call argument --- openbsc/src/gsm_04_08_utils.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 8497fa842..e96a1ca09 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -541,21 +541,22 @@ static void gsm48_chan_desc(struct gsm48_chan_desc *cd, } /* Chapter 9.1.15: Handover Command */ -int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, - struct gsm_lchan *new_lchan, u_int8_t power_command) +int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, + u_int8_t power_command, u_int8_t ho_ref) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *) msgb_put(msg, sizeof(*ho)); - static u_int8_t ho_ref; msg->lchan = old_lchan; + gh->proto_discr = GSM48_PDISC_RR; + gh->msg_type = GSM48_MT_RR_HANDO_CMD; /* mandatory bits */ gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts); gsm48_chan_desc(&ho->chan_desc, new_lchan); - ho->ho_ref = ho_ref++; + ho->ho_ref = ho_ref; ho->power_command = power_command; /* FIXME: optional bits for type of synchronization? */ -- cgit v1.2.3 From 8d77b9540a907fb36afbb324df549c9261e1ca02 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 00:31:10 +0100 Subject: [handover] first functional handover implementation With this commit, we can successfully hand over a channel from one cell to another cell. We implement asynchronous intra-BSC (but inter-BTS) handover. Changes: * introduce new DHO log category * extend rsl_chan_activate_lchan() with argument for HO reference * introduce actual minimal handover decision making in handover_decision.c * various fixes to bsc_handover_start() in handover_logic.c --- openbsc/src/Makefile.am | 3 +- openbsc/src/abis_rsl.c | 15 ++++-- openbsc/src/bsc_hack.c | 1 + openbsc/src/bsc_init.c | 1 + openbsc/src/debug.c | 3 +- openbsc/src/handover_decision.c | 111 ++++++++++++++++++++++++++++++++++++++++ openbsc/src/handover_logic.c | 27 ++++++++-- 7 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 openbsc/src/handover_decision.c (limited to 'openbsc/src') diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index f22582122..5692ac4e4 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -11,7 +11,8 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ - talloc_ctx.c system_information.c bitvec.c rest_octets.c + talloc_ctx.c system_information.c bitvec.c rest_octets.c \ + handover_decision.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 1fbea837d..d42daf5f2 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -576,7 +576,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr, #endif int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, - u_int8_t ta) + u_int8_t ta, u_int8_t ho_ref) { struct abis_rsl_dchan_hdr *dh; struct msgb *msg; @@ -603,9 +603,9 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, dh->chan_nr = chan_nr; msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type); - /* For compatibility with Phase 1 */ msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm), (u_int8_t *) &cm); + /* For compatibility with Phase 1 */ msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4, (u_int8_t *) &ci); @@ -616,6 +616,15 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info); } + switch (act_type) { + case RSL_ACT_INTER_ASYNC: + case RSL_ACT_INTER_SYNC: + msgb_tv_put(msg, RSL_IE_HANDO_REF, ho_ref); + break; + default: + break; + } + msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power); msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power); msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta); @@ -1258,7 +1267,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) lchan->bs_power = 0; /* 0dB reduction, output power = Pn */ lchan->rsl_cmode = RSL_CMOD_SPD_SIGN; lchan->tch_mode = GSM48_CMODE_SIGN; - rsl_chan_activate_lchan(lchan, 0x00, rqd_ta); + rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, 0); /* create IMMEDIATE ASSIGN 04.08 messge */ memset(&ia, 0, sizeof(ia)); diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 1dd5e1020..b0f8d6c3f 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -162,6 +162,7 @@ int main(int argc, char **argv) talloc_ctx_init(); on_dso_load_token(); on_dso_load_rrlp(); + on_dso_load_ho_dec(); /* parse options */ handle_options(argc, argv); diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index aed0dad42..ce3d0b4f8 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -679,6 +679,7 @@ static int set_system_infos(struct gsm_bts_trx *trx) rc = gsm_generate_si(si_tmp, trx->bts, i); if (rc < 0) goto err_out; + DEBUGP(DRR, "SI%u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } } diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 5dc2e0ff7..9c6cb4963 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -28,7 +28,7 @@ #include -unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB|DMEAS); +unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB); struct debug_info { const char *name; @@ -60,6 +60,7 @@ static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DSCCP, "DSCCP", "", "") DEBUG_CATEGORY(DMSC, "DMSC", "", "") DEBUG_CATEGORY(DMGCP, "DMGCP", "", "") + DEBUG_CATEGORY(DHO, "DHO", "", "") }; static int use_color = 1; diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c new file mode 100644 index 000000000..06eb86507 --- /dev/null +++ b/openbsc/src/handover_decision.c @@ -0,0 +1,111 @@ +/* Handover Decision making for Inter-BTS (Intra-BSC) Handover. This + * only implements the handover algorithm/decision, but not execution + * of it */ + +/* (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 General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, + u_int16_t arfcn, u_int8_t bsic) +{ + struct gsm_bts *new_bts; + + /* resolve the gsm_bts structure for the best neighbor */ + new_bts = gsm_bts_neighbor(lchan->ts->trx->bts, arfcn, bsic); + if (!new_bts) { + DEBUGP(DHO, "unable to determine neighbor BTS for ARFCN %u BSIC %u ?!?\n", arfcn, bsic); + return -EINVAL; + } + + /* and actually try to handover to that cell */ + return bsc_handover_start(lchan, new_bts); +} + +#define RXLEV_HYST 3 + +/* process an already parsed measurement report */ +static int process_meas_rep(struct gsm_meas_rep *mr) +{ + struct gsm_meas_rep_cell *mr_cell = NULL; + unsigned int best_better_db; + int i; + + DEBUGP(DHO, "process meas res: "); + + /* FIXME: implement actual averaging over multiple measurement + * reports */ + + /* find the best cell in this report that is at least RXLEV_HYST + * better than the current serving cell */ + for (i = 0; i < mr->num_cell; i++) { + unsigned int better; + if (mr->cell[i].rxlev < mr->dl.full.rx_lev + RXLEV_HYST) + continue; + + better = mr->cell[i].rxlev - mr->dl.full.rx_lev; + if (better > best_better_db) { + mr_cell = &mr->cell[i]; + best_better_db = better; + } + } + + if (mr_cell) { + DEBUGPC(DHO, "Cell on ARFCN %u is better, starting handover\n", mr_cell->arfcn); + return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, + mr_cell->bsic); + } + + DEBUGPC(DHO, "No better cell\n"); + return 0; +} + +static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct gsm_meas_rep *mr; + + if (subsys != SS_LCHAN) + return 0; + + switch (signal) { + case S_LCHAN_MEAS_REP: + mr = signal_data; + process_meas_rep(mr); + break; + } + + return 0; +} + +void on_dso_load_ho_dec(void) +{ + register_signal_handler(SS_LCHAN, ho_dec_sig_cb, NULL); +} diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index d4a888487..99b3c0139 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -85,23 +85,40 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) { struct gsm_lchan *new_lchan; struct bsc_handover *ho; + static u_int8_t ho_ref; int rc; + DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u): ", + old_lchan->ts->trx->bts->nr, bts->nr); + new_lchan = lchan_alloc(bts, old_lchan->type); - if (!new_lchan) + if (!new_lchan) { + DEBUGPC(DHO, "No free channel\n"); return -ENOSPC; + } ho = talloc_zero(NULL, struct bsc_handover); if (!ho) { + DEBUGPC(DHO, "Out of Memory\n"); lchan_free(new_lchan); return -ENOMEM; } ho->old_lchan = old_lchan; ho->new_lchan = new_lchan; + ho->ho_ref = ho_ref++; + + /* copy some parameters from old lchan */ + memcpy(&new_lchan->encr, &old_lchan->encr, sizeof(new_lchan->encr)); + new_lchan->ms_power = old_lchan->ms_power; + new_lchan->bs_power = old_lchan->bs_power; + new_lchan->rsl_cmode = old_lchan->rsl_cmode; + new_lchan->tch_mode = old_lchan->tch_mode; /* FIXME: do we have a better idea of the timing advance? */ - rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0); + rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0, + ho->ho_ref); if (rc < 0) { + DEBUGPC(DHO, "could not activate channel\n"); talloc_free(ho); lchan_free(new_lchan); return rc; @@ -118,6 +135,8 @@ static void ho_T3103_cb(void *_ho) { struct bsc_handover *ho = _ho; + DEBUGP(DHO, "HO T3103 expired\n"); + lchan_free(ho->new_lchan); llist_del(&ho->list); talloc_free(ho); @@ -129,6 +148,8 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) struct bsc_handover *ho; int rc; + DEBUGP(DHO, "handover activate ack, send HO Command\n"); + ho = bsc_ho_by_new_lchan(new_lchan); if (!ho) return -ENODEV; @@ -136,7 +157,7 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) /* we can now send the 04.08 HANDOVER COMMAND to the MS * using the old lchan */ - rc = gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0); + rc = gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0, ho->ho_ref); /* start T3103. We can continue either with T3103 expiration, * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */ -- cgit v1.2.3 From cc9beb53663c9660c7e7a225256a9e71d3c9165e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 17:13:28 +0100 Subject: introduce trans_lchan_change() to update transaction about lchan change --- openbsc/src/transaction.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index 04eaa3c99..9f1bbf36d 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -140,3 +140,22 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr, return -1; } + +/* update all transactions to use a different LCHAN, e.g. + * after handover has succeeded */ +int trans_lchan_change(struct gsm_lchan *lchan_old, + struct gsm_lchan *lchan_new) +{ + struct gsm_network *net = lchan_old->ts->trx->bts->network; + struct gsm_trans *trans; + int num = 0; + + llist_for_each_entry(trans, &net->trans_list, entry) { + if (trans->lchan == lchan_old) { + trans->lchan = lchan_new; + num++; + } + } + + return num; +} -- cgit v1.2.3 From fe18d5cba426cd537140a09cb0c74e5d3be0a0ec Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 17:14:43 +0100 Subject: call trans_lchan_change() from ho_gsm48_ho_compl() --- openbsc/src/handover_logic.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 99b3c0139..68cdcba07 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -196,6 +196,9 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) bsc_del_timer(&ho->T3103); llist_del(&ho->list); + /* update lchan pointer of transaction */ + trans_lchan_change(ho->old_lchan, new_lchan); + /* do something to re-route the actual speech frames ! */ //tch_remap(ho->old_lchan, ho->new_lchan); -- cgit v1.2.3 From 7cb7a73b4fe7152dc89f4450c43d5f10daf9900a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 21:32:19 +0100 Subject: [vty] ensure we mark fd in writefd once we vty_out() something --- openbsc/src/vty/vty.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c index affe28d8d..788c7fd6f 100644 --- a/openbsc/src/vty/vty.c +++ b/openbsc/src/vty/vty.c @@ -236,6 +236,8 @@ int vty_out(struct vty *vty, const char *format, ...) talloc_free(p); } + vty_event(VTY_WRITE, vty->fd, vty); + return len; } -- cgit v1.2.3 From 66706812514c4baca743ad3a07e4556d48b6cded Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 22:23:21 +0100 Subject: don't try multiple concurrent handovers for 1 channel --- openbsc/src/handover_logic.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 68cdcba07..9da8baf91 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -88,6 +88,11 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) static u_int8_t ho_ref; int rc; + /* don't attempt multiple handovers for the same lchan at + * the same time */ + if (bsc_ho_by_old_lchan(old_lchan)) + return -EBUSY; + DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u): ", old_lchan->ts->trx->bts->nr, bts->nr); -- cgit v1.2.3 From b1d4c8ed9d2b4ecb76355d71a152c22934c48504 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 17 Dec 2009 23:10:46 +0100 Subject: logging: introduce log levels at caller site This introduces a new LOGP() macro together with LOGL_* definition to support multiple log levels (severities) throughout the codebase. Please note that the actual logging system does not use them yet, in this patch we simply introduce the new macros at the caller site. --- openbsc/src/abis_nm.c | 16 +++++------ openbsc/src/abis_rsl.c | 58 ++++++++++++++++++++-------------------- openbsc/src/bsc_init.c | 28 +++++++++---------- openbsc/src/chan_alloc.c | 8 +++--- openbsc/src/e1_config.c | 5 ++-- openbsc/src/e1_input.c | 14 +++++----- openbsc/src/handover_decision.c | 8 +++--- openbsc/src/handover_logic.c | 28 ++++++++++++------- openbsc/src/mncc.c | 13 +++++---- openbsc/src/msgb.c | 5 +++- openbsc/src/rtp_proxy.c | 2 +- openbsc/src/system_information.c | 11 +++++--- openbsc/src/telnet_interface.c | 13 +++++---- openbsc/src/trau_frame.c | 18 ++++++++----- openbsc/src/trau_mux.c | 4 ++- 15 files changed, 129 insertions(+), 102 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 30b3ec632..e7e3bf004 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1088,8 +1088,8 @@ static int abis_nm_rcvmsg_manuf(struct msgb *mb) rc = abis_nm_rx_ipacc(mb); break; default: - fprintf(stderr, "don't know how to parse OML for this " - "BTS type (%u)\n", bts_type); + LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this " + "BTS type (%u)\n", bts_type); rc = 0; break; } @@ -1106,12 +1106,12 @@ int abis_nm_rcvmsg(struct msgb *msg) /* Various consistency checks */ if (oh->placement != ABIS_OM_PLACEMENT_ONLY) { - fprintf(stderr, "ABIS OML placement 0x%x not supported\n", + LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n", oh->placement); return -EINVAL; } if (oh->sequence != 0) { - fprintf(stderr, "ABIS OML sequence 0x%x != 0x00\n", + LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n", oh->sequence); return -EINVAL; } @@ -1119,12 +1119,12 @@ int abis_nm_rcvmsg(struct msgb *msg) unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg); unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr); if (oh->length + hlen > l2_len) { - fprintf(stderr, "ABIS OML truncated message (%u > %u)\n", + LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n", oh->length + sizeof(*oh), l2_len); return -EINVAL; } if (oh->length + hlen < l2_len) - fprintf(stderr, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len); + 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); #endif msg->l3h = (unsigned char *)oh + sizeof(*oh); @@ -1137,11 +1137,11 @@ int abis_nm_rcvmsg(struct msgb *msg) break; case ABIS_OM_MDISC_MMI: case ABIS_OM_MDISC_TRAU: - fprintf(stderr, "unimplemented ABIS OML message discriminator 0x%x\n", + LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n", oh->mdisc); break; default: - fprintf(stderr, "unknown ABIS OML message discriminator 0x%x\n", + LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n", oh->mdisc); return -EINVAL; } diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index d42daf5f2..c4bb4bd11 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -206,32 +206,32 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) if (ts->pchan != GSM_PCHAN_TCH_F && ts->pchan != GSM_PCHAN_PDCH && ts->pchan != GSM_PCHAN_TCH_F_PDCH) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); } else if ((cbits & 0x1e) == 0x02) { lch_idx = cbits & 0x1; /* TCH/H */ if (ts->pchan != GSM_PCHAN_TCH_H) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); } else if ((cbits & 0x1c) == 0x04) { lch_idx = cbits & 0x3; /* SDCCH/4 */ if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); } else if ((cbits & 0x18) == 0x08) { lch_idx = cbits & 0x7; /* SDCCH/8 */ if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); } else if (cbits == 0x10 || cbits == 0x11 || cbits == 0x12) { lch_idx = 0; if (ts->pchan != GSM_PCHAN_CCCH && ts->pchan != GSM_PCHAN_CCCH_SDCCH4) - fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); /* FIXME: we should not return first sdcch4 !!! */ } else { - fprintf(stderr, "unknown chan_nr=0x%02x\n", chan_nr); + LOGP(DRSL, LOGL_ERROR, "unknown chan_nr=0x%02x\n", chan_nr); return NULL; } @@ -491,7 +491,7 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, if (lchan->rsl_cmode == RSL_CMOD_SPD_SIGN && lchan->tch_mode != GSM48_CMODE_SIGN) - DEBUGP(DRSL, "unsupported: rsl_mode == signalling, " + LOGP(DRSL, LOGL_ERROR, "unsupported: rsl_mode == signalling, " "but tch_mode != signalling\n"); switch (lchan->type) { @@ -848,7 +848,7 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id) struct abis_rsl_rll_hdr *rh; if (msg->lchan == NULL) { - fprintf(stderr, "cannot send DATA REQUEST to unknown lchan\n"); + LOGP(DRSL, LOGL_ERROR, "cannot send DATA REQUEST to unknown lchan\n"); return -EINVAL; } @@ -949,7 +949,8 @@ static int rsl_rx_conn_fail(struct msgb *msg) struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; - DEBUGPC(DRSL, "CONNECTION FAIL: "); + /* FIXME: print which channel */ + LOGP(DRSL, LOGL_NOTICE, "CONNECTION FAIL: RELEASING\n"); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -957,8 +958,6 @@ static int rsl_rx_conn_fail(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); - DEBUGPC(DRSL, "RELEASING.\n"); - /* FIXME: only free it after channel release ACK */ return rsl_rf_chan_release(msg->lchan); } @@ -1171,7 +1170,7 @@ static int rsl_rx_error_rep(struct msgb *msg) struct abis_rsl_common_hdr *rslh = msgb_l2(msg); struct tlv_parsed tp; - DEBUGP(DRSL, "ERROR REPORT "); + LOGP(DRSL, LOGL_ERROR, "ERROR REPORT "); rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh)); @@ -1179,7 +1178,7 @@ static int rsl_rx_error_rep(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); - DEBUGPC(DRSL, "\n"); + LOGPC(DRSL, LOGL_ERROR, "\n"); return 0; } @@ -1199,7 +1198,7 @@ static int abis_rsl_rx_trx(struct msgb *msg) break; case RSL_MT_OVERLOAD: /* indicate CCCH / ACCH / processor overload */ - DEBUGP(DRSL, "TRX: CCCH/ACCH/CPU Overload\n"); + LOGP(DRSL, LOGL_ERROR, "TRX: CCCH/ACCH/CPU Overload\n"); break; default: DEBUGP(DRSL, "Unknown Abis RSL TRX message type 0x%02x\n", @@ -1350,12 +1349,12 @@ static int abis_rsl_rx_cchan(struct msgb *msg) /* CCCH overloaded, IMM_ASSIGN was dropped */ case RSL_MT_CBCH_LOAD_IND: /* current load on the CBCH */ - fprintf(stderr, "Unimplemented Abis RSL TRX message type " - "0x%02x\n", rslh->c.msg_type); + LOGP(DRSL, LOGL_NOTICE, "Unimplemented Abis RSL TRX message " + "type 0x%02x\n", rslh->c.msg_type); break; default: - fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n", - rslh->c.msg_type); + LOGP(DRSL, LOGL_NOTICE, "Unknown Abis RSL TRX message type " + "0x%02x\n", rslh->c.msg_type); return -EINVAL; } @@ -1367,7 +1366,7 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); u_int8_t *rlm_cause = rllh->data; - DEBUGPC(DRLL, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]); + LOGP(DRLL, LOGL_ERROR, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]); rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); @@ -1448,12 +1447,12 @@ static int abis_rsl_rx_rll(struct msgb *msg) rc = rsl_rx_rll_err_ind(msg); break; case RSL_MT_UNIT_DATA_IND: - DEBUGPC(DRLL, "unimplemented Abis RLL message type 0x%02x\n", - rllh->c.msg_type); + LOGP(DRLL, LOGL_NOTICE, "unimplemented Abis RLL message " + "type 0x%02x\n", rllh->c.msg_type); break; default: - DEBUGPC(DRLL, "unknown Abis RLL message type 0x%02x\n", - rllh->c.msg_type); + LOGP(DRLL, LOGL_NOTICE, "unknown Abis RLL message " + "type 0x%02x\n", rllh->c.msg_type); } return rc; } @@ -1490,7 +1489,7 @@ static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan) default: break; } - DEBUGPC(DRSL, "Cannot determine ip.access speech mode for " + LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access speech mode for " "tch_mode == 0x%02x\n", lchan->tch_mode); return 0; } @@ -1604,7 +1603,7 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) if (!TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_PORT) || !TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_IP) || !TLVP_PRESENT(&tv, RSL_IE_IPAC_CONN_ID)) { - DEBUGPC(DRSL, "mandatory IE missing"); + LOGP(DRSL, LOGL_NOTICE, "mandatory IE missing"); return -EINVAL; } ip.s_addr = *((u_int32_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_IP)); @@ -1680,7 +1679,8 @@ static int abis_rsl_rx_ipacc(struct msgb *msg) rc = abis_rsl_rx_ipacc_dlcx_ind(msg); break; default: - DEBUGPC(DRSL, "Unknown ip.access msg_type 0x%02x", rllh->c.msg_type); + LOGP(DRSL, LOGL_NOTICE, "Unknown ip.access msg_type 0x%02x", + rllh->c.msg_type); break; } DEBUGPC(DRSL, "\n"); @@ -1709,15 +1709,15 @@ int abis_rsl_rcvmsg(struct msgb *msg) rc = abis_rsl_rx_trx(msg); break; case ABIS_RSL_MDISC_LOC: - fprintf(stderr, "unimplemented RSL msg disc 0x%02x\n", + LOGP(DRSL, LOGL_NOTICE, "unimplemented RSL msg disc 0x%02x\n", rslh->msg_discr); break; case ABIS_RSL_MDISC_IPACCESS: rc = abis_rsl_rx_ipacc(msg); break; default: - fprintf(stderr, "unknown RSL message discriminator 0x%02x\n", - rslh->msg_discr); + LOGP(DRSL, LOGL_NOTICE, "unknown RSL message discriminator " + "0x%02x\n", rslh->msg_discr); return -EINVAL; } msgb_free(msg); diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index ce3d0b4f8..744eacb24 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -453,7 +453,7 @@ static int sw_activ_rep(struct msgb *mb) static int oml_msg_nack(u_int8_t mt) { if (mt == NM_MT_SET_BTS_ATTR_NACK) { - fprintf(stderr, "Failed to set BTS attributes. That is fatal. " + LOGP(DNM, LOGL_FATAL, "Failed to set BTS attributes. That is fatal. " "Was the bts type and frequency properly specified?\n"); exit(-1); } @@ -556,7 +556,7 @@ static void nm_reconfig_trx(struct gsm_bts_trx *trx) trx->nominal_power = 23; break; default: - fprintf(stderr, "Unsupported nanoBTS GSM band %s\n", + LOGP(DNM, LOGL_ERROR, "Unsupported nanoBTS GSM band %s\n", gsm_band_name(trx->bts->band)); break; } @@ -621,7 +621,7 @@ static void bootstrap_om_bs11(struct gsm_bts *bts) static void bootstrap_om(struct gsm_bts *bts) { - fprintf(stdout, "bootstrapping OML for BTS %u\n", bts->nr); + LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr); switch (bts->type) { case GSM_BTS_TYPE_BS11: @@ -631,13 +631,13 @@ static void bootstrap_om(struct gsm_bts *bts) bootstrap_om_nanobts(bts); break; default: - fprintf(stderr, "Unable to bootstrap OML: Unknown BTS type %d\n", bts->type); + LOGP(DNM, LOGL_ERROR, "Unable to bootstrap OML: Unknown BTS type %d\n", bts->type); } } static int shutdown_om(struct gsm_bts *bts) { - fprintf(stdout, "shutting down OML for BTS %u\n", bts->nr); + LOGP(DNM, LOGL_NOTICE, "shutting down OML for BTS %u\n", bts->nr); /* stop sending event reports */ abis_nm_event_reports(bts, 0); @@ -707,7 +707,7 @@ static int set_system_infos(struct gsm_bts_trx *trx) return 0; err_out: - fprintf(stderr, "Cannot generate SI %u for BTS %u, most likely " + LOGP(DRR, LOGL_ERROR, "Cannot generate SI %u for BTS %u, most likely " "a problem with neighbor cell list generation\n", i, trx->bts->nr); return rc; @@ -746,7 +746,7 @@ static void patch_nm_tables(struct gsm_bts *bts) static void bootstrap_rsl(struct gsm_bts_trx *trx) { - fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) " + LOGP(DRSL, LOGL_NOTICE, "bootstrapping RSL for BTS/TRX (%u/%u) " "using MCC=%u MNC=%u BSIC=%u TSC=%u\n", trx->bts->nr, trx->nr, bsc_gsmnet->country_code, bsc_gsmnet->network_code, trx->bts->bsic, trx->bts->tsc); @@ -769,7 +769,7 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) } break; case EVT_E1_TEI_DN: - fprintf(stderr, "Lost some E1 TEI link\n"); + LOGP(DMI, LOGL_NOTICE, "Lost some E1 TEI link\n"); /* FIXME: deal with TEI or L1 link loss */ break; default: @@ -782,30 +782,30 @@ static int bootstrap_bts(struct gsm_bts *bts) switch (bts->band) { case GSM_BAND_1800: if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) { - fprintf(stderr, "GSM1800 channel must be between 512-885.\n"); + LOGP(DNM, LOGL_ERROR, "GSM1800 channel must be between 512-885.\n"); return -EINVAL; } break; case GSM_BAND_1900: if (bts->c0->arfcn < 512 || bts->c0->arfcn > 810) { - fprintf(stderr, "GSM1900 channel must be between 512-810.\n"); + LOGP(DNM, LOGL_ERROR, "GSM1900 channel must be between 512-810.\n"); return -EINVAL; } break; case GSM_BAND_900: if (bts->c0->arfcn < 1 || bts->c0->arfcn > 124) { - fprintf(stderr, "GSM900 channel must be between 1-124.\n"); + LOGP(DNM, LOGL_ERROR, "GSM900 channel must be between 1-124.\n"); return -EINVAL; } break; default: - fprintf(stderr, "Unsupported frequency band.\n"); + LOGP(DNM, LOGL_ERROR, "Unsupported frequency band.\n"); return -EINVAL; } if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL && !bts->cell_barred) - fprintf(stderr, "\nWARNING: You are running an 'accept-all' " + LOGP(DNM, LOG_ERROR, "\nWARNING: You are running an 'accept-all' " "network on a BTS that is not barred. This " "configuration is likely to interfere with production " "GSM networks and should only be used in a RF " @@ -858,7 +858,7 @@ int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, int, void *), telnet_init(bsc_gsmnet, 4242); rc = vty_read_config_file(config_file); if (rc < 0) { - fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n", config_file); return rc; } diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 0a2984773..786e8b11b 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -210,7 +210,7 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) } break; default: - fprintf(stderr, "Unknown gsm_chan_t %u\n", type); + LOGP(DRLL, LOGL_ERROR, "Unknown gsm_chan_t %u\n", type); } if (lchan) { @@ -276,9 +276,9 @@ int lchan_auto_release(struct gsm_lchan *lchan) } /* spoofed? message */ - if (lchan->use_count < 0) { - DEBUGP(DRLL, "Channel count is negative: %d\n", lchan->use_count); - } + if (lchan->use_count < 0) + LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n", + lchan->use_count); DEBUGP(DRLL, "Recycling the channel with: %d (%x)\n", lchan->nr, lchan->nr); rsl_release_request(lchan, 0); diff --git a/openbsc/src/e1_config.c b/openbsc/src/e1_config.c index 62bacf2ca..6a2abd85b 100644 --- a/openbsc/src/e1_config.c +++ b/openbsc/src/e1_config.c @@ -10,6 +10,7 @@ #include #include #include +#include #define SAPI_L2ML 0 #define SAPI_OML 62 @@ -25,7 +26,7 @@ int e1_reconfig_ts(struct gsm_bts_trx_ts *ts) struct e1inp_line *line; struct e1inp_ts *e1_ts; - printf("e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr); + DEBUGP(DMI, "e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr); if (!e1_link->e1_ts) return 0; @@ -87,7 +88,7 @@ int e1_reconfig_bts(struct gsm_bts *bts) struct e1inp_sign_link *oml_link; struct gsm_bts_trx *trx; - printf("e1_reconfig_bts(%u)\n", bts->nr); + DEBUGP(DMI, "e1_reconfig_bts(%u)\n", bts->nr); if (!e1_link->e1_ts) return -EINVAL; diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index 15495fbbb..083d8f8de 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -235,7 +235,7 @@ int abis_rsl_sendmsg(struct msgb *msg) msg->l2h = msg->data; if (!msg->trx || !msg->trx->rsl_link) { - fprintf(stderr, "rsl_sendmsg: msg->trx == NULL\n"); + LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx == NULL\n"); talloc_free(msg); return -EINVAL; } @@ -264,7 +264,7 @@ int _abis_nm_sendmsg(struct msgb *msg) msg->l2h = msg->data; if (!msg->trx || !msg->trx->bts || !msg->trx->bts->oml_link) { - fprintf(stderr, "nm_sendmsg: msg->trx == NULL\n"); + LOGP(DRSL, LOGL_ERROR, "nm_sendmsg: msg->trx == NULL\n"); return -EINVAL; } @@ -306,7 +306,7 @@ int e1inp_ts_config(struct e1inp_ts *ts, struct e1inp_line *line, subch_demux_init(&ts->trau.demux); break; default: - fprintf(stderr, "unsupported E1 timeslot type %u\n", + LOGP(DMI, LOGL_ERROR, "unsupported E1 timeslot type %u\n", ts->type); return -EINVAL; } @@ -431,7 +431,7 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, write_pcap_packet(PCAP_INPUT, sapi, tei, msg); link = e1inp_lookup_sign_link(ts, tei, sapi); if (!link) { - fprintf(stderr, "didn't find signalling link for " + LOGP(DMI, LOGL_ERROR, "didn't find signalling link for " "tei %d, sapi %d\n", tei, sapi); return -EINVAL; } @@ -446,7 +446,7 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, break; default: ret = -EINVAL; - fprintf(stderr, "unknown link type %u\n", link->type); + LOGP(DMI, LOGL_ERROR, "unknown link type %u\n", link->type); break; } break; @@ -455,7 +455,7 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, break; default: ret = -EINVAL; - fprintf(stderr, "unknown TS type %u\n", ts->type); + LOGP(DMI, LOGL_ERROR, "unknown TS type %u\n", ts->type); break; } @@ -492,7 +492,7 @@ struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts, msgb_put(msg, 40); break; default: - fprintf(stderr, "unsupported E1 TS type %u\n", e1i_ts->type); + LOGP(DMI, LOGL_ERROR, "unsupported E1 TS type %u\n", e1i_ts->type); return NULL; } return msg; diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index 06eb86507..a1956868d 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -41,7 +41,8 @@ static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, /* resolve the gsm_bts structure for the best neighbor */ new_bts = gsm_bts_neighbor(lchan->ts->trx->bts, arfcn, bsic); if (!new_bts) { - DEBUGP(DHO, "unable to determine neighbor BTS for ARFCN %u BSIC %u ?!?\n", arfcn, bsic); + LOGP(DHO, LOGL_NOTICE, "unable to determine neighbor BTS " + "for ARFCN %u BSIC %u ?!?\n", arfcn, bsic); return -EINVAL; } @@ -58,8 +59,6 @@ static int process_meas_rep(struct gsm_meas_rep *mr) unsigned int best_better_db; int i; - DEBUGP(DHO, "process meas res: "); - /* FIXME: implement actual averaging over multiple measurement * reports */ @@ -78,7 +77,8 @@ static int process_meas_rep(struct gsm_meas_rep *mr) } if (mr_cell) { - DEBUGPC(DHO, "Cell on ARFCN %u is better, starting handover\n", mr_cell->arfcn); + LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better, starting " + "handover\n", mr_cell->arfcn); return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, mr_cell->bsic); } diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 9da8baf91..66ff77362 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -93,18 +93,18 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) if (bsc_ho_by_old_lchan(old_lchan)) return -EBUSY; - DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u): ", + DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); new_lchan = lchan_alloc(bts, old_lchan->type); if (!new_lchan) { - DEBUGPC(DHO, "No free channel\n"); + LOGP(DHO, LOGL_NOTICE, "No free channel\n"); return -ENOSPC; } ho = talloc_zero(NULL, struct bsc_handover); if (!ho) { - DEBUGPC(DHO, "Out of Memory\n"); + LOGP(DHO, LOGL_FATAL, "Out of Memory\n"); lchan_free(new_lchan); return -ENOMEM; } @@ -123,7 +123,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0, ho->ho_ref); if (rc < 0) { - DEBUGPC(DHO, "could not activate channel\n"); + LOGP(DHO, LOGL_ERROR, "could not activate channel\n"); talloc_free(ho); lchan_free(new_lchan); return rc; @@ -156,8 +156,10 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) DEBUGP(DHO, "handover activate ack, send HO Command\n"); ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } /* we can now send the 04.08 HANDOVER COMMAND to the MS * using the old lchan */ @@ -178,8 +180,10 @@ static int ho_chan_activ_nack(struct gsm_lchan *new_lchan) struct bsc_handover *ho; ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } llist_del(&ho->list); talloc_free(ho); @@ -195,8 +199,10 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) struct bsc_handover *ho; ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } bsc_del_timer(&ho->T3103); llist_del(&ho->list); @@ -221,8 +227,10 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) struct bsc_handover *ho; ho = bsc_ho_by_old_lchan(old_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } bsc_del_timer(&ho->T3103); llist_del(&ho->list); @@ -238,8 +246,10 @@ static int ho_rsl_detect(struct gsm_lchan *new_lchan) struct bsc_handover *ho; ho = bsc_ho_by_old_lchan(new_lchan); - if (!ho) + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; + } /* FIXME: do we actually want to do something here ? */ diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index de1765761..a5efc7312 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -85,8 +85,7 @@ static struct mncc_names { {"GSM_TRAU_FRAME", 0x0300}, - {NULL, 0} -}; + {NULL, 0} }; static LLIST_HEAD(call_list); @@ -146,8 +145,8 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, /* transfer mode 1 would be packet mode, which was never specified */ if (setup->bearer_cap.mode != 0) { - DEBUGP(DMNCC, "(call %x) We don't support packet mode\n", - call->callref); + LOGP(DMNCC, LOGL_NOTICE, "(call %x) We don't support " + "packet mode\n", call->callref); mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); goto out_reject; @@ -155,8 +154,8 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, /* we currently only do speech */ if (setup->bearer_cap.transfer != GSM_MNCC_BCAP_SPEECH) { - DEBUGP(DMNCC, "(call %x) We only support voice calls\n", - call->callref); + LOGP(DMNCC, LOGL_NOTICE, "(call %x) We only support " + "voice calls\n", call->callref); mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_BEARER_CA_UNAVAIL); goto out_reject; @@ -406,7 +405,7 @@ int mncc_recv(struct gsm_network *net, int msg_type, void *arg) rc = mncc_send(net, MNCC_RETRIEVE_REJ, data); break; default: - DEBUGP(DMNCC, "(call %x) Message unhandled\n", callref); + LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref); break; } diff --git a/openbsc/src/msgb.c b/openbsc/src/msgb.c index edeb975a9..48a5a7b03 100644 --- a/openbsc/src/msgb.c +++ b/openbsc/src/msgb.c @@ -26,6 +26,7 @@ #include #include #include +#include static void *tall_msgb_ctx; @@ -35,8 +36,10 @@ struct msgb *msgb_alloc(u_int16_t size, const char *name) msg = _talloc_zero(tall_msgb_ctx, sizeof(*msg) + size, name); - if (!msg) + if (!msg) { + LOGP(DRSL, LOGL_FATAL, "unable to allocate msgb\n"); return NULL; + } msg->data_len = size; msg->len = 0; diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index 59c0735a5..bfd494856 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -211,7 +211,7 @@ static int rtp_socket_write(struct rtp_socket *rs, struct rtp_sub_socket *rss) written = write(rss->bfd.fd, msg->data, msg->len); if (written < msg->len) { - perror("short write"); + LOGP(DMIB, LOGL_ERROR, "short write"); msgb_free(msg); return -EIO; } diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 644abb432..b404e5151 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -45,8 +45,10 @@ static int freq_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) { unsigned int byte, bit; - if (arfcn > 124 || arfcn < 1) + if (arfcn > 124 || arfcn < 1) { + LOGP(DRR, LOGL_ERROR, "Bitmap 0 only supports ARFCN 1...124\n"); return -EINVAL; + } /* the bitmask is from 1..124, not from 0..123 */ arfcn--; @@ -75,11 +77,11 @@ static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn) return 0; if (arfcn < min_arfcn) { - DEBUGP(DRR, "arfcn(%u) < min(%u)\n", arfcn, min_arfcn); + LOGP(DRR, LOGL_ERROR, "arfcn(%u) < min(%u)\n", arfcn, min_arfcn); return -EINVAL; } if (arfcn > min_arfcn + 111) { - DEBUGP(DRR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn); + LOGP(DRR, LOGL_ERROR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn); return -EINVAL; } @@ -127,7 +129,8 @@ static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv, } if ((max - min) > 111) { - DEBUGP(DRR, "min_arfcn=%u, max_arfcn=%u, distance > 111\n", min, max); + LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, " + "distance > 111\n", min, max); return -EINVAL; } diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c index 128c34e94..2d7b05c70 100644 --- a/openbsc/src/telnet_interface.c +++ b/openbsc/src/telnet_interface.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -71,7 +72,7 @@ void telnet_init(struct gsm_network *network, int port) { fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd < 0) { - perror("Telnet interface socket creation failed"); + LOGP(DNM, LOGL_ERROR, "Telnet interface socket creation failed\n"); return; } @@ -83,12 +84,12 @@ void telnet_init(struct gsm_network *network, int port) { sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) { - perror("Telnet interface failed to bind"); + LOGP(DNM, LOG_ERROR, "Telnet interface failed to bind\n"); return; } if (listen(fd, 0) < 0) { - perror("Telnet interface failed to listen"); + LOGP(DNM, LOG_ERROR, "Telnet interface failed to listen\n"); return; } @@ -154,7 +155,7 @@ static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) { int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len); if (new_connection < 0) { - perror("telnet accept failed"); + LOGP(DNM, LOGL_ERROR, "telnet accept failed\n"); return -1; } @@ -171,8 +172,10 @@ static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) { print_welcome(new_connection); connection->vty = vty_create(new_connection, connection); - if (!connection->vty) + if (!connection->vty) { + LOGP(DNM, LOGL_ERROR, "couldn't create VTY\n"); return -1; + } return 0; } diff --git a/openbsc/src/trau_frame.c b/openbsc/src/trau_frame.c index aa039574b..2bc61a513 100644 --- a/openbsc/src/trau_frame.c +++ b/openbsc/src/trau_frame.c @@ -107,11 +107,13 @@ int decode_trau_frame(struct decoded_trau_frame *fr, const u_int8_t *trau_bits) case TRAU_FT_DATA_DOWN: case TRAU_FT_D145_SYNC: case TRAU_FT_EDATA: - DEBUGP(DMUX, "can't decode unimplemented TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "can't decode unimplemented TRAU " + "Frame Type 0x%02x\n", cbits5); return -1; break; default: - DEBUGP(DMUX, "can't decode unknown TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "can't decode unknown TRAU " + "Frame Type 0x%02x\n", cbits5); return -1; break; } @@ -162,11 +164,13 @@ int trau_frame_up2down(struct decoded_trau_frame *fr) case TRAU_FT_DATA_UP: case TRAU_FT_D145_SYNC: case TRAU_FT_EDATA: - DEBUGP(DMUX, "unimplemented TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "unimplemented TRAU Frame Type " + "0x%02x\n", cbits5); return -1; break; default: - DEBUGP(DMUX, "unknown TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "unknown TRAU Frame Type " + "0x%02x\n", cbits5); return -1; break; } @@ -224,11 +228,13 @@ int encode_trau_frame(u_int8_t *trau_bits, const struct decoded_trau_frame *fr) case TRAU_FT_DATA_DOWN: case TRAU_FT_D145_SYNC: case TRAU_FT_EDATA: - DEBUGP(DMUX, "unimplemented TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "unimplemented TRAU Frame Type " + "0x%02x\n", cbits5); return -1; break; default: - DEBUGP(DMUX, "unknown TRAU Frame Type 0x%02x\n", cbits5); + LOGP(DMUX, LOGL_NOTICE, "unknown TRAU Frame Type " + "0x%02x\n", cbits5); return -1; break; } diff --git a/openbsc/src/trau_mux.c b/openbsc/src/trau_mux.c index 6a19f0c99..7ea65ce35 100644 --- a/openbsc/src/trau_mux.c +++ b/openbsc/src/trau_mux.c @@ -56,8 +56,10 @@ int trau_mux_map(const struct gsm_e1_subslot *src, struct map_entry *me; me = talloc(tall_map_ctx, struct map_entry); - if (!me) + if (!me) { + LOGP(DMIB, LOGL_FATAL, "Out of memory\n"); return -ENOMEM; + } DEBUGP(DCC, "Setting up TRAU mux map between (e1=%u,ts=%u,ss=%u) " "and (e1=%u,ts=%u,ss=%u)\n", -- cgit v1.2.3 From e47f96b80c42809b99e5a875de949c843abd6957 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 11:49:03 +0100 Subject: fix segfault in case of handover timer expiration --- openbsc/src/handover_logic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 66ff77362..93870aa4c 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -169,6 +169,7 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) /* start T3103. We can continue either with T3103 expiration, * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */ ho->T3103.cb = ho_T3103_cb; + ho->T3103.data = ho; bsc_schedule_timer(&ho->T3103, 10, 0); return 0; -- cgit v1.2.3 From 386cd2b777ea24b55264c884ccb52efd44e04073 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 11:49:20 +0100 Subject: for now we only do handover of TCH channels --- openbsc/src/handover_decision.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index a1956868d..c0ec0a931 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -59,6 +59,15 @@ static int process_meas_rep(struct gsm_meas_rep *mr) unsigned int best_better_db; int i; + /* we currently only do handover for TCH channels */ + switch (mr->lchan->type) { + case GSM_LCHAN_TCH_F: + case GSM_LCHAN_TCH_H: + break; + default: + return 0; + } + /* FIXME: implement actual averaging over multiple measurement * reports */ -- cgit v1.2.3 From 6f7a5a7843877a82dc288a89ac0553333769b7ec Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 11:52:03 +0100 Subject: handover: use correct handover lookup function --- openbsc/src/handover_logic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 93870aa4c..d852f8e3c 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -246,7 +246,7 @@ static int ho_rsl_detect(struct gsm_lchan *new_lchan) { struct bsc_handover *ho; - ho = bsc_ho_by_old_lchan(new_lchan); + ho = bsc_ho_by_new_lchan(new_lchan); if (!ho) { LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); return -ENODEV; -- cgit v1.2.3 From a9fa8dca33e10c98db0ff6dddc2f999c37b25e63 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 14:50:08 +0100 Subject: [handover]: make sure the new lchan keeps the subscriber pointer of the old lchan also, ensure that we don't print debug messages about handover in non-handover channel activation cases. --- openbsc/src/handover_logic.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index d852f8e3c..f3f5d6c21 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -118,6 +118,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) new_lchan->bs_power = old_lchan->bs_power; new_lchan->rsl_cmode = old_lchan->rsl_cmode; new_lchan->tch_mode = old_lchan->tch_mode; + new_lchan->subscr = subscr_get(old_lchan->subscr); /* FIXME: do we have a better idea of the timing advance? */ rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0, @@ -153,13 +154,13 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) struct bsc_handover *ho; int rc; - DEBUGP(DHO, "handover activate ack, send HO Command\n"); - + /* we need to check if this channel activation is related to + * a handover at all (and if, which particular handover) */ ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) { - LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); + if (!ho) return -ENODEV; - } + + DEBUGP(DHO, "handover activate ack, send HO Command\n"); /* we can now send the 04.08 HANDOVER COMMAND to the MS * using the old lchan */ -- cgit v1.2.3 From 18750cf1df7d7a134c5dbfc2544800f746927bb0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 14:51:48 +0100 Subject: [handover] lchan use count handling in case of trans_lchan_change() --- openbsc/src/transaction.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index 9f1bbf36d..026928876 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -152,7 +152,12 @@ int trans_lchan_change(struct gsm_lchan *lchan_old, llist_for_each_entry(trans, &net->trans_list, entry) { if (trans->lchan == lchan_old) { + /* drop old channel use cound */ + put_lchan(trans->lchan); + /* assign new channel */ trans->lchan = lchan_new; + /* bump new channel use count */ + use_lchan(trans->lchan); num++; } } -- cgit v1.2.3 From 1d9efd6c9c318ec2ffdff537d80fbaf78f8a92c4 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:07 +0100 Subject: Fix typos in debug message / comments Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 4930e5c85..a87c6ed3d 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -173,7 +173,7 @@ static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans, DEBUGP(DSMS, "TX: CP-ACK "); break; case GSM411_MT_CP_ERROR: - DEBUGP(DSMS, "TX: CP-ACK "); + DEBUGP(DSMS, "TX: CP-ERROR "); break; } -- cgit v1.2.3 From c56a14181cf73e0530ecb791b2ae3bd913c998bd Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:08 +0100 Subject: Fix transaction_id displayed in debug message In SMS debug messages, we always display the transaction ID as if we were 'sending' the message. Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index a87c6ed3d..38f585b22 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -906,7 +906,7 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id) return -EIO; /* FIXME: send some error message */ - DEBUGP(DSMS, "trans_id=%x ", gh->proto_discr >> 4); + DEBUGP(DSMS, "trans_id=%x ", transaction_id); trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS, transaction_id); if (!trans) { -- cgit v1.2.3 From feaca92fc0dde67f392e1245a6fe0ea52d1022d5 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:09 +0100 Subject: Use 'new' rather than 'unknown' when starting transaction 'unknown' has a negative connotation for a case that's totally normal so refer to it as 'new' so it doesn't sound like a problem. Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 38f585b22..31526e979 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -910,7 +910,7 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id) trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS, transaction_id); if (!trans) { - DEBUGPC(DSMS, "(unknown) "); + DEBUGPC(DSMS, "(new) "); trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS, transaction_id, new_callref++); if (!trans) { -- cgit v1.2.3 From ea3f674710c8fab1bf06150b4cba67e139b5e04e Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:10 +0100 Subject: Fix subscr ref leak for multi CM SERV REQ Multiple CM SERVICE REQUEST can happen on a single RR connection, in this case, since the subscr reference is tracked through lchan->subscr and will only be put'd once on lchan_free, we need to make sure we don't get several reference .... Signed-off-by: Sylvain Munaut --- openbsc/src/gsm_04_08.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 5fea6bfbf..f87b3358f 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1343,7 +1343,9 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg) if (!msg->lchan->subscr) msg->lchan->subscr = subscr; - else if (msg->lchan->subscr != subscr) { + else if (msg->lchan->subscr == subscr) + subscr_put(subscr); /* lchan already has a ref, don't need another one */ + else { DEBUGP(DMM, "<- CM Channel already owned by someone else?\n"); subscr_put(subscr); } -- cgit v1.2.3 From b9f3dce0ae8e7064e3be4951d81c351a0b76ed41 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Fri, 18 Dec 2009 18:28:11 +0100 Subject: Never allocate transaction ID 7 According to GSM 04.07 11.2.3.1.3 , TID 7 is "reserved for future extensions". Signed-off-by: Sylvain Munaut --- openbsc/src/transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index 026928876..e49f75b28 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -133,7 +133,7 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr, used_tid_bitmask |= (1 << trans->transaction_id); } - for (i = 0; i <= 7; i++) { + for (i = 0; i < 7; i++) { if ((used_tid_bitmask & (1 << (i | ti_flag))) == 0) return i | ti_flag; } -- cgit v1.2.3 From f314f6899b89cacae521daf12db85531a5e20dc5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 18 Dec 2009 15:05:02 +0100 Subject: add --help message about --rtp-proxy argument --- openbsc/src/bsc_hack.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index b0f8d6c3f..c0695ef35 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -75,6 +75,7 @@ static void print_help() printf(" -l --database db-name The database to use\n"); printf(" -p --pcap file The filename of the pcap file\n"); printf(" -T --timestamp Prefix every log line with a timestamp\n"); + printf(" -P --rtp-proxy Enable the RTP Proxy code inside OpenBSC\n"); } static void handle_options(int argc, char** argv) -- cgit v1.2.3 From 5e3d91bff71a9c456069bbf4a459b66a32f9656e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 16:42:06 +0100 Subject: ip.access: Keep a full copy of local and remote IP/PORT in lchan Keeping all parameters for each RTP connection in the abis_ip member of lchan will help us with actual TCH handover later on. --- openbsc/src/abis_rsl.c | 137 +++++++++++++++++++++++++++++++----------------- openbsc/src/gsm_04_08.c | 3 -- 2 files changed, 89 insertions(+), 51 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index c4bb4bd11..3310c5724 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1495,11 +1495,63 @@ static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan) } /* ip.access specific RSL extensions */ +static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv) +{ + struct in_addr ip; + u_int16_t port, conn_id; + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_LOCAL_IP)) { + ip.s_addr = *((u_int32_t *) TLVP_VAL(tv, RSL_IE_IPAC_LOCAL_IP)); + DEBUGPC(DRSL, "LOCAL_IP=%s ", inet_ntoa(ip)); + lchan->abis_ip.bound_ip = ntohl(ip.s_addr); + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_LOCAL_PORT)) { + port = *((u_int16_t *) TLVP_VAL(tv, RSL_IE_IPAC_LOCAL_PORT)); + port = ntohs(port); + DEBUGPC(DRSL, "LOCAL_PORT=%u ", port); + lchan->abis_ip.bound_port = port; + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_CONN_ID)) { + conn_id = *((u_int16_t *) TLVP_VAL(tv, RSL_IE_IPAC_CONN_ID)); + conn_id = ntohs(conn_id); + DEBUGPC(DRSL, "CON_ID=%u ", conn_id); + lchan->abis_ip.conn_id = conn_id; + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_RTP_PAYLOAD2)) { + lchan->abis_ip.rtp_payload2 = + *TLVP_VAL(tv, RSL_IE_IPAC_RTP_PAYLOAD2); + DEBUGPC(DRSL, "RTP_PAYLOAD2=0x%02x ", + lchan->abis_ip.rtp_payload2); + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_SPEECH_MODE)) { + lchan->abis_ip.speech_mode = + *TLVP_VAL(tv, RSL_IE_IPAC_SPEECH_MODE); + DEBUGPC(DRSL, "speech_mode=0x%02x ", + lchan->abis_ip.speech_mode); + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_REMOTE_IP)) { + ip.s_addr = *((u_int32_t *) TLVP_VAL(tv, RSL_IE_IPAC_REMOTE_IP)); + DEBUGPC(DRSL, "REMOTE_IP=%s ", inet_ntoa(ip)); + lchan->abis_ip.connect_ip = ntohl(ip.s_addr); + } + + if (TLVP_PRESENT(tv, RSL_IE_IPAC_REMOTE_PORT)) { + port = *((u_int16_t *) TLVP_VAL(tv, RSL_IE_IPAC_REMOTE_PORT)); + port = ntohs(port); + DEBUGPC(DRSL, "REMOTE_PORT=%u ", port); + lchan->abis_ip.connect_port = port; + } +} + int rsl_ipacc_crcx(struct gsm_lchan *lchan) { struct msgb *msg = rsl_msgb_alloc(); struct abis_rsl_dchan_hdr *dh; - u_int8_t speech_mode; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); init_dchan_hdr(dh, RSL_MT_IPAC_CRCX); @@ -1507,12 +1559,12 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan) dh->chan_nr = lchan2chan_nr(lchan); /* 0x1- == receive-only, 0x-1 == EFR codec */ - speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan); - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode); + lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan); + msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND " "speech_mode=0x%02x\n", gsm_ts_name(lchan->ts), - dh->chan_nr, speech_mode); + dh->chan_nr, lchan->abis_ip.speech_mode); msg->trx = lchan->ts->trx; @@ -1520,12 +1572,11 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan) } int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, - u_int16_t conn_id, u_int8_t rtp_payload2) + u_int8_t rtp_payload2) { struct msgb *msg = rsl_msgb_alloc(); struct abis_rsl_dchan_hdr *dh; - u_int8_t *att_f8, *att_ip, *att_port; - u_int8_t speech_mode; + u_int32_t *att_ip; struct in_addr ia; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); @@ -1533,34 +1584,26 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; dh->chan_nr = lchan2chan_nr(lchan); + /* we need to store these now as MDCX_ACK does not return them :( */ + lchan->abis_ip.rtp_payload2 = rtp_payload2; + lchan->abis_ip.connect_port = port; + lchan->abis_ip.connect_ip = ip; + /* 0x0- == both directions, 0x-1 == EFR codec */ - speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan); + lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan); ia.s_addr = htonl(ip); DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_MDCX " "IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d speech_mode=0x%02x\n", - gsm_ts_name(lchan->ts), dh->chan_nr, - inet_ntoa(ia), port, rtp_payload2, conn_id, speech_mode); - - att_f8 = msgb_put(msg, sizeof(conn_id)+1); - att_f8[0] = RSL_IE_IPAC_CONN_ID; - att_f8[1] = conn_id >> 8; - att_f8[2] = conn_id & 0xff; - - att_ip = msgb_put(msg, sizeof(ip)+1); - att_ip[0] = RSL_IE_IPAC_REMOTE_IP; - att_ip[1] = ip >> 24; - att_ip[2] = ip >> 16; - att_ip[3] = ip >> 8; - att_ip[4] = ip & 0xff; - //att_ip[4] = 11; - - att_port = msgb_put(msg, sizeof(port)+1); - att_port[0] = RSL_IE_IPAC_REMOTE_PORT; - att_port[1] = port >> 8; - att_port[2] = port & 0xff; - - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode); + gsm_ts_name(lchan->ts), dh->chan_nr, inet_ntoa(ia), port, + rtp_payload2, lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode); + + msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id); + msgb_v_put(msg, RSL_IE_IPAC_REMOTE_IP); + att_ip = (u_int32_t *) msgb_put(msg, sizeof(ip)); + *att_ip = ia.s_addr; + msgb_tv16_put(msg, RSL_IE_IPAC_REMOTE_PORT, port); + msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); if (rtp_payload2) msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2); @@ -1592,8 +1635,6 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; struct gsm_lchan *lchan = msg->lchan; - struct in_addr ip; - u_int16_t port, attr_f8; /* the BTS has acknowledged a local bind, it now tells us the IP * address and port number to which it has bound the given logical @@ -1606,26 +1647,25 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) LOGP(DRSL, LOGL_NOTICE, "mandatory IE missing"); return -EINVAL; } - ip.s_addr = *((u_int32_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_IP)); - port = *((u_int16_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_PORT)); - attr_f8 = *((u_int16_t *) TLVP_VAL(&tv, 0xf8)); + ipac_parse_rtp(lchan, &tv); + dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); - DEBUGPC(DRSL, "IP=%s PORT=%d CONN_ID=%d ", - inet_ntoa(ip), ntohs(port), ntohs(attr_f8)); + return 0; +} - if (TLVP_PRESENT(&tv, RSL_IE_IPAC_RTP_PAYLOAD2)) { - lchan->abis_ip.rtp_payload2 = - *TLVP_VAL(&tv, RSL_IE_IPAC_RTP_PAYLOAD2); - DEBUGPC(DRSL, "RTP_PAYLOAD2=0x%02x ", - lchan->abis_ip.rtp_payload2); - } +static int abis_rsl_rx_ipacc_mdcx_ack(struct msgb *msg) +{ + struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); + struct tlv_parsed tv; + struct gsm_lchan *lchan = msg->lchan; - /* update our local information about this TS */ - lchan->abis_ip.bound_ip = ntohl(ip.s_addr); - lchan->abis_ip.bound_port = ntohs(port); - lchan->abis_ip.conn_id = ntohs(attr_f8); + /* the BTS has acknowledged a remote connect request and + * it now tells us the IP address and port number to which it has + * connected the given logical channel */ - dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); + rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); + ipac_parse_rtp(lchan, &tv); + dispatch_signal(SS_ABISIP, S_ABISIP_MDCX_ACK, msg->lchan); return 0; } @@ -1668,6 +1708,7 @@ static int abis_rsl_rx_ipacc(struct msgb *msg) case RSL_MT_IPAC_MDCX_ACK: /* the BTS tells us that a connect operation was successful */ DEBUGPC(DRSL, "IPAC_MDCX_ACK "); + rc = abis_rsl_rx_ipacc_mdcx_ack(msg); break; case RSL_MT_IPAC_MDCX_NACK: /* somehow the BTS was unable to connect the lchan to a remote diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index f87b3358f..589133e27 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1920,7 +1920,6 @@ static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan) rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), ntohs(rs->rtp.sin_local.sin_port), - lchan->abis_ip.conn_id, /* FIXME: use RTP payload of bound socket, not BTS*/ lchan->abis_ip.rtp_payload2); @@ -1959,13 +1958,11 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) /* directly connect TCH RTP streams to each other */ rc = rsl_ipacc_mdcx(lchan, remote_lchan->abis_ip.bound_ip, remote_lchan->abis_ip.bound_port, - lchan->abis_ip.conn_id, remote_lchan->abis_ip.rtp_payload2); if (rc < 0) return rc; rc = rsl_ipacc_mdcx(remote_lchan, lchan->abis_ip.bound_ip, lchan->abis_ip.bound_port, - remote_lchan->abis_ip.conn_id, lchan->abis_ip.rtp_payload2); } break; -- cgit v1.2.3 From 51cec5f7259e14e4c6f78a69c3d411964b1baf4c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 16:45:29 +0100 Subject: measurement report parsing: NO-NCELL-M of 7 tells us no neighbors --- openbsc/src/gsm_04_08.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 589133e27..d59d7d7ca 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -191,7 +191,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2); - if (rep->num_cell < 1) + if (rep->num_cell < 1 || rep->num_cell > 6) return 0; /* an encoding nightmare in perfection */ -- cgit v1.2.3 From 479015bc1fc46ff7e0082d4636ef5b83e1af0412 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 18:33:05 +0100 Subject: don't print measurement reports that have no cells --- openbsc/src/abis_rsl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 3310c5724..2d55806a1 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1003,6 +1003,8 @@ static void print_meas_rep(struct gsm_meas_rep *mr) print_meas_rep_uni(&mr->dl, "dl"); DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", mr->num_cell); + if (mr->num_cell == 7) + return; for (i = 0; i < mr->num_cell; i++) { struct gsm_meas_rep_cell *mrc = &mr->cell[i]; DEBUGP(DMEAS, "ARFCN=%u BSIC=%u => %d dBm\n", mrc->arfcn, mrc->bsic, -- cgit v1.2.3 From e2d0d5fa8c596cf22f266471995f96215b39fc9d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 21:26:54 +0100 Subject: system_information: ip.access wants L2_PLEN, BS-11 doesn't It seems that depending on the manufacturer, there is a need to include the L2 pseudo-length in the SI5+SI6 messasges (SACCH FILLING) Thanks to Dieter for pointing this out. --- openbsc/src/system_information.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index b404e5151..df4f1a0c8 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -316,10 +316,16 @@ static int generate_si4(u_int8_t *output, struct gsm_bts *bts) static int generate_si5(u_int8_t *output, struct gsm_bts *bts) { - struct gsm48_system_information_type_5 *si5 = - (struct gsm48_system_information_type_5 *) output; - int rc; + struct gsm48_system_information_type_5 *si5; + int rc, l2_plen = 18; + + /* ip.access nanoBTS needs l2_plen!! */ + if (is_ipaccess_bts(bts)) { + *output++ = (l2_plen << 2) | 1; + l2_plen++; + } + si5 = (struct gsm48_system_information_type_5 *) output; memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); /* l2 pseudo length, not part of msg: 18 */ @@ -331,14 +337,21 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts) return rc; /* 04.08 9.1.37: L2 Pseudo Length of 18 */ - return 18; + return l2_plen; } static int generate_si6(u_int8_t *output, struct gsm_bts *bts) { - struct gsm48_system_information_type_6 *si6 = - (struct gsm48_system_information_type_6 *) output; + struct gsm48_system_information_type_6 *si6; + int l2_plen = 11; + + /* ip.access nanoBTS needs l2_plen!! */ + if (is_ipaccess_bts(bts)) { + *output++ = (l2_plen << 2) | 1; + l2_plen++; + } + si6 = (struct gsm48_system_information_type_6 *) output; memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); /* l2 pseudo length, not part of msg: 11 */ @@ -354,7 +367,7 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts) /* SI6 Rest Octets: 10.5.2.35a: PCH / NCH info, VBS/VGCS options */ - return 18; + return l2_plen; } static struct gsm48_si13_info si13_default = { -- cgit v1.2.3 From 50e7fec9b892c32655ce74431e45437669bffac6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 21:29:00 +0100 Subject: system_information: DEBUGP() SI13/5/6 during startup --- openbsc/src/bsc_init.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 744eacb24..7065833bf 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -679,30 +679,30 @@ static int set_system_infos(struct gsm_bts_trx *trx) rc = gsm_generate_si(si_tmp, trx->bts, i); if (rc < 0) goto err_out; - DEBUGP(DRR, "SI%u: %s\n", i, hexdump(si_tmp, rc)); + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } } #ifdef GPRS + i = 13 rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); - if (rc < 0) { - i = 13; + if (rc < 0) goto err_out; - } + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); #endif - rc = gsm_generate_si(si_tmp, trx->bts, 5); - if (rc < 0) { - i = 5; + i = 5; + rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_5); + if (rc < 0) goto err_out; - } + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si_tmp, rc); - rc = gsm_generate_si(si_tmp, trx->bts, 6); - if (rc < 0) { - i = 6; + i = 6; + rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_6); + if (rc < 0) goto err_out; - } + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si_tmp, rc); return 0; -- cgit v1.2.3 From e786c32bc935bb7767335758e92c886322c8aeb5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 21:29:19 +0100 Subject: [handover] don't use measurement reports with NCELL=7 NCELL=7 inidicates that there was no neighbor cell info in the SI5 on the SACCH. --- openbsc/src/handover_decision.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index c0ec0a931..3605a8e0a 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -71,6 +71,9 @@ static int process_meas_rep(struct gsm_meas_rep *mr) /* FIXME: implement actual averaging over multiple measurement * reports */ + if (mr->num_cell > 6) + return 0; + /* find the best cell in this report that is at least RXLEV_HYST * better than the current serving cell */ for (i = 0; i < mr->num_cell; i++) { -- cgit v1.2.3 From bc814501e8a28f72e16a4662250af01aaa2a1489 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 21:41:52 +0100 Subject: [handover] add VTY parameter to enable/disable handover --- openbsc/src/handover_decision.c | 18 +++++++++++------- openbsc/src/vty_interface.c | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index 3605a8e0a..4c08c6664 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -88,15 +88,19 @@ static int process_meas_rep(struct gsm_meas_rep *mr) } } - if (mr_cell) { - LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better, starting " - "handover\n", mr_cell->arfcn); - return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, - mr_cell->bsic); + if (!mr_cell) { + DEBUGPC(DHO, "No better cell\n"); + return 0; } - DEBUGPC(DHO, "No better cell\n"); - return 0; + LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better: ", mr_cell->arfcn); + if (!mr->lchan->ts->trx->bts->network->handover.active) { + LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n"); + return 0; + } + + LOGPC(DHO, LOGL_INFO, "Starting handover\n"); + return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, mr_cell->bsic); } static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal, diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index d5344edac..20df9091d 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -95,6 +95,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) VTY_NEWLINE); vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off", VTY_NEWLINE); + vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off", + VTY_NEWLINE); } DEFUN(show_net, show_net_cmd, "show network", @@ -296,6 +298,7 @@ static int config_write_net(struct vty *vty) vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), VTY_NEWLINE); vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE); + vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); @@ -863,6 +866,16 @@ DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd, return CMD_SUCCESS; } +DEFUN(cfg_net_handover, cfg_net_handover_cmd, + "handover (0|1)", + "Whether or not to use in-call handover") +{ + gsmnet->handover.active = atoi(argv[0]); + + return CMD_SUCCESS; +} + + #define DECLARE_TIMER(number) \ DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ @@ -1371,6 +1384,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd); install_element(GSMNET_NODE, &cfg_net_mm_info_cmd); + install_element(GSMNET_NODE, &cfg_net_handover_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd); -- cgit v1.2.3 From da7ab74298b9fdb5eb27d6575e8a15683b69889f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 22:23:05 +0100 Subject: RTP-enable MNCC API for LCR + ip.access Instead of passing TRAU frames down the MNCC API to the call control application like MNCC, we now decode the TRAU frame into the actual codec frame. We do the same with the RTP packets in case of ip.access and thus have a unified format of passing codec data from the BTS to an application, independent of the BTS type. This is only implemented for V1 full-rate at the moment, and needs to be fixed. --- openbsc/src/gsm_04_08.c | 117 +++++++++++++++++-------- openbsc/src/rtp_proxy.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++-- openbsc/src/trau_mux.c | 92 ++++++++++++++++++-- 3 files changed, 388 insertions(+), 48 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index d59d7d7ca..f36723937 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1864,12 +1864,16 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, return 0; } +static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable); + /* some other part of the code sends us a signal */ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { struct gsm_lchan *lchan = signal_data; int rc; + struct gsm_network *net; + struct gsm_trans *trans; if (subsys != SS_ABISIP) return 0; @@ -1896,6 +1900,15 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, lchan->abis_ip.bound_port); if (rc < 0) goto out_err; + /* check if any transactions on this lchan still have + * a tch_recv_mncc request pending */ + net = lchan->ts->trx->bts->network; + llist_for_each_entry(trans, &net->trans_list, entry) { + if (trans->lchan == lchan && trans->tch_recv) { + DEBUGP(DCC, "pending tch_recv_mncc request\n"); + tch_recv_mncc(net, trans->callref, 1); + } + } break; case S_ABISIP_DLCX_IND: /* the BTS tells us a RTP stream has been disconnected */ @@ -1941,7 +1954,8 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n"); return -EINVAL; } - + + // todo: map between different bts types switch (bts->type) { case GSM_BTS_TYPE_NANOBTS: if (!ipacc_rtp_direct) { @@ -1950,6 +1964,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) if (rc < 0) return rc; rc = ipacc_connect_proxy_bind(remote_lchan); +#warning do we need a check of rc here? /* connect them with each other */ rtp_socket_proxy(lchan->abis_ip.rtp_socket, @@ -1971,8 +1986,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) break; default: DEBUGP(DCC, "Unknown BTS type %u\n", bts->type); - rc = -EINVAL; - break; + return -EINVAL; } return 0; @@ -1994,45 +2008,61 @@ static int tch_bridge(struct gsm_network *net, u_int32_t *refs) return tch_map(trans1->lchan, trans2->lchan); } -/* enable receive of channels to upqueue */ -static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable) +/* enable receive of channels to MNCC upqueue */ +static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable) { struct gsm_trans *trans; + struct gsm_lchan *lchan; + struct gsm_bts *bts; + int rc; /* Find callref */ - trans = trans_find_by_callref(net, data->callref); + trans = trans_find_by_callref(net, callref); if (!trans) return -EIO; if (!trans->lchan) return 0; + lchan = trans->lchan; + bts = lchan->ts->trx->bts; - // todo IPACCESS - if (enable) - return trau_recv_lchan(trans->lchan, data->callref); - return trau_mux_unmap(NULL, data->callref); -} - -/* send a frame to channel */ -static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame) -{ - struct gsm_trans *trans; - - /* Find callref */ - trans = trans_find_by_callref(net, frame->callref); - if (!trans) - return -EIO; - if (!trans->lchan) - return 0; - if (trans->lchan->type != GSM_LCHAN_TCH_F && - trans->lchan->type != GSM_LCHAN_TCH_H) - return 0; + switch (bts->type) { + case GSM_BTS_TYPE_NANOBTS: + if (ipacc_rtp_direct) { + DEBUGP(DCC, "Error: RTP proxy is disabled\n"); + return -EINVAL; + } + /* in case, we don't have a RTP socket yet, we note this + * in the transaction and try later */ + if (!lchan->abis_ip.rtp_socket) { + trans->tch_recv = enable; + DEBUGP(DCC, "queue tch_recv_mncc request (%d)\n", enable); + return 0; + } + if (enable) { + /* connect the TCH's to our RTP proxy */ + rc = ipacc_connect_proxy_bind(lchan); + if (rc < 0) + return rc; + /* assign socket to application interface */ + rtp_socket_upstream(lchan->abis_ip.rtp_socket, + net, callref); + } else + rtp_socket_upstream(lchan->abis_ip.rtp_socket, + net, 0); + break; + case GSM_BTS_TYPE_BS11: + if (enable) + return trau_recv_lchan(lchan, callref); + return trau_mux_unmap(NULL, callref); + break; + default: + DEBUGP(DCC, "Unknown BTS type %u\n", bts->type); + return -EINVAL; + } - // todo IPACCESS - return trau_send_lchan(trans->lchan, - (struct decoded_trau_frame *)frame->data); + return 0; } - static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg) { DEBUGP(DCC, "-> STATUS ENQ\n"); @@ -3262,11 +3292,30 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) case MNCC_BRIDGE: return tch_bridge(net, arg); case MNCC_FRAME_DROP: - return tch_recv(net, arg, 0); + return tch_recv_mncc(net, data->callref, 0); case MNCC_FRAME_RECV: - return tch_recv(net, arg, 1); - case GSM_TRAU_FRAME: - return tch_frame(net, arg); + return tch_recv_mncc(net, data->callref, 1); + case GSM_TCHF_FRAME: + /* Find callref */ + trans = trans_find_by_callref(net, data->callref); + if (!trans) + return -EIO; + if (!trans->lchan) + return 0; + if (trans->lchan->type != GSM_LCHAN_TCH_F) + return 0; + bts = trans->lchan->ts->trx->bts; + switch (bts->type) { + case GSM_BTS_TYPE_NANOBTS: + if (!trans->lchan->abis_ip.rtp_socket) + return 0; + return rtp_send_frame(trans->lchan->abis_ip.rtp_socket, arg); + case GSM_BTS_TYPE_BS11: + return trau_send_frame(trans->lchan, arg); + default: + DEBUGP(DCC, "Unknown BTS type %u\n", bts->type); + } + return -EINVAL; } memset(&rel, 0, sizeof(struct gsm_mncc)); diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index bfd494856..f9207d661 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -24,6 +24,10 @@ #include #include #include +#include /* gettimeofday() */ +#include /* get..() */ +#include /* clock() */ +#include /* uname() */ #include #include @@ -57,6 +61,169 @@ struct rtcp_hdr { #define RTCP_IE_CNAME 1 +/* according to RFC 3550 */ +struct rtp_hdr { + u_int8_t csrc_count:4, + extension:1, + padding:1, + version:2; + u_int8_t payload_type:7, + marker:1; + u_int16_t sequence; + u_int32_t timestamp; + u_int32_t ssrc; +} __attribute__((packed)); + +struct rtp_x_hdr { + u_int16_t by_profile; + u_int16_t length; +} __attribute__((packed)); + +#define RTP_VERSION 2 + +#define RTP_PT_GSM_FULL 3 + +/* decode an rtp frame and create a new buffer with payload */ +static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data) +{ + struct msgb *new_msg; + struct gsm_data_frame *frame; + struct rtp_hdr *rtph = (struct rtp_hdr *)msg->data; + struct rtp_x_hdr *rtpxh; + u_int8_t *payload; + int payload_len; + int msg_type; + int x_len; + + if (msg->len < 12) { + DEBUGPC(DMUX, "received RTP frame too short (len = %d)\n", + msg->len); + return -EINVAL; + } + if (rtph->version != RTP_VERSION) { + DEBUGPC(DMUX, "received RTP version %d not supported.\n", + rtph->version); + return -EINVAL; + } + payload = msg->data + sizeof(struct rtp_hdr) + (rtph->csrc_count << 2); + payload_len = msg->len - sizeof(struct rtp_hdr) - (rtph->csrc_count << 2); + if (payload_len < 0) { + DEBUGPC(DMUX, "received RTP frame too short (len = %d, " + "csrc count = %d)\n", msg->len, rtph->csrc_count); + return -EINVAL; + } + if (rtph->extension) { + if (payload_len < sizeof(struct rtp_x_hdr)) { + DEBUGPC(DMUX, "received RTP frame too short for " + "extension header\n"); + return -EINVAL; + } + rtpxh = (struct rtp_x_hdr *)payload; + x_len = ntohs(rtpxh->length) * 4 + sizeof(struct rtp_x_hdr); + payload += x_len; + payload_len -= x_len; + if (payload_len < 0) { + DEBUGPC(DMUX, "received RTP frame too short, " + "extension header exceeds frame length\n"); + return -EINVAL; + } + } + if (rtph->padding) { + if (payload_len < 0) { + DEBUGPC(DMUX, "received RTP frame too short for " + "padding length\n"); + return -EINVAL; + } + payload_len -= payload[payload_len - 1]; + if (payload_len < 0) { + DEBUGPC(DMUX, "received RTP frame with padding " + "greater than payload\n"); + return -EINVAL; + } + } + + switch (rtph->payload_type) { + case RTP_PT_GSM_FULL: + msg_type = GSM_TCHF_FRAME; + if (payload_len != 33) { + DEBUGPC(DMUX, "received RTP full rate frame with " + "payload length != 32 (len = %d)\n", + payload_len); + return -EINVAL; + } + break; + default: + DEBUGPC(DMUX, "received RTP frame with unknown payload " + "type %d\n", rtph->payload_type); + return -EINVAL; + } + + new_msg = msgb_alloc(sizeof(struct gsm_data_frame) + payload_len, + "GSM-DATA"); + if (!new_msg) + return -ENOMEM; + frame = (struct gsm_data_frame *)(new_msg->data); + frame->msg_type = msg_type; + frame->callref = callref; + memcpy(frame->data, payload, payload_len); + msgb_put(new_msg, sizeof(struct gsm_data_frame) + payload_len); + + *data = new_msg; + return 0; +} + +/* encode and send a rtp frame */ +int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) +{ + struct rtp_sub_socket *rss = &rs->rtp; + struct msgb *msg; + struct rtp_hdr *rtph; + int payload_type; + int payload_len; + int duration; /* in samples */ + + if (rs->tx_action != RTP_SEND_DOWNSTREAM) { + /* initialize sequences */ + rs->tx_action = RTP_SEND_DOWNSTREAM; + rs->transmit.ssrc = rand(); + rs->transmit.sequence = random(); + rs->transmit.timestamp = random(); + } + + switch (frame->msg_type) { + case GSM_TCHF_FRAME: + payload_type = RTP_PT_GSM_FULL; + payload_len = 33; + duration = 160; + break; + default: + DEBUGPC(DMUX, "unsupported message type %d\n", + frame->msg_type); + return -EINVAL; + } + + msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP-GSM-FULL"); + if (!msg) + return -ENOMEM; + rtph = (struct rtp_hdr *)msg->data; + rtph->version = RTP_VERSION; + rtph->padding = 0; + rtph->extension = 0; + rtph->csrc_count = 0; + rtph->marker = 0; + rtph->payload_type = payload_type; + rtph->sequence = htons(rs->transmit.sequence++); + rtph->timestamp = htonl(rs->transmit.timestamp); + rs->transmit.timestamp += duration; + rtph->ssrc = htonl(rs->transmit.ssrc); + memcpy(msg->data + sizeof(struct rtp_hdr), frame->data, payload_len); + msgb_put(msg, sizeof(struct rtp_hdr) + payload_len); + msgb_enqueue(&rss->tx_queue, msg); + rss->bfd.when |= BSC_FD_WRITE; + + return 0; +} + /* iterate over all chunks in one RTCP message, look for CNAME IEs and * replace all of those with 'new_cname' */ static int rtcp_sdes_cname_mangle(struct msgb *msg, struct rtcp_hdr *rh, @@ -123,10 +290,16 @@ static int rtcp_mangle(struct msgb *msg, struct rtp_socket *rs) if (!mangle_rtcp_cname) return 0; + printf("RTCP\n"); /* iterate over list of RTCP messages */ rtph = (struct rtcp_hdr *)msg->data; - while ((void *)rtph + sizeof(*rtph) < (void *)msg->data + msg->len) { + while ((void *)rtph + sizeof(*rtph) <= (void *)msg->data + msg->len) { old_len = (ntohs(rtph->length) + 1) * 4; + if ((void *)rtph + old_len > (void *)msg->data + msg->len) { + DEBUGPC(DMUX, "received RTCP packet too short for " + "length element\n"); + return -EINVAL; + } if (rtph->type == RTCP_TYPE_SDES) { char new_cname[255]; strncpy(new_cname, inet_ntoa(rss->sin_local.sin_addr), @@ -148,6 +321,7 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss) { int rc; struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP"); + struct msgb *new_msg; struct rtp_sub_socket *other_rss; if (!msg) @@ -184,13 +358,40 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss) break; case RTP_RECV_UPSTREAM: - case RTP_NONE: - /* FIXME: other cases */ - DEBUGP(DMUX, "unhandled action: %d\n", rs->rx_action); + if (!rs->receive.callref || !rs->receive.net) { + rc = -EIO; + goto out_free; + } + if (rss->bfd.priv_nr == RTP_PRIV_RTCP) { + if (!mangle_rtcp_cname) { + msgb_free(msg); + break; + } + /* modify RTCP SDES CNAME */ + rc = rtcp_mangle(msg, rs); + if (rc < 0) + goto out_free; + msgb_enqueue(&rss->tx_queue, msg); + rss->bfd.when |= BSC_FD_WRITE; + break; + } + if (rss->bfd.priv_nr != RTP_PRIV_RTP) { + rc = -EINVAL; + goto out_free; + } + rc = rtp_decode(msg, rs->receive.callref, &new_msg); + if (rc < 0) + goto out_free; + msgb_free(msg); + msgb_enqueue(&rs->receive.net->upqueue, new_msg); + break; + + case RTP_NONE: /* if socket exists, but disabled by app */ + msgb_free(msg); break; } - return rc; + return 0; out_free: msgb_free(msg); @@ -420,6 +621,22 @@ int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other) return 0; } +/* bind RTP/RTCP socket to application */ +int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, u_int32_t callref) +{ + DEBUGP(DMUX, "rtp_socket_proxy(this=%p, callref=%lu)\n", + this, callref); + + if (callref) { + this->rx_action = RTP_RECV_UPSTREAM; + this->receive.net = net; + this->receive.callref = callref; + } else + this->rx_action = RTP_NONE; + + return 0; +} + static void free_tx_queue(struct rtp_sub_socket *rss) { struct msgb *msg; diff --git a/openbsc/src/trau_mux.c b/openbsc/src/trau_mux.c index 7ea65ce35..477ea21e5 100644 --- a/openbsc/src/trau_mux.c +++ b/openbsc/src/trau_mux.c @@ -32,6 +32,19 @@ #include #include +u_int8_t gsm_fr_map[] = { + 6, 6, 5, 5, 4, 4, 3, 3, + 7, 2, 2, 6, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 7, 2, 2, 6, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 7, 2, 2, 6, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 7, 2, 2, 6, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3 +}; + struct map_entry { struct llist_head list; struct gsm_e1_subslot src, dst; @@ -144,6 +157,8 @@ lookup_trau_upqueue(const struct gsm_e1_subslot *src) return NULL; } +static const u_int8_t c_bits_check[] = { 0, 0, 0, 1, 0 }; + /* we get called by subchan_demux */ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, const u_int8_t *trau_bits, int num_bits) @@ -153,8 +168,6 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss); struct subch_mux *mx; struct upqueue_entry *ue; - struct msgb *msg; - struct gsm_trau_frame *frame; int rc; /* decode TRAU, change it to downlink, re-encode */ @@ -163,19 +176,44 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, return rc; if (!dst_e1_ss) { + struct msgb *msg; + struct gsm_data_frame *frame; + unsigned char *data; + int i, j, k, l, o; /* frame shall be sent to upqueue */ if (!(ue = lookup_trau_upqueue(src_e1_ss))) return -EINVAL; if (!ue->callref) return -EINVAL; - msg = msgb_alloc(sizeof(struct gsm_trau_frame) + sizeof(tf), - "TRAU"); + if (memcpy(tf.c_bits, c_bits_check, sizeof(c_bits_check))) + DEBUGPC(DMUX, "illegal trau (C1-C5) %s\n", + hexdump(tf.c_bits, sizeof(c_bits_check))); + msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33, + "GSM-DATA"); if (!msg) return -ENOMEM; - frame = (struct gsm_trau_frame *)msg->data; - frame->msg_type = GSM_TRAU_FRAME; + + frame = (struct gsm_data_frame *)msg->data; + memset(frame, 0, sizeof(struct gsm_data_frame)); + data = frame->data; + data[0] = 0xd << 4; + /* reassemble d-bits */ + i = 0; /* counts bits */ + j = 4; /* counts output bits */ + k = gsm_fr_map[0]-1; /* current number bit in element */ + l = 0; /* counts element bits */ + o = 0; /* offset input bits */ + while (i < 260) { + data[j/8] |= (tf.d_bits[k+o] << (7-(j%8))); + if (--k < 0) { + o += gsm_fr_map[l]; + k = gsm_fr_map[++l]-1; + } + i++; + j++; + } + frame->msg_type = GSM_TCHF_FRAME; frame->callref = ue->callref; - memcpy(frame->data, &tf, sizeof(tf)); msgb_enqueue(&ue->net->upqueue, msg); return 0; @@ -221,17 +259,53 @@ int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref) return 0; } -int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf) +int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame) { u_int8_t trau_bits_out[TRAU_FRAME_BITS]; struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link; struct subch_mux *mx; + int i, j, k, l, o; + unsigned char *data = frame->data; + struct decoded_trau_frame tf; mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts); if (!mx) return -EINVAL; - encode_trau_frame(trau_bits_out, tf); + switch (frame->msg_type) { + case GSM_TCHF_FRAME: + /* set c-bits and t-bits */ + tf.c_bits[0] = 1; + tf.c_bits[1] = 1; + tf.c_bits[2] = 1; + tf.c_bits[3] = 0; + tf.c_bits[4] = 0; + memset(&tf.c_bits[5], 0, 6); + memset(&tf.c_bits[11], 1, 10); + memset(&tf.t_bits[0], 1, 4); + /* reassemble d-bits */ + i = 0; /* counts bits */ + j = 4; /* counts input bits */ + k = gsm_fr_map[0]-1; /* current number bit in element */ + l = 0; /* counts element bits */ + o = 0; /* offset output bits */ + while (i < 260) { + tf.d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1; + if (--k < 0) { + o += gsm_fr_map[l]; + k = gsm_fr_map[++l]-1; + } + i++; + j++; + } + break; + default: + DEBUGPC(DMUX, "unsupported message type %d\n", + frame->msg_type); + return -EINVAL; + } + + encode_trau_frame(trau_bits_out, &tf); /* and send it to the muxer */ return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out, -- cgit v1.2.3 From aca8f158bccfc129a9eae234339a2b9c96d6f230 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 19 Dec 2009 23:06:41 +0100 Subject: Add RTP support for EFR This is just the minimal support to receive and send EFR codec RTP frames. We are missing the code to convert TRAU frames in EFR format! --- openbsc/src/mncc.c | 2 +- openbsc/src/rtp_proxy.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index a5efc7312..f53b15dcb 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -83,7 +83,7 @@ static struct mncc_names { {"MNCC_FRAME_DROP", 0x0202}, {"MNCC_LCHAN_MODIFY", 0x0203}, - {"GSM_TRAU_FRAME", 0x0300}, + {"GSM_TCH_FRAME", 0x0300}, {NULL, 0} }; diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index f9207d661..551349750 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -82,6 +82,7 @@ struct rtp_x_hdr { #define RTP_VERSION 2 #define RTP_PT_GSM_FULL 3 +#define RTP_PT_GSM_EFR 97 /* decode an rtp frame and create a new buffer with payload */ static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data) @@ -152,6 +153,9 @@ static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data) return -EINVAL; } break; + case RTP_PT_GSM_EFR: + msg_type = GSM_TCHF_FRAME_EFR; + break; default: DEBUGPC(DMUX, "received RTP frame with unknown payload " "type %d\n", rtph->payload_type); @@ -196,6 +200,11 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) payload_len = 33; duration = 160; break; + case GSM_TCHF_FRAME_EFR: + payload_type = RTP_PT_GSM_EFR; + payload_len = 31; + duration = 160; + break; default: DEBUGPC(DMUX, "unsupported message type %d\n", frame->msg_type); -- cgit v1.2.3 From 9f16c871060d0f607360d7d720c10325f9b99ce9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 00:04:57 +0100 Subject: handover: don't create negative lchan use counts trans_lchan_change() takes care of use counts for us. --- openbsc/src/handover_logic.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index f3f5d6c21..2c7549761 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -215,9 +215,6 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) /* do something to re-route the actual speech frames ! */ //tch_remap(ho->old_lchan, ho->new_lchan); - /* release old lchan */ - put_lchan(ho->old_lchan); - talloc_free(ho); return 0; -- cgit v1.2.3 From ea09002e73bf70ac9c88ab6046b17fdc2033b40a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 00:05:38 +0100 Subject: handover: no debug message for ever non-handover measurement report --- openbsc/src/handover_decision.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index 4c08c6664..736679ab1 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -88,10 +88,8 @@ static int process_meas_rep(struct gsm_meas_rep *mr) } } - if (!mr_cell) { - DEBUGPC(DHO, "No better cell\n"); + if (!mr_cell) return 0; - } LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better: ", mr_cell->arfcn); if (!mr->lchan->ts->trx->bts->network->handover.active) { -- cgit v1.2.3 From 5e68183a201ab92f29cd2467df5209f7b351a66d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 00:06:02 +0100 Subject: handover: disable default-printing of every measurement report --- openbsc/src/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 9c6cb4963..6e99d4144 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -28,7 +28,7 @@ #include -unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB); +unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB|DMEAS); struct debug_info { const char *name; -- cgit v1.2.3 From 0b7b61c6b79eb2e69a9418af611e67bdbc70b353 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 09:48:28 +0100 Subject: fix segfault in rrlp code in case of unsuccessful paging PAGING_COMPLETED can be signalled without an active lchan in case it was unable to page the repsective subscriber. --- openbsc/src/rrlp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c index 60ce750ad..d4665d570 100644 --- a/openbsc/src/rrlp.c +++ b/openbsc/src/rrlp.c @@ -90,6 +90,10 @@ static int paging_sig_cb(unsigned int subsys, unsigned int signal, switch (signal) { case S_PAGING_COMPLETED: + /* paging might have "completed' unsucessfully, + * in this case we don't have a lchan */ + if (!psig_data->lchan) + break; /* A subscriber has attached. */ send_rrlp_req(psig_data->lchan); break; -- cgit v1.2.3 From 31981a0051682c59fc5bcebfa1ac4e3086103b25 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 09:58:40 +0100 Subject: add FIXME to IMSI DETACH INDICATION: we need to release all transactions --- openbsc/src/gsm_04_08.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index f36723937..227131671 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1402,6 +1402,9 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) } else DEBUGP(DMM, "Unknown Subscriber ?!?\n"); + /* FIXME: iterate over all transactions and release them, + * imagine an IMSI DETACH happening during an active call! */ + /* subscriber is detached: should we release lchan? */ return 0; -- cgit v1.2.3 From 392736d38bf9dae29800bde630c9ceee8a3914f3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 13:16:14 +0100 Subject: RTP Proxy: Fix RTP sequence number and timestamp in case of dropped frames During handover, we will not send RTP frames for quite some time. However, the way the rtp_send code is structured, it will increment the timestamp with a fixed amount every time we send a frame, independent how much wallclock time has actually passed. This code is a hack to update the sequence number and timestamp in case it seems to be wrong. It makes handover much more reliable. --- openbsc/src/rtp_proxy.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index 551349750..02938125a 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -176,6 +176,21 @@ static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data) return 0; } +/* "to - from" */ +static void tv_difference(struct timeval *diff, const struct timeval *from, + const struct timeval *__to) +{ + struct timeval _to = *__to, *to = &_to; + + if (to->tv_usec < from->tv_usec) { + to->tv_sec -= 1; + to->tv_usec += 1000000; + } + + diff->tv_usec = to->tv_usec - from->tv_usec; + diff->tv_sec = to->tv_sec - from->tv_sec; +} + /* encode and send a rtp frame */ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) { @@ -211,6 +226,26 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) return -EINVAL; } + { + struct timeval tv, tv_diff; + long int usec_diff, frame_diff; + + gettimeofday(&tv, NULL); + tv_difference(&tv_diff, &rs->transmit.last_tv, &tv); + rs->transmit.last_tv = tv; + + usec_diff = tv_diff.tv_sec * 1000000 + tv_diff.tv_usec; + frame_diff = (usec_diff / 20000); + + if (abs(frame_diff) > 1) { + long int frame_diff_excess = frame_diff - 1; + + DEBUGP(DMUX, "Correcting frame difference of %ld frames\n", frame_diff_excess); + rs->transmit.sequence += frame_diff_excess; + rs->transmit.timestamp += frame_diff_excess * duration; + } + } + msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP-GSM-FULL"); if (!msg) return -ENOMEM; -- cgit v1.2.3 From f88c8a02fc35fbcc8b85e3b51733f1a20ceadf13 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 13:48:15 +0100 Subject: remove hand full of 'extern ipacc_rtp_direct' definitions and instead declare it in gsm_data.h --- openbsc/src/bsc_hack.c | 1 - openbsc/src/bsc_init.c | 1 - openbsc/src/gsm_04_08.c | 2 -- 3 files changed, 4 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index c0695ef35..a9a5d372f 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -41,7 +41,6 @@ struct gsm_network *bsc_gsmnet = 0; static const char *database_name = "hlr.sqlite3"; static const char *config_file = "openbsc.cfg"; -extern int ipacc_rtp_direct; extern int bsc_bootstrap_network(int (*mmc_rev)(struct gsm_network *, int, void *), const char *cfg_file); diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 7065833bf..8450af6d0 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -35,7 +35,6 @@ /* global pointer to the gsm network data structure */ extern struct gsm_network *bsc_gsmnet; -extern int ipacc_rtp_direct; static void patch_nm_tables(struct gsm_bts *bts); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 227131671..2985d385c 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -57,8 +57,6 @@ void *tall_locop_ctx; -extern int ipacc_rtp_direct; - static const struct tlv_definition rsl_att_tlvdef = { .def = { [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV }, -- cgit v1.2.3 From edbc0f7aea00a6441adc05e904fb2351c99ad7b5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 14:22:11 +0100 Subject: Introduce new MNCC based proxy mode Since the MNCC API can now send and receive frames to/from the MNCC application, we can also implement a proxy this way. Not at the RTP/UDP packet level, but at the 'TCH speech frame' level. Especially for handover, we need this mode as the receiver in the BTS needs a persistent SSRC and monotonic frame numbers / timestamps. --- openbsc/src/mncc.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 4 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index f53b15dcb..15e2978e6 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include void *tall_call_ctx; @@ -232,7 +234,8 @@ static int mncc_notify_ind(struct gsm_call *call, int msg_type, static int mncc_setup_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *connect) { - struct gsm_mncc connect_ack; + struct gsm_mncc connect_ack, frame_recv; + struct gsm_network *net = call->net; struct gsm_call *remote; u_int32_t refs[2]; @@ -253,7 +256,26 @@ static int mncc_setup_cnf(struct gsm_call *call, int msg_type, refs[0] = call->callref; refs[1] = call->remote_ref; DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref); - return mncc_send(call->net, MNCC_BRIDGE, refs); + + /* in direct mode, we always have to bridge the channels */ + if (ipacc_rtp_direct) + return mncc_send(call->net, MNCC_BRIDGE, refs); + + /* proxy mode */ + if (!net->handover.active) { + /* in the no-handover case, we can bridge, i.e. use + * the old RTP proxy code */ + return mncc_send(call->net, MNCC_BRIDGE, refs); + } else { + /* in case of handover, we need to re-write the RTP + * SSRC, sequence and timestamp values and thus + * need to enable RTP receive for both directions */ + memset(&frame_recv, 0, sizeof(struct gsm_mncc)); + frame_recv.callref = call->callref; + mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv); + frame_recv.callref = call->remote_ref; + return mncc_send(call->net, MNCC_FRAME_RECV, &frame_recv); + } } static int mncc_disc_ind(struct gsm_call *call, int msg_type, @@ -301,6 +323,28 @@ static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *re return 0; } +/* receiving a TCH/F frame from the BSC code */ +static int mncc_rcv_tchf(struct gsm_call *call, int msg_type, + struct gsm_data_frame *dfr) +{ + struct gsm_trans *remote_trans; + + remote_trans = trans_find_by_callref(call->net, call->remote_ref); + + /* this shouldn't really happen */ + if (!remote_trans || !remote_trans->lchan) { + LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n"); + return -EIO; + } + + /* RTP socket of remote end has meanwhile died */ + if (!remote_trans->lchan->abis_ip.rtp_socket) + return -EIO; + + return rtp_send_frame(remote_trans->lchan->abis_ip.rtp_socket, dfr); +} + + int mncc_recv(struct gsm_network *net, int msg_type, void *arg) { struct gsm_mncc *data = arg; @@ -342,8 +386,15 @@ int mncc_recv(struct gsm_network *net, int msg_type, void *arg) DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref); } - DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref, - get_mncc_name(msg_type)); + switch (msg_type) { + case GSM_TCHF_FRAME: + case GSM_TCHF_FRAME_EFR: + break; + default: + DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref, + get_mncc_name(msg_type)); + break; + } switch(msg_type) { case MNCC_SETUP_IND: @@ -404,6 +455,10 @@ int mncc_recv(struct gsm_network *net, int msg_type, void *arg) call->callref, data->cause.value); rc = mncc_send(net, MNCC_RETRIEVE_REJ, data); break; + case GSM_TCHF_FRAME: + case GSM_TCHF_FRAME_EFR: + rc = mncc_rcv_tchf(call, msg_type, arg); + break; default: LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref); break; -- cgit v1.2.3 From fe03f0d002b146370542f9d59a344dd0c3bcf78d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 13:51:01 +0100 Subject: don't enable handover unless RTP Proxy is enabled We cannot support in-call handover of calls without a RTP proxy, since at the time of the handover the SSRC, sequence number and timestamp of the RTP frames change. --- openbsc/src/vty_interface.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 20df9091d..82fd00472 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -870,6 +870,12 @@ DEFUN(cfg_net_handover, cfg_net_handover_cmd, "handover (0|1)", "Whether or not to use in-call handover") { + if (ipacc_rtp_direct) { + vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode " + "is enabled by using the -P command line option%s", + VTY_NEWLINE); + return CMD_WARNING; + } gsmnet->handover.active = atoi(argv[0]); return CMD_SUCCESS; -- cgit v1.2.3 From 17f5bf64f1ac514a90324cb9506f674c5833a974 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 15:42:44 +0100 Subject: Move RTP socket handling out of signal handlers into abis_rsl This is not really nice, but we will soon have multiple users of the CRCX / MDCX / DLCX signals, and we cannot guarantee the ordering of them. So as a workaround, we move the RTP socket creation and deletion into the core abis_rsl codebase. --- openbsc/src/abis_rsl.c | 33 +++++++++++++++++++++++++++++++++ openbsc/src/gsm_04_08.c | 26 -------------------------- 2 files changed, 33 insertions(+), 26 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 2d55806a1..05735ee5a 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -39,6 +39,7 @@ #include #include #include +#include #define RSL_ALLOC_SIZE 1024 #define RSL_ALLOC_HEADROOM 128 @@ -1649,10 +1650,35 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) LOGP(DRSL, LOGL_NOTICE, "mandatory IE missing"); return -EINVAL; } + ipac_parse_rtp(lchan, &tv); + + /* in case we don't use direct BTS-to-BTS RTP */ + if (!ipacc_rtp_direct) { + int rc; + /* the BTS has successfully bound a TCH to a local ip/port, + * which means we can connect our UDP socket to it */ + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; + } + + lchan->abis_ip.rtp_socket = rtp_socket_create(); + if (!lchan->abis_ip.rtp_socket) + goto out_err; + + rc = rtp_socket_connect(lchan->abis_ip.rtp_socket, + lchan->abis_ip.bound_ip, + lchan->abis_ip.bound_port); + if (rc < 0) + goto out_err; + } + dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); return 0; +out_err: + return -EIO; } static int abis_rsl_rx_ipacc_mdcx_ack(struct msgb *msg) @@ -1676,6 +1702,7 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; + struct gsm_lchan *lchan = msg->lchan; rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1683,6 +1710,12 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tv, RSL_IE_CAUSE), TLVP_LEN(&tv, RSL_IE_CAUSE)); + /* the BTS tells us a RTP stream has been disconnected */ + if (lchan->abis_ip.rtp_socket) { + rtp_socket_free(lchan->abis_ip.rtp_socket); + lchan->abis_ip.rtp_socket = NULL; + } + dispatch_signal(SS_ABISIP, S_ABISIP_DLCX_IND, msg->lchan); return 0; diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 2985d385c..2dad42083 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1885,22 +1885,6 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, switch (signal) { case S_ABISIP_CRCX_ACK: - /* the BTS has successfully bound a TCH to a local ip/port, - * which means we can connect our UDP socket to it */ - if (lchan->abis_ip.rtp_socket) { - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } - - lchan->abis_ip.rtp_socket = rtp_socket_create(); - if (!lchan->abis_ip.rtp_socket) - goto out_err; - - rc = rtp_socket_connect(lchan->abis_ip.rtp_socket, - lchan->abis_ip.bound_ip, - lchan->abis_ip.bound_port); - if (rc < 0) - goto out_err; /* check if any transactions on this lchan still have * a tch_recv_mncc request pending */ net = lchan->ts->trx->bts->network; @@ -1911,18 +1895,8 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, } } break; - case S_ABISIP_DLCX_IND: - /* the BTS tells us a RTP stream has been disconnected */ - if (lchan->abis_ip.rtp_socket) { - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } - break; } - return 0; -out_err: - /* FIXME: do something */ return 0; } -- cgit v1.2.3 From a72273e176cf19a4d1352736a71698445d79b8fd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 16:51:09 +0100 Subject: rename ipacc_connect_proxy_bind() to rsl_ipacc_mdcx_to_rtpsock() Our RTP sockets are no longer just for the proxy mode, so having "proxy" in the function name is really misleading. --- openbsc/src/abis_rsl.c | 14 ++++++++++++++ openbsc/src/gsm_04_08.c | 20 +++----------------- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 05735ee5a..a50d7aa1c 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1615,6 +1615,20 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, return abis_rsl_sendmsg(msg); } +/* tell BTS to connect RTP stream to our local RTP socket */ +int rsl_ipacc_mdcx_to_rtpsock(struct gsm_lchan *lchan) +{ + struct rtp_socket *rs = lchan->abis_ip.rtp_socket; + int rc; + + rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), + ntohs(rs->rtp.sin_local.sin_port), + /* FIXME: use RTP payload of bound socket, not BTS*/ + lchan->abis_ip.rtp_payload2); + + return rc; +} + int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan) { struct msgb *msg = rsl_msgb_alloc(); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 2dad42083..281982e22 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1900,20 +1900,6 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, return 0; } -/* bind rtp proxy to local IP/port and tell BTS to connect to it */ -static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan) -{ - struct rtp_socket *rs = lchan->abis_ip.rtp_socket; - int rc; - - rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), - ntohs(rs->rtp.sin_local.sin_port), - /* FIXME: use RTP payload of bound socket, not BTS*/ - lchan->abis_ip.rtp_payload2); - - return rc; -} - /* map two ipaccess RTP streams onto each other */ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) { @@ -1935,10 +1921,10 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) case GSM_BTS_TYPE_NANOBTS: if (!ipacc_rtp_direct) { /* connect the TCH's to our RTP proxy */ - rc = ipacc_connect_proxy_bind(lchan); + rc = rsl_ipacc_mdcx_to_rtpsock(lchan); if (rc < 0) return rc; - rc = ipacc_connect_proxy_bind(remote_lchan); + rc = rsl_ipacc_mdcx_to_rtpsock(remote_lchan); #warning do we need a check of rc here? /* connect them with each other */ @@ -2015,7 +2001,7 @@ static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable) } if (enable) { /* connect the TCH's to our RTP proxy */ - rc = ipacc_connect_proxy_bind(lchan); + rc = rsl_ipacc_mdcx_to_rtpsock(lchan); if (rc < 0) return rc; /* assign socket to application interface */ -- cgit v1.2.3 From a03790232316edfc87de94012b110d8d8e2067f2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 17:04:40 +0100 Subject: [handover] implement TCH RTP stream handover This patch takes care of handling the RTP streams / sockets during an in-call handover from one BTS to another BTS. It only works in combination with rtp_proxy mode. --- openbsc/src/handover_logic.c | 70 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 2c7549761..3007d2581 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -40,6 +40,7 @@ #include #include #include +#include struct bsc_handover { struct llist_head list; @@ -173,6 +174,10 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) ho->T3103.data = ho; bsc_schedule_timer(&ho->T3103, 10, 0); + /* create a RTP connection */ + if (is_ipaccess_bts(new_lchan->ts->trx->bts)) + rsl_ipacc_crcx(new_lchan); + return 0; } @@ -213,7 +218,6 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) trans_lchan_change(ho->old_lchan, new_lchan); /* do something to re-route the actual speech frames ! */ - //tch_remap(ho->old_lchan, ho->new_lchan); talloc_free(ho); @@ -255,6 +259,61 @@ static int ho_rsl_detect(struct gsm_lchan *new_lchan) return 0; } +static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + struct rtp_socket *old_rs, *new_rs, *other_rs; + + ho = bsc_ho_by_new_lchan(new_lchan); + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); + return -ENODEV; + } + + if (ipacc_rtp_direct) { + LOGP(DHO, LOGL_ERROR, "unable to handover in direct RTP mode\n"); + return 0; + } + + /* RTP Proxy mode */ + new_rs = new_lchan->abis_ip.rtp_socket; + old_rs = ho->old_lchan->abis_ip.rtp_socket; + + if (!new_rs) { + LOGP(DHO, LOGL_ERROR, "no RTP socket for new_lchan\n"); + return -EIO; + } + + rsl_ipacc_mdcx_to_rtpsock(new_lchan); + + if (!old_rs) { + LOGP(DHO, LOGL_ERROR, "no RTP socekt for old_lchan\n"); + return -EIO; + } + + /* copy rx_action and reference to other sock */ + new_rs->rx_action = old_rs->rx_action; + new_rs->tx_action = old_rs->tx_action; + new_rs->transmit = old_rs->transmit; + + switch (ho->old_lchan->abis_ip.rtp_socket->rx_action) { + case RTP_PROXY: + other_rs = old_rs->proxy.other_sock; + rtp_socket_proxy(new_rs, other_rs); + /* delete reference to other end socket to prevent + * rtp_socket_free() from removing the inverse reference */ + old_rs->proxy.other_sock = NULL; + break; + case RTP_RECV_UPSTREAM: + new_rs->receive = old_rs->receive; + break; + case RTP_NONE: + break; + } + + return 0; +} + static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { @@ -276,6 +335,14 @@ static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, return ho_gsm48_ho_fail(lchan); } break; + case SS_ABISIP: + lchan = signal_data; + switch (signal) { + case S_ABISIP_CRCX_ACK: + return ho_ipac_crcx_ack(lchan); + break; + } + break; default: break; } @@ -286,4 +353,5 @@ static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, static __attribute__((constructor)) void on_dso_load_ho_logic(void) { register_signal_handler(SS_LCHAN, ho_logic_sig_cb, NULL); + register_signal_handler(SS_ABISIP, ho_logic_sig_cb, NULL); } -- cgit v1.2.3 From 9fb1f1065a8dc5b0fd2cbaad9d438d57f1dd7ac2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 17:07:23 +0100 Subject: fix compiler warning and coding style in rtp_proxy --- openbsc/src/rtp_proxy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index 02938125a..0f4e32799 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -666,9 +666,10 @@ int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other) } /* bind RTP/RTCP socket to application */ -int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, u_int32_t callref) +int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, + u_int32_t callref) { - DEBUGP(DMUX, "rtp_socket_proxy(this=%p, callref=%lu)\n", + DEBUGP(DMUX, "rtp_socket_proxy(this=%p, callref=%u)\n", this, callref); if (callref) { -- cgit v1.2.3 From a4e2d04b35095d059218ab05ffcd5b69e18edf70 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 20 Dec 2009 17:08:22 +0100 Subject: Fix some compiler warnings regarding missing const in rest_octets.c --- openbsc/src/rest_octets.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c index 6efd47515..6226203ec 100644 --- a/openbsc/src/rest_octets.c +++ b/openbsc/src/rest_octets.c @@ -291,7 +291,8 @@ static int encode_drx_timer(unsigned int drx) ** ; */ -static int append_gprs_cell_opt(struct bitvec *bv, struct gprs_cell_options *gco) +static int append_gprs_cell_opt(struct bitvec *bv, + const struct gprs_cell_options *gco) { int t3192, drx_timer_max; @@ -323,7 +324,7 @@ static int append_gprs_cell_opt(struct bitvec *bv, struct gprs_cell_options *gco } static void append_gprs_pwr_ctrl_pars(struct bitvec *bv, - struct gprs_power_ctrl_pars *pcp) + const struct gprs_power_ctrl_pars *pcp) { bitvec_set_uint(bv, pcp->alpha, 4); bitvec_set_uint(bv, pcp->t_avg_w, 5); -- cgit v1.2.3 From d5778fc4c7497e1b7310811c881f8cb21b742ec8 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut <246tnt@gmail.com> Date: Mon, 21 Dec 2009 01:09:57 +0100 Subject: [db] Fix queries for unsent SMS - Need to use sms.id for the ORDER BY since 'subscriber' also has 'id' - Need to add the join clause between 'SMS' and 'subscriber' - Add a LIMIT 1 (probably no impact for the db size we're dealing with here, but with large DB and mysql/postgresql this can help the planner) - (fix a wrong comment in passing ...) Signed-off-by: Sylvain Munaut --- openbsc/src/db.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 5dfefb53f..d85386548 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -769,8 +769,9 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id) result = dbi_conn_queryf(conn, "SELECT * FROM SMS,Subscriber " "WHERE sms.id >= %llu AND sms.sent is NULL " + "AND sms.receiver_id = subscriber.id " "AND subscriber.lac > 0 " - "ORDER BY id", + "ORDER BY sms.id LIMIT 1", min_id); if (!result) return NULL; @@ -787,7 +788,7 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id) return sms; } -/* retrieve the next unsent SMS with ID >= min_id */ +/* retrieve the next unsent SMS for a given subscriber */ struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr) { dbi_result result; @@ -796,8 +797,9 @@ struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr) result = dbi_conn_queryf(conn, "SELECT * FROM SMS,Subscriber " "WHERE sms.receiver_id = %llu AND sms.sent is NULL " + "AND sms.receiver_id = subscriber.id " "AND subscriber.lac > 0 " - "ORDER BY id", + "ORDER BY sms.id LIMIT 1", subscr->id); if (!result) return NULL; -- cgit v1.2.3 From f77af1fb302ba624bf401c56104a16d79e221916 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut <246tnt@gmail.com> Date: Mon, 21 Dec 2009 01:11:25 +0100 Subject: chan_alloc: Delete T3101 on lchan_free as well If a RF channel is assigned but no response is ever heard from the phone, we will receive a CONNECTION FAIL from the BTS, triggering a RF release freeing the channel. Then sometime later, T3101 will expire as well and free the channel again ... Signed-off-by: Sylvain Munaut --- openbsc/src/chan_alloc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc/src') diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 786e8b11b..a23192ae6 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -251,6 +251,7 @@ void lchan_free(struct gsm_lchan *lchan) /* stop the timer */ bsc_del_timer(&lchan->release_timer); + bsc_del_timer(&lchan->T3101); /* clear cached measuement reports */ lchan->meas_rep_idx = 0; -- cgit v1.2.3 From 56315f02bb88f0595d369c2d80f6556922758f62 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 21 Dec 2009 01:18:44 +0100 Subject: Fix typo s/memcpy/memcmp in trau_frame.c --- openbsc/src/trau_mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/trau_mux.c b/openbsc/src/trau_mux.c index 477ea21e5..9930751a5 100644 --- a/openbsc/src/trau_mux.c +++ b/openbsc/src/trau_mux.c @@ -185,7 +185,7 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, return -EINVAL; if (!ue->callref) return -EINVAL; - if (memcpy(tf.c_bits, c_bits_check, sizeof(c_bits_check))) + if (memcmp(tf.c_bits, c_bits_check, sizeof(c_bits_check))) DEBUGPC(DMUX, "illegal trau (C1-C5) %s\n", hexdump(tf.c_bits, sizeof(c_bits_check))); msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33, -- cgit v1.2.3 From 38fe2a67e1a376e4370ddfed2f75687075cc9e6b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 09:26:17 +0100 Subject: meas_rep: utility function for processing of measurement reports This provides two functions: get_meas_rep_avg() to obtain the sliding window average of one particular field, and meas_rep_n_out_of_m_be() to check if at least N out of M measurments are >= BE. --- openbsc/src/Makefile.am | 2 +- openbsc/src/meas_rep.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 openbsc/src/meas_rep.c (limited to 'openbsc/src') diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 5692ac4e4..f36a701bc 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -12,7 +12,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \ - handover_decision.c + handover_decision.c meas_rep.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ diff --git a/openbsc/src/meas_rep.c b/openbsc/src/meas_rep.c new file mode 100644 index 000000000..4b9cc1a0c --- /dev/null +++ b/openbsc/src/meas_rep.c @@ -0,0 +1,114 @@ +/* Measurement Report Processing */ + +/* (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 General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include + +#include +#include + +static int get_field(const struct gsm_meas_rep *rep, + enum meas_rep_field field) +{ + switch (field) { + case MEAS_REP_DL_RXLEV_FULL: + return rep->dl.full.rx_lev; + case MEAS_REP_DL_RXLEV_SUB: + return rep->dl.sub.rx_lev; + case MEAS_REP_DL_RXQUAL_FULL: + return rep->dl.full.rx_qual; + case MEAS_REP_DL_RXQUAL_SUB: + return rep->dl.sub.rx_qual; + case MEAS_REP_UL_RXLEV_FULL: + return rep->ul.full.rx_lev; + case MEAS_REP_UL_RXLEV_SUB: + return rep->ul.sub.rx_lev; + case MEAS_REP_UL_RXQUAL_FULL: + return rep->ul.full.rx_qual; + case MEAS_REP_UL_RXQUAL_SUB: + return rep->ul.sub.rx_qual; + } + + return 0; +} + + +unsigned int calc_initial_idx(unsigned int array_size, + unsigned int meas_rep_idx, + unsigned int num_values) +{ + int offs, idx; + + /* from which element do we need to start if we're interested + * in an average of 'num' elements */ + offs = meas_rep_idx - num_values; + + if (offs < 0) + idx = array_size + offs; + else + idx = offs; + + return idx; +} + +/* obtain an average over the last 'num' fields in the meas reps */ +int get_meas_rep_avg(const struct gsm_lchan *lchan, + enum meas_rep_field field, unsigned int num) +{ + unsigned int i, idx; + int avg = 0; + + idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), + lchan->meas_rep_idx, num); + + for (i = 0; i < num; i++) { + int j = (idx+i) % ARRAY_SIZE(lchan->meas_rep); + + avg += get_field(&lchan->meas_rep[j], field); + } + + return avg / num; +} + +/* Check if N out of M last values for FIELD are >= bd */ +int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan, + enum meas_rep_field field, + unsigned int n, unsigned int m, int be) +{ + unsigned int i, idx; + int count = 0; + + idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), + lchan->meas_rep_idx, m); + + for (i = 0; i < m; i++) { + int j = (idx + i) % ARRAY_SIZE(lchan->meas_rep); + int val = get_field(&lchan->meas_rep[j], field); + + if (val >= be) + count++; + + if (count >= n) + return 1; + } + + return 0; +} -- cgit v1.2.3 From b8bfc567b7b8c705c1a2ec7654ce7184ab6c295f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 13:27:11 +0100 Subject: RSL: keep track if a channel is active or not This allows us to block packets that we have received after the channel is no longer being used. This is visible during handover, where we still receive a measurement report after the MS has switched to the new channel. This leftover measurement report then attempts to trigger another handover, which si bogus and will fail - and thus only consumes resources. With the new LCHAN_S_ACTIVE state, we can check for this when processing the measurement report. --- openbsc/src/abis_rsl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index a50d7aa1c..72ae9dbb6 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -918,6 +918,8 @@ static int rsl_rx_chan_act_ack(struct msgb *msg) if (rslh->ie_chan != RSL_IE_CHAN_NR) return -EINVAL; + msg->lchan->state = LCHAN_S_ACTIVE; + dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan); return 0; @@ -938,6 +940,8 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), TLVP_LEN(&tp, RSL_IE_CAUSE)); + msg->lchan->state = LCHAN_S_NONE; + dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan); lchan_free(msg->lchan); @@ -1022,6 +1026,11 @@ static int rsl_rx_meas_res(struct msgb *msg) const u_int8_t *val; int rc; + /* check if this channel is actually active */ + /* FIXME: maybe this check should be way more generic/centralized */ + if (msg->lchan->state != LCHAN_S_ACTIVE) + return 0; + memset(mr, 0, sizeof(*mr)); mr->lchan = msg->lchan; @@ -1128,6 +1137,7 @@ static int abis_rsl_rx_dchan(struct msgb *msg) break; case RSL_MT_RF_CHAN_REL_ACK: DEBUGPC(DRSL, "RF CHANNEL RELEASE ACK\n"); + msg->lchan->state = LCHAN_S_NONE; lchan_free(msg->lchan); break; case RSL_MT_MODE_MODIFY_ACK: -- cgit v1.2.3 From ade773f44193052ade3be70b794130dd6a39ee06 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 13:29:19 +0100 Subject: handover: set old channel to INACTIVE state After receiving the HANDOVER COMPLETE on the new channel, we mark the old channel as INACTIVE and try to release it ASAP. --- openbsc/src/handover_logic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 3007d2581..94d3d0d1e 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -212,13 +212,16 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) } bsc_del_timer(&ho->T3103); - llist_del(&ho->list); /* update lchan pointer of transaction */ trans_lchan_change(ho->old_lchan, new_lchan); + ho->old_lchan->state = LCHAN_S_INACTIVE; + lchan_auto_release(ho->old_lchan); + /* do something to re-route the actual speech frames ! */ + llist_del(&ho->list); talloc_free(ho); return 0; -- cgit v1.2.3 From f7c28b099f928cc6fb48fc9cc072656d8c3bb902 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 13:30:17 +0100 Subject: [handover] Real handover algorithm This implements the handover algorithm (and associated parameters) as described in Chapter 8 of the book "Performance Enhancements in a Frequency |Hopping GSM Network" by Thomas Toftegard Nielsen and Jeroen Wigard. The parameters such as averaging windows are configured in struct gsm_network. We keep some state to trakc up to 10 neighbors as they are being reported from the MS. This has so far only been tested in a network with two BTS that have each other as neighbor. Networks with morge neighbors might encounter bugs. --- openbsc/src/chan_alloc.c | 2 + openbsc/src/gsm_04_08.c | 1 + openbsc/src/gsm_data.c | 8 ++ openbsc/src/handover_decision.c | 227 +++++++++++++++++++++++++++++++++++----- 4 files changed, 211 insertions(+), 27 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index a23192ae6..c42b60b46 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -259,6 +259,8 @@ void lchan_free(struct gsm_lchan *lchan) lchan->meas_rep[i].flags = 0; lchan->meas_rep[i].nr = 0; } + for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++) + lchan->neigh_meas[i].arfcn = 0; /* FIXME: ts_free() the timeslot, if we're the last logical * channel using it */ diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 281982e22..156927f56 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1404,6 +1404,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) * imagine an IMSI DETACH happening during an active call! */ /* subscriber is detached: should we release lchan? */ + lchan_auto_release(msg->lchan); return 0; } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 94ed91ba5..12f439be2 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -210,6 +210,14 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c net->T3113 = GSM_T3113_DEFAULT; /* FIXME: initialize all other timers! */ + /* default set of handover parameters */ + net->handover.win_rxlev_avg = 10; + net->handover.win_rxqual_avg = 1; + net->handover.win_rxlev_avg_neigh = 10; + net->handover.pwr_interval = 6; + net->handover.pwr_hysteresis = 3; + net->handover.max_distance = 9999; + INIT_LLIST_HEAD(&net->trans_list); INIT_LLIST_HEAD(&net->upqueue); INIT_LLIST_HEAD(&net->bts_list); diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c index 736679ab1..b37cecddb 100644 --- a/openbsc/src/handover_decision.c +++ b/openbsc/src/handover_decision.c @@ -32,7 +32,9 @@ #include #include #include +#include +/* issue handover to a cell identified by ARFCN and BSIC */ static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, u_int16_t arfcn, u_int8_t bsic) { @@ -50,55 +52,226 @@ static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, return bsc_handover_start(lchan, new_bts); } -#define RXLEV_HYST 3 - -/* process an already parsed measurement report */ -static int process_meas_rep(struct gsm_meas_rep *mr) +/* did we get a RXLEV for a given cell in the given report? */ +static int rxlev_for_cell_in_rep(struct gsm_meas_rep *mr, + u_int16_t arfcn, u_int8_t bsic) { - struct gsm_meas_rep_cell *mr_cell = NULL; - unsigned int best_better_db; int i; - /* we currently only do handover for TCH channels */ - switch (mr->lchan->type) { - case GSM_LCHAN_TCH_F: - case GSM_LCHAN_TCH_H: - break; - default: - return 0; + for (i = 0; i < mr->num_cell; i++) { + struct gsm_meas_rep_cell *mrc = &mr->cell[i]; + + /* search for matching report */ + if (!(mrc->arfcn == arfcn && mrc->bsic == bsic)) + continue; + + mrc->flags |= MRC_F_PROCESSED; + return mrc->rxlev; } + return -ENODEV; +} - /* FIXME: implement actual averaging over multiple measurement - * reports */ +/* obtain averaged rxlev for given neighbor */ +static int neigh_meas_avg(struct neigh_meas_proc *nmp, int window) +{ + unsigned int i, idx; + int avg = 0; - if (mr->num_cell > 6) - return 0; + idx = calc_initial_idx(ARRAY_SIZE(nmp->rxlev), + nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev), + window); + + for (i = 0; i < window; i++) { + int j = (idx+i) % ARRAY_SIZE(nmp->rxlev); + + avg += nmp->rxlev[j]; + } + + return avg / window; +} + +/* find empty or evict bad neighbor */ +static struct neigh_meas_proc *find_evict_neigh(struct gsm_lchan *lchan) +{ + int j, worst = 999999; + struct neigh_meas_proc *nmp_worst; + + /* first try to find an empty/unused slot */ + for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) { + struct neigh_meas_proc *nmp = &lchan->neigh_meas[j]; + if (!nmp->arfcn) + return nmp; + } + + /* no empty slot found. evict worst neighbor from list */ + for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) { + struct neigh_meas_proc *nmp = &lchan->neigh_meas[j]; + int avg = neigh_meas_avg(nmp, MAX_WIN_NEIGH_AVG); + if (avg < worst) { + worst = avg; + nmp_worst = nmp; + } + } + + return nmp_worst; +} + +/* process neighbor cell measurement reports */ +static void process_meas_neigh(struct gsm_meas_rep *mr) +{ + int i, j, idx; + + /* for each reported cell, try to update global state */ + for (j = 0; j < ARRAY_SIZE(mr->lchan->neigh_meas); j++) { + struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[j]; + unsigned int idx; + int rxlev; + + /* skip unused entries */ + if (!nmp->arfcn) + continue; + + rxlev = rxlev_for_cell_in_rep(mr, nmp->arfcn, nmp->bsic); + idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev); + if (rxlev >= 0) { + nmp->rxlev[idx] = rxlev; + nmp->last_seen_nr = mr->nr; + } else + nmp->rxlev[idx] = 0; + nmp->rxlev_cnt++; + } + + /* iterate over list of reported cells, check if we did not + * process all of them */ + for (i = 0; i < mr->num_cell; i++) { + struct gsm_meas_rep_cell *mrc = &mr->cell[i]; + struct neigh_meas_proc *nmp; + + if (mrc->flags & MRC_F_PROCESSED) + continue; + + nmp = find_evict_neigh(mr->lchan); + + nmp->arfcn = mrc->arfcn; + nmp->bsic = mrc->bsic; + + idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev); + nmp->rxlev[idx] = mrc->rxlev; + nmp->rxlev_cnt++; + nmp->last_seen_nr = mr->nr; + + mrc->flags |= MRC_F_PROCESSED; + } +} + +/* attempt to do a handover */ +static int attempt_handover(struct gsm_meas_rep *mr) +{ + struct gsm_network *net = mr->lchan->ts->trx->bts->network; + struct neigh_meas_proc *best_cell = NULL; + unsigned int best_better_db = 0; + int i, rc; /* find the best cell in this report that is at least RXLEV_HYST * better than the current serving cell */ - for (i = 0; i < mr->num_cell; i++) { - unsigned int better; - if (mr->cell[i].rxlev < mr->dl.full.rx_lev + RXLEV_HYST) + + for (i = 0; i < ARRAY_SIZE(mr->lchan->neigh_meas); i++) { + struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[i]; + int avg, better; + + /* skip empty slots */ + if (nmp->arfcn == 0) continue; - better = mr->cell[i].rxlev - mr->dl.full.rx_lev; + /* caculate average rxlev for this cell over the window */ + avg = neigh_meas_avg(nmp, net->handover.win_rxlev_avg_neigh); + + /* check if hysteresis is fulfilled */ + if (avg < mr->dl.full.rx_lev + net->handover.pwr_hysteresis) + continue; + + better = avg - mr->dl.full.rx_lev; if (better > best_better_db) { - mr_cell = &mr->cell[i]; + best_cell = nmp; best_better_db = better; } } - if (!mr_cell) + if (!best_cell) return 0; - LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better: ", mr_cell->arfcn); - if (!mr->lchan->ts->trx->bts->network->handover.active) { + LOGP(DHO, LOGL_INFO, "%s: Cell on ARFCN %u is better: ", + gsm_ts_name(mr->lchan->ts), best_cell->arfcn); + if (!net->handover.active) { LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n"); return 0; } - LOGPC(DHO, LOGL_INFO, "Starting handover\n"); - return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, mr_cell->bsic); + rc = handover_to_arfcn_bsic(mr->lchan, best_cell->arfcn, best_cell->bsic); + switch (rc) { + case 0: + LOGPC(DHO, LOGL_INFO, "Starting handover\n"); + break; + case -ENOSPC: + LOGPC(DHO, LOGL_INFO, "No channel available\n"); + break; + case -EBUSY: + LOGPC(DHO, LOGL_INFO, "Handover already active\n"); + break; + default: + LOGPC(DHO, LOGL_ERROR, "Unknown error\n"); + } + return rc; +} + +/* process an already parsed measurement report and decide if we want to + * attempt a handover */ +static int process_meas_rep(struct gsm_meas_rep *mr) +{ + struct gsm_network *net = mr->lchan->ts->trx->bts->network; + int av_rxlev; + + /* we currently only do handover for TCH channels */ + switch (mr->lchan->type) { + case GSM_LCHAN_TCH_F: + case GSM_LCHAN_TCH_H: + break; + default: + return 0; + } + + /* parse actual neighbor cell info */ + if (mr->num_cell > 0 && mr->num_cell < 7) + process_meas_neigh(mr); + + av_rxlev = get_meas_rep_avg(mr->lchan, MEAS_REP_DL_RXLEV_FULL, + net->handover.win_rxlev_avg); + + /* Interference HO */ + if (rxlev2dbm(av_rxlev) > -85 && + meas_rep_n_out_of_m_be(mr->lchan, MEAS_REP_DL_RXQUAL_FULL, + 3, 4, 5)) + return attempt_handover(mr); + + /* Bad Quality */ + if (meas_rep_n_out_of_m_be(mr->lchan, MEAS_REP_DL_RXQUAL_FULL, + 3, 4, 5)) + return attempt_handover(mr); + + /* Low Level */ + if (rxlev2dbm(av_rxlev) <= -110) + return attempt_handover(mr); + + /* Distance */ + if (mr->ms_l1.ta > net->handover.max_distance) + return attempt_handover(mr); + + /* Power Budget AKA Better Cell */ + if ((mr->nr % net->handover.pwr_interval) == 0) + return attempt_handover(mr); + + return 0; + } static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal, -- cgit v1.2.3 From b720bd3678b461b1973d194ba51f4c824dc4c98c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 16:51:50 +0100 Subject: make handover algorithm parameters configurable from VTY --- openbsc/src/vty_interface.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 82fd00472..0e518efd4 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -299,6 +299,18 @@ static int config_write_net(struct vty *vty) VTY_NEWLINE); vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE); vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE); + vty_out(vty, " handover window rxlev averaging %u%s", + gsmnet->handover.win_rxlev_avg, VTY_NEWLINE); + vty_out(vty, " handover window rxqual averaging %u%s", + gsmnet->handover.win_rxqual_avg, VTY_NEWLINE); + vty_out(vty, " handover window rxlev neighbor averaging %u%s", + gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE); + vty_out(vty, " handover power budget interval %u%s", + gsmnet->handover.pwr_interval, VTY_NEWLINE); + vty_out(vty, " handover power budget hysteresis %u%s", + gsmnet->handover.pwr_hysteresis, VTY_NEWLINE); + vty_out(vty, " handover maximum distance %u%s", + gsmnet->handover.max_distance, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); @@ -881,6 +893,53 @@ DEFUN(cfg_net_handover, cfg_net_handover_cmd, return CMD_SUCCESS; } +DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd, + "handover window rxlev averaging <1-10>", + "How many RxLev measurements are used for averaging") +{ + gsmnet->handover.win_rxlev_avg = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd, + "handover window rxqual averaging <1-10>", + "How many RxQual measurements are used for averaging") +{ + gsmnet->handover.win_rxqual_avg = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd, + "handover window rxlev neighbor averaging <1-10>", + "How many RxQual measurements are used for averaging") +{ + gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd, + "handover power budget interval <1-99>", + "How often to check if we have a better cell (SACCH frames)") +{ + gsmnet->handover.pwr_interval = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd, + "handover power budget hysteresis <0-999>", + "How many dB does a neighbor to be stronger to become a HO candidate") +{ + gsmnet->handover.pwr_hysteresis = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd, + "handover maximum distance <0-9999>", + "How big is the maximum timing advance before HO is forced") +{ + gsmnet->handover.max_distance = atoi(argv[0]); + return CMD_SUCCESS; +} #define DECLARE_TIMER(number) \ DEFUN(cfg_net_T##number, \ @@ -1391,6 +1450,12 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd); install_element(GSMNET_NODE, &cfg_net_mm_info_cmd); install_element(GSMNET_NODE, &cfg_net_handover_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd); + install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd); -- cgit v1.2.3 From 17c24c905785f967161dacde8b849c5b1ad275c4 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 21 Dec 2009 16:56:28 +0100 Subject: [abis] Properly compare obj_inst->trx_nr to bts->num_trx * Use >= in this case as we start counting the trx from 0 * This is fixing a problem with multi trx config --- openbsc/src/abis_nm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index e7e3bf004..fc00ca8d6 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -635,7 +635,7 @@ objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class, nm_state = &trx->bb_transc.nm_state; break; case NM_OC_CHANNEL: - if (obj_inst->trx_nr > bts->num_trx) { + if (obj_inst->trx_nr >= bts->num_trx) { DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; } @@ -719,7 +719,7 @@ objclass2obj(struct gsm_bts *bts, u_int8_t obj_class, obj = &trx->bb_transc; break; case NM_OC_CHANNEL: - if (obj_inst->trx_nr > bts->num_trx) { + if (obj_inst->trx_nr >= bts->num_trx) { DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; } -- cgit v1.2.3 From 306b7219ac616980b99a78f45b181aa980672d86 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 21 Dec 2009 17:06:07 +0100 Subject: [abis] Do not access an array with N elements at index N Possible crash fixes by preventing accessing the array out of bounds. --- openbsc/src/abis_nm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index fc00ca8d6..bb7248be7 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -671,7 +671,7 @@ objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class, nm_state = &bts->bs11.rack.nm_state; break; case NM_OC_BS11_ENVABTSE: - if (obj_inst->trx_nr > ARRAY_SIZE(bts->bs11.envabtse)) + if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse)) return NULL; nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state; break; @@ -682,7 +682,7 @@ objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class, nm_state = &bts->gprs.cell.nm_state; break; case NM_OC_GPRS_NSVC: - if (obj_inst->trx_nr > ARRAY_SIZE(bts->gprs.nsvc)) + if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc)) return NULL; nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state; break; @@ -738,7 +738,7 @@ objclass2obj(struct gsm_bts *bts, u_int8_t obj_class, obj = &bts->gprs.cell; break; case NM_OC_GPRS_NSVC: - if (obj_inst->trx_nr > ARRAY_SIZE(bts->gprs.nsvc)) + if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc)) return NULL; obj = &bts->gprs.nsvc[obj_inst->trx_nr]; break; -- cgit v1.2.3 From 6a22c0135a6ac49d716d38a92c9d9c9a329da980 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 17:02:32 +0100 Subject: [gprs] SI 13 should only be generated on C0 (BCCH-carrying TRX) --- openbsc/src/bsc_init.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 8450af6d0..48d90d700 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -681,15 +681,16 @@ static int set_system_infos(struct gsm_bts_trx *trx) DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } - } #ifdef GPRS - i = 13 - rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); - if (rc < 0) - goto err_out; - DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); - rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); + i = 13 + rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); + if (rc < 0) + goto err_out; + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); + rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); #endif + } + i = 5; rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_5); if (rc < 0) -- cgit v1.2.3 From 1394fea03f888408616cac3a669191f2e6923c8f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 23:01:33 +0100 Subject: ipaccess: Fix two minor bugs regarding multi-TRX setup we need to set newbfd->priv_nr to 2+trx_id, rather than keeping it '2' all the time, as it is used to look-up the e1i_ts when we receive a packet. A constant '2' would always match to TRX 0. we also need to keep one separate bit for each TRX state in order to properly generate the EVT_E1_TEI_UP event for trx > 0. --- openbsc/src/input/ipaccess.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 143712e1c..6bd501df1 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -238,6 +238,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, trx->rsl_tei, 0); /* get rid of our old temporary bfd */ memcpy(newbfd, bfd, sizeof(*newbfd)); + newbfd->priv_nr = 2+trx_id; bsc_unregister_fd(bfd); bsc_register_fd(newbfd); talloc_free(bfd); @@ -347,9 +348,9 @@ static int handle_ts1_read(struct bsc_fd *bfd) switch (link->type) { case E1INP_SIGN_RSL: - if (!(msg->trx->bts->ip_access.flags & RSL_UP)) { + if (!(msg->trx->bts->ip_access.flags & (RSL_UP << msg->trx->nr))) { e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); - msg->trx->bts->ip_access.flags |= RSL_UP; + msg->trx->bts->ip_access.flags |= (RSL_UP << msg->trx->nr); } ret = abis_rsl_rcvmsg(msg); break; -- cgit v1.2.3 From 713550120cb9231de49090c01abb6e867a93137d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 23:08:18 +0100 Subject: remove duplicate flag for cell barring it's sufficient if we keep the state of cell barring in one place --- openbsc/src/bsc_init.c | 4 +--- openbsc/src/vty_interface.c | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 48d90d700..86a93a1a9 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -804,7 +804,7 @@ static int bootstrap_bts(struct gsm_bts *bts) } if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL && - !bts->cell_barred) + !bts->si_common.rach_control.cell_bar) LOGP(DNM, LOG_ERROR, "\nWARNING: You are running an 'accept-all' " "network on a BTS that is not barred. This " "configuration is likely to interfere with production " @@ -815,8 +815,6 @@ static int bootstrap_bts(struct gsm_bts *bts) bts->si_common.chan_desc.att = 1; bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; - if (bts->cell_barred) - bts->si_common.rach_control.cell_bar = 1; /* T3212 is set from vty/config */ /* some defaults for our system information */ diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 0e518efd4..b13dc5f58 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -140,7 +140,7 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) VTY_NEWLINE); vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s", bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); - if (bts->cell_barred) + if (bts->si_common.rach_control.cell_bar) vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) vty_out(vty, " Unit ID: %u/%u/0, OML Stream ID 0x%02x%s", @@ -258,7 +258,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " channel allocator %s%s", bts->chan_alloc_reverse ? "descending" : "ascending", VTY_NEWLINE); - if (bts->cell_barred) + if (bts->si_common.rach_control.cell_bar) vty_out(vty, " cell barred 1%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) { vty_out(vty, " ip.access unit_id %u %u%s", @@ -1202,7 +1202,7 @@ DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd, { struct gsm_bts *bts = vty->index; - bts->cell_barred = atoi(argv[0]); + bts->si_common.rach_control.cell_bar = atoi(argv[0]); return CMD_SUCCESS; } -- cgit v1.2.3 From 73d4fce151b587ae28692448ea7094212e7eab7b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 23:12:19 +0100 Subject: make sure bootstrap_bts() only contains static initialization values that might change at runtime are moved to set_system_infos() which we might now also call at runtime to update the BTS with changes in the SI --- openbsc/src/bsc_init.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 86a93a1a9..61510435b 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -672,6 +672,11 @@ static int set_system_infos(struct gsm_bts_trx *trx) { int i, rc; u_int8_t si_tmp[23]; + struct gsm_bts *bts = trx->bts; + + bts->si_common.cell_sel_par.ms_txpwr_max_ccch = + ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); + bts->si_common.cell_sel_par.neci = bts->network->neci; if (trx == trx->bts->c0) { for (i = 1; i <= 4; i++) { @@ -827,10 +832,7 @@ static int bootstrap_bts(struct gsm_bts *bts) bts->si_common.cell_options.dtx = 2; /* MS shall not use upplink DTX */ bts->si_common.cell_options.pwrc = 0; /* PWRC not set */ - bts->si_common.cell_sel_par.ms_txpwr_max_ccch = - ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); bts->si_common.cell_sel_par.acs = 0; - bts->si_common.cell_sel_par.neci = bts->network->neci; bts->si_common.ncc_permitted = 0xff; -- cgit v1.2.3 From ac0c13c02c16a2ae3188978665606ac8061f84e8 Mon Sep 17 00:00:00 2001 From: Steffen Neubauer Date: Sat, 5 Dec 2009 12:44:41 +0100 Subject: [sms] bugfix: additional functionality indicator only appears in TP_VPF_ENHANCED - not in TP_VPF_ABSOLUTE --- openbsc/src/gsm_04_11.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 31526e979..17a583113 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -560,7 +560,8 @@ static int gsm340_rx_tpdu(struct msgb *msg) case GSM340_TP_VPF_ENHANCED: sms_vp = smsp; /* the additional functionality indicator... */ - if (*smsp & (1<<7)) smsp++; + if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7)) + smsp++; smsp += 7; break; case GSM340_TP_VPF_NONE: -- cgit v1.2.3 From a992a36d5f9e7a2d1bb7948784c69ea2e342b7d3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 21 Dec 2009 23:36:45 +0100 Subject: it's LOGL_ERROR, not LOG_ERROR --- openbsc/src/bsc_init.c | 2 +- openbsc/src/telnet_interface.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 61510435b..a8a202e93 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -810,7 +810,7 @@ static int bootstrap_bts(struct gsm_bts *bts) if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL && !bts->si_common.rach_control.cell_bar) - LOGP(DNM, LOG_ERROR, "\nWARNING: You are running an 'accept-all' " + LOGP(DNM, LOGL_ERROR, "\nWARNING: You are running an 'accept-all' " "network on a BTS that is not barred. This " "configuration is likely to interfere with production " "GSM networks and should only be used in a RF " diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c index 2d7b05c70..bc91ca333 100644 --- a/openbsc/src/telnet_interface.c +++ b/openbsc/src/telnet_interface.c @@ -84,12 +84,12 @@ void telnet_init(struct gsm_network *network, int port) { sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) { - LOGP(DNM, LOG_ERROR, "Telnet interface failed to bind\n"); + LOGP(DNM, LOGL_ERROR, "Telnet interface failed to bind\n"); return; } if (listen(fd, 0) < 0) { - LOGP(DNM, LOG_ERROR, "Telnet interface failed to listen\n"); + LOGP(DNM, LOGL_ERROR, "Telnet interface failed to listen\n"); return; } -- cgit v1.2.3 From 24ff6ee0a343d46823771b9a86e867780eb2099b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 22 Dec 2009 00:41:05 +0100 Subject: keep some internal statistics inside OpenBSC the statistics will give us some idea about the network load and performance. --- openbsc/src/abis_rsl.c | 3 +++ openbsc/src/gsm_04_08.c | 19 +++++++++++++++++++ openbsc/src/gsm_04_08_utils.c | 2 ++ openbsc/src/gsm_04_11.c | 9 ++++++++- openbsc/src/handover_logic.c | 8 ++++++++ openbsc/src/paging.c | 7 +++++++ openbsc/src/vty_interface.c | 36 ++++++++++++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 72ae9dbb6..ae1d6af5d 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1261,11 +1261,14 @@ static int rsl_rx_chan_rqd(struct msgb *msg) lctype = get_ctype_by_chreq(bts, rqd_ref->ra, bts->network->neci); chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra, bts->network->neci); + bts->network->stats.chreq.total++; + /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { DEBUGP(DRSL, "CHAN RQD: no resources for %s 0x%x\n", gsm_lchan_name(lctype), rqd_ref->ra); + bts->network->stats.chreq.no_channel++; /* FIXME: send some kind of reject ?!? */ return -ENOMEM; } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 156927f56..2b9dcc238 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -886,6 +886,7 @@ static int encode_more(struct msgb *msg) /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) { + struct gsm_bts *bts = lchan->ts->trx->bts; struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -897,6 +898,8 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) gh->data[0] = cause; DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr); + + bts->network->stats.loc_upd_resp.reject++; return gsm48_sendmsg(msg, NULL); } @@ -925,6 +928,8 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); + bts->network->stats.loc_upd_resp.accept++; + return gsm48_sendmsg(msg, NULL); } @@ -1043,6 +1048,18 @@ static int mm_rx_loc_upd_req(struct msgb *msg) dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, &lu->mi_len); + switch (lu->type) { + case GSM48_LUPD_NORMAL: + bts->network->stats.loc_upd_type.normal++; + break; + case GSM48_LUPD_IMSI_ATT: + bts->network->stats.loc_upd_type.attach++; + break; + case GSM48_LUPD_PERIODIC: + bts->network->stats.loc_upd_type.periodic++; + break; + } + /* * Pseudo Spoof detection: Just drop a second/concurrent * location updating request. @@ -1369,6 +1386,8 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ", mi_type, mi_string); + bts->network->stats.loc_upd_type.detach++; + switch (mi_type) { case GSM_MI_TYPE_TMSI: subscr = subscr_get_by_tmsi(bts->network, diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index e96a1ca09..2cd571e24 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -488,6 +488,8 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr) sig_data.bts = msg->lchan->ts->trx->bts; sig_data.lchan = msg->lchan; + bts->network->stats.paging.completed++; + dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); /* Stop paging on the bts we received the paging response */ diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 17a583113..579bb55d1 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -517,6 +517,8 @@ static int gsm340_rx_tpdu(struct msgb *msg) u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; + bts->network->stats.sms.submitted++; + gsms = sms_alloc(); if (!gsms) return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; @@ -605,6 +607,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr); if (!gsms->receiver) { rc = 1; /* cause 1: unknown subscriber */ + bts->network->stats.sms.no_receiver++; goto out; } @@ -791,7 +794,9 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, * to store this in our database and wati for a SMMA message */ /* FIXME */ dispatch_signal(SS_SMS, S_SMS_MEM_EXCEEDED, trans->subscr); - } + trans->lchan->ts->trx->bts->network->stats.sms.rp_err_mem++; + } else + trans->lchan->ts->trx->bts->network->stats.sms.rp_err_other++; sms_free(sms); trans->sms.sms = NULL; @@ -1064,6 +1069,8 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) DEBUGP(DSMS, "TX: SMS DELIVER\n"); + lchan->ts->trx->bts->network->stats.sms.delivered++; + return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref); /* FIXME: enter 'wait for RP-ACK' state, start TR1N */ } diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 94d3d0d1e..393b0f2ad 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -97,9 +97,12 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n", old_lchan->ts->trx->bts->nr, bts->nr); + bts->network->stats.handover.attempted++; + new_lchan = lchan_alloc(bts, old_lchan->type); if (!new_lchan) { LOGP(DHO, LOGL_NOTICE, "No free channel\n"); + bts->network->stats.handover.no_channel++; return -ENOSPC; } @@ -143,6 +146,7 @@ static void ho_T3103_cb(void *_ho) struct bsc_handover *ho = _ho; DEBUGP(DHO, "HO T3103 expired\n"); + ho->new_lchan->ts->trx->bts->network->stats.handover.timeout++; lchan_free(ho->new_lchan); llist_del(&ho->list); @@ -211,6 +215,8 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) return -ENODEV; } + new_lchan->ts->trx->bts->network->stats.handover.completed++; + bsc_del_timer(&ho->T3103); /* update lchan pointer of transaction */ @@ -238,6 +244,8 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) return -ENODEV; } + old_lchan->ts->trx->bts->network->stats.handover.failed++; + bsc_del_timer(&ho->T3103); llist_del(&ho->list); put_lchan(ho->new_lchan); diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index b273419c3..538e0a8ec 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -212,6 +212,8 @@ static void paging_T3113_expired(void *data) cbfn = req->cbfn; paging_remove_request(&req->bts->paging, req); + req->bts->network->stats.paging.expired++; + dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); if (cbfn) cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL, @@ -254,6 +256,8 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, struct gsm_bts *bts = NULL; int num_pages = 0; + network->stats.paging.attempted++; + /* start paging subscriber on all BTS within Location Area */ do { int rc; @@ -269,6 +273,9 @@ int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr, return rc; } while (1); + if (num_pages == 0) + network->stats.paging.detached++; + return num_pages; } diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index b13dc5f58..fa9b45da4 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -761,6 +761,41 @@ DEFUN(show_paging, return CMD_SUCCESS; } +DEFUN(show_stats, + show_stats_cmd, + "show statistics", + SHOW_STR "Display network statistics\n") +{ + struct gsm_network *net = gsmnet; + + vty_out(vty, "Channel Requests: %lu total, %lu no channel%s", + net->stats.chreq.total, net->stats.chreq.no_channel, + VTY_NEWLINE); + vty_out(vty, "Location Update: %lu attach, %lu normal, %lu periodic%s", + net->stats.loc_upd_type.attach, net->stats.loc_upd_type.normal, + net->stats.loc_upd_type.periodic, VTY_NEWLINE); + vty_out(vty, "IMSI Detach Indications: %lu%s\n", + net->stats.loc_upd_type.detach, VTY_NEWLINE); + vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", + net->stats.loc_upd_resp.accept, + net->stats.loc_upd_resp.reject, VTY_NEWLINE); + vty_out(vty, "Paging: %lu attempted, %lu complete, %lu expired%s", + net->stats.paging.attempted, net->stats.paging.completed, + net->stats.paging.expired, VTY_NEWLINE); + vty_out(vty, "Handover: %lu attempted, %lu no_channel, %lu timeout, " + "%lu completed, %lu failed%s", net->stats.handover.attempted, + net->stats.handover.no_channel, net->stats.handover.timeout, + net->stats.handover.completed, net->stats.handover.failed, + VTY_NEWLINE); + vty_out(vty, "SMS MO: %lu submitted, %lu no receiver%s", + net->stats.sms.submitted, net->stats.sms.no_receiver, + VTY_NEWLINE); + vty_out(vty, "SMS MT: %lu delivered, %lu no memory, %lu other error%s", + net->stats.sms.delivered, net->stats.sms.rp_err_mem, + net->stats.sms.rp_err_other, VTY_NEWLINE); + return CMD_SUCCESS; +} + DEFUN(cfg_net, cfg_net_cmd, "network", @@ -1435,6 +1470,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(VIEW_NODE, &show_e1ts_cmd); install_element(VIEW_NODE, &show_paging_cmd); + install_element(VIEW_NODE, &show_stats_cmd); install_element(CONFIG_NODE, &cfg_net_cmd); install_node(&net_node, config_write_net); -- cgit v1.2.3 From 92ffd926ef61b46a5cab9230a66b6fbb26bec613 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 22 Dec 2009 07:45:17 +0100 Subject: [gsm48] Move gsm48_parse_meas_rep to gsm_04_08_utils Move the function over to the _utils side as handover measurement is compiled into libbsc and we don't want to end up with linking errors. --- openbsc/src/gsm_04_08.c | 68 ------------------------------------------ openbsc/src/gsm_04_08_utils.c | 69 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 68 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 2b9dcc238..f89d8c5a2 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -165,74 +165,6 @@ static const char *rr_cause_name(u_int8_t cause) return strbuf; } -int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); - u_int8_t *data = gh->data; - struct gsm_bts *bts = msg->lchan->ts->trx->bts; - struct bitvec *nbv = &bts->si_common.neigh_list; - - if (gh->msg_type != GSM48_MT_RR_MEAS_REP) - return -EINVAL; - - if (data[0] & 0x80) - rep->flags |= MEAS_REP_F_BA1; - if (data[0] & 0x40) - rep->flags |= MEAS_REP_F_UL_DTX; - if ((data[1] & 0x40) == 0x00) - rep->flags |= MEAS_REP_F_DL_VALID; - - rep->dl.full.rx_lev = data[0] & 0x3f; - rep->dl.sub.rx_lev = data[1] & 0x3f; - rep->dl.full.rx_qual = (data[3] >> 4) & 0x7; - rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; - - rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2); - if (rep->num_cell < 1 || rep->num_cell > 6) - return 0; - - /* an encoding nightmare in perfection */ - - rep->cell[0].rxlev = data[3] & 0x3f; - rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2); - rep->cell[0].bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); - if (rep->num_cell < 2) - return 0; - - rep->cell[1].rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); - rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f); - rep->cell[1].bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); - if (rep->num_cell < 3) - return 0; - - rep->cell[2].rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); - rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f); - rep->cell[2].bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); - if (rep->num_cell < 4) - return 0; - - rep->cell[3].rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); - rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f); - rep->cell[3].bsic = data[11] >> 2; - if (rep->num_cell < 5) - return 0; - - rep->cell[4].rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); - rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv, - ((data[12] & 0xf) << 1) | (data[13] >> 7)); - rep->cell[4].bsic = (data[13] >> 1) & 0x3f; - if (rep->num_cell < 6) - return 0; - - rep->cell[5].rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); - rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv, - ((data[14] & 0x07) << 2) | (data[15] >> 6)); - rep->cell[5].bsic = data[15] & 0x3f; - - return 0; -} - int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi); static int gsm48_tx_simple(struct gsm_lchan *lchan, u_int8_t pdisc, u_int8_t msg_type); diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 2cd571e24..2db46ca58 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -700,3 +700,72 @@ int gsm48_rx_rr_modif_ack(struct msgb *msg) rsl_ipacc_crcx(msg->lchan); return rc; } + +int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); + u_int8_t *data = gh->data; + struct gsm_bts *bts = msg->lchan->ts->trx->bts; + struct bitvec *nbv = &bts->si_common.neigh_list; + + if (gh->msg_type != GSM48_MT_RR_MEAS_REP) + return -EINVAL; + + if (data[0] & 0x80) + rep->flags |= MEAS_REP_F_BA1; + if (data[0] & 0x40) + rep->flags |= MEAS_REP_F_UL_DTX; + if ((data[1] & 0x40) == 0x00) + rep->flags |= MEAS_REP_F_DL_VALID; + + rep->dl.full.rx_lev = data[0] & 0x3f; + rep->dl.sub.rx_lev = data[1] & 0x3f; + rep->dl.full.rx_qual = (data[3] >> 4) & 0x7; + rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7; + + rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2); + if (rep->num_cell < 1 || rep->num_cell > 6) + return 0; + + /* an encoding nightmare in perfection */ + + rep->cell[0].rxlev = data[3] & 0x3f; + rep->cell[0].arfcn = bitvec_get_nth_set_bit(nbv, data[4] >> 2); + rep->cell[0].bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); + if (rep->num_cell < 2) + return 0; + + rep->cell[1].rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); + rep->cell[1].arfcn = bitvec_get_nth_set_bit(nbv, (data[6] >> 2) & 0x1f); + rep->cell[1].bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); + if (rep->num_cell < 3) + return 0; + + rep->cell[2].rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); + rep->cell[2].arfcn = bitvec_get_nth_set_bit(nbv, (data[8] >> 1) & 0x1f); + rep->cell[2].bsic = ((data[8] & 0x01) << 6) | (data[9] >> 3); + if (rep->num_cell < 4) + return 0; + + rep->cell[3].rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); + rep->cell[3].arfcn = bitvec_get_nth_set_bit(nbv, data[10] & 0x1f); + rep->cell[3].bsic = data[11] >> 2; + if (rep->num_cell < 5) + return 0; + + rep->cell[4].rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); + rep->cell[4].arfcn = bitvec_get_nth_set_bit(nbv, + ((data[12] & 0xf) << 1) | (data[13] >> 7)); + rep->cell[4].bsic = (data[13] >> 1) & 0x3f; + if (rep->num_cell < 6) + return 0; + + rep->cell[5].rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); + rep->cell[5].arfcn = bitvec_get_nth_set_bit(nbv, + ((data[14] & 0x07) << 2) | (data[15] >> 6)); + rep->cell[5].bsic = data[15] & 0x3f; + + return 0; +} + -- cgit v1.2.3 From 4f5456c040c2dd0c53fe28cb51219d668d464a21 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 22 Dec 2009 07:48:20 +0100 Subject: [misc] Move rtp_proxy.c into the libbsc.c For the time being RSL has to know about Layer4 and upwards and is using the RTP socket class.... --- openbsc/src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index f36a701bc..4def2e93b 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -12,10 +12,10 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \ - handover_decision.c meas_rep.c + handover_decision.c meas_rep.c rtp_proxy.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ - mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ + mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c -- cgit v1.2.3