FreeCalypso > hg > fc-selenite
diff src/g23m-gprs/sm/sm_qos.c @ 1:d393cd9bb723
src/g23m-*: initial import from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 15 Jul 2018 04:40:46 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g23m-gprs/sm/sm_qos.c Sun Jul 15 04:40:46 2018 +0000 @@ -0,0 +1,1852 @@ +/*---------------------------------------------------------------------------- +| Project : 3G PS +| Module : SM ++----------------------------------------------------------------------------- +| Copyright 2003 Texas Instruments. +| All rights reserved. +| +| This file is confidential and a trade secret of Texas +| Instruments . +| The receipt of or possession of this file does not convey +| any rights to reproduce or disclose its contents or to +| manufacture, use, or sell anything it may describe, in +| whole, or in part, without the specific written consent of +| Texas Instruments. ++----------------------------------------------------------------------------- +| Purpose: 3G QoS utility functions implementation in the SM entity. +| For design details, see: +| 8010.908 SM Detailed Specification ++---------------------------------------------------------------------------*/ + +/*==== DECLARATION CONTROL =================================================*/ + +/*==== INCLUDES =============================================================*/ + +#include "sm.h" + +#include "sm_qos.h" + +/*==== CONST ================================================================*/ + +struct qos_from_to { + U32 integer; + struct { + U16 ratio_mant, ratio_exp; + } ratio; + U8 packed; +}; + +/*@checked@*/ +static const struct qos_from_to sm_qos_ber_table[] = { + { 20UL, {(U16)5,(U16)2}, (U8)M_SM_QOS_BER_5E_2}, + { 100UL, {(U16)5,(U16)2}, (U8)M_SM_QOS_BER_1E_2}, + { 200UL, {(U16)5,(U16)3}, (U8)M_SM_QOS_BER_5E_3}, + { 250UL, {(U16)4,(U16)3}, (U8)M_SM_QOS_BER_4E_3}, + { 1000UL, {(U16)1,(U16)3}, (U8)M_SM_QOS_BER_1E_3}, + { 10000UL, {(U16)1,(U16)4}, (U8)M_SM_QOS_BER_1E_4}, + { 100000UL, {(U16)1,(U16)5}, (U8)M_SM_QOS_BER_1E_5}, + { 1000000UL, {(U16)1,(U16)6}, (U8)M_SM_QOS_BER_1E_6}, + {16666667UL, {(U16)6,(U16)8}, (U8)M_SM_QOS_BER_6E_8}, + { 0UL, {(U16)0,(U16)0}, (U8)M_SM_QOS_BER_SUB} +}; + +/*@checked@*/ +static const struct qos_from_to sm_qos_sdu_err_ratio_table[] = { + { 10UL, {(U16)1,(U16)1}, (U8)M_SM_QOS_SDU_ERR_1E_1}, /* NOTE: M_SM_QOS_SDU_ERR_1E_1 == 7 */ + { 100UL, {(U16)1,(U16)2}, (U8)M_SM_QOS_SDU_ERR_1E_2}, + { 143UL, {(U16)7,(U16)3}, (U8)M_SM_QOS_SDU_ERR_7E_3}, + { 1000UL, {(U16)1,(U16)3}, (U8)M_SM_QOS_SDU_ERR_1E_3}, + { 10000UL, {(U16)1,(U16)4}, (U8)M_SM_QOS_SDU_ERR_1E_4}, + { 100000UL, {(U16)1,(U16)5}, (U8)M_SM_QOS_SDU_ERR_1E_5}, + { 1000000UL, {(U16)1,(U16)6}, (U8)M_SM_QOS_SDU_ERR_1E_6}, + { 0UL, {(U16)0,(U16)0}, (U8)M_SM_QOS_SDU_ERR_SUB} +}; + +/* + * Conversion table for 1/n in T_ratio. + * Contains 1/n * 1E9 entries used for scaling. + */ +/*@checked@*/ +static const U32 sm_qos_ratio_table[10] = { + 0UL, + 1000000000UL, /* 1E9 / 1 */ + 500000000UL, /* 1E9 / 2 */ + 333333333UL, /* 1E9 / 3 */ + 250000000UL, /* 1E9 / 4 */ + 200000000UL, /* 1E9 / 5 */ + 166666667UL, /* 1E9 / 6 */ + 142857143UL, /* 1E9 / 7 */ + 125000000UL, /* 1E9 / 8 */ + 111111111UL /* 1E9 / 9 */ +}; + +/*==== LOCAL VARS ===========================================================*/ + +/*==== PRIVATE FUNCTIONS ====================================================*/ + +/* Conversion function: ratio to integer */ +static U32 sm_qos_ratio_to_U32(U8 ratio_mant, U8 ratio_exp) + /*@globals sm_qos_ratio_table@*/ +{ + U32 value; + int count; + + /* Error checks */ + if (ratio_exp > (U8)9) + { + (void)TRACE_ERROR( "QoS ratio exponent parameter out of bounds!" ); + return 0; + } else if (ratio_mant > (U8)9) { + (void)TRACE_ERROR( "QoS ratio mantissa parameter out of bounds!" ); + return 0; + } else if (ratio_exp == (U8)9 && ratio_mant < (U8)5) { + (void)TRACE_ERROR( "QoS ratio parameter exceeds data type range!" ); + return 0; + } else { + for (count = 9-(int)ratio_exp, value = 1UL; count > 0; count--) { + value *= 10; + } + /* Get real value by rounding 1/x and dividing by 10^(9-ratio_exp) */ + value = (sm_qos_ratio_table[(U16)ratio_mant] + (value >> 1)) / value; + + return value; + } +} + +static U8 sm_qos_ratio_to_r99aim(const struct qos_from_to *table, + U8 ratio_mant, U8 ratio_exp) + /*@globals sm_qos_ratio_table@*/ +{ + int index; + U32 value; + + /* Check for zero / subscribed parameter */ + if (ratio_mant == (U8)0) + { + return (U8)M_SM_QOS_BER_SUB; + } + + value = sm_qos_ratio_to_U32(ratio_mant, ratio_exp); + + /* Find the smallest matching table entry that is >= value */ + for (index = 0; + table[index].integer != 0 && table[index].integer < value; + index++) + {}; + + return (table[index].packed); +} + +static void sm_qos_r99aim_to_ratio(const struct qos_from_to *table, + U8 packed_ratio, + /*@out@*/U8 *ratio_mant, + /*@out@*/U8 *ratio_exp) + /*@modifies *ratio_mant, *ratio_exp@*/ +{ + int index; + + for (index = 0; + table[index].integer != 0 && packed_ratio != table[index].packed; + index++) + {}; + + *ratio_mant = (U8)table[index].ratio.ratio_mant; + *ratio_exp = (U8)table[index].ratio.ratio_exp; +} + +static U32 sm_qos_r99aim_ratio_to_U32(const struct qos_from_to *table, + U8 packed_ratio) +{ + int index; + + for (index = 0; + table[index].integer != 0 && packed_ratio != table[index].packed; + index++) + {}; + + return (table[index].integer); +} + +/* Helper function for converting "human readable" bit-rate values into + * packed 3G air interface equvalents. + * + * Parameters: Integer representation of the bit-rate + * Returns: Packed bit-rate value + * + * Conversion rules according to [3G 24.008, sec 11.5.6.5] + */ + +static U8 sm_qos_bitrate_to_r99aim(U16 bitrate) /*@*/ +{ + U8 result = (U8)0; + + if (bitrate < (U16)64) { + /* 1 - 63 kbps map to values 1 - 63 @ 1kbps increments*/ + result = (U8)bitrate; + } else if (bitrate < (U16)576) { + /* 64 - 568 kbps map to values 64 - 127 @ 8kbps increments. + * Values not on boundaries are rounded up. + * Formula: result = ((bitrate + 7) / 8) + (64 - (64 / 8)) */ + result = (U8)((U16)(bitrate + ((64 * 8) - 64 + 7)) >> 3); + } else if (bitrate < (U16)8640) { + /* 576 - 8640 kbps map to values 128 - 254 @ 64kbps increments. + * Values not on boundaries are rounded up. + * Formula: result = ((bitrate + 63) / 64) + (128 - (576 / 64)) */ + result = (U8)((U16)(bitrate + ((128 * 64) - 576 + 63)) >> 6); + } else { + /* Error */ + (void)TRACE_EVENT( "Warning: Bitrate parameter out of bounds! Truncated..." ); + result = (U8)254; + } + return result; +} + +/* Helper function for converting packed 3G air interface bit-rate values + * into "human readable" equvalents. + * + * Parameters: Packed bit-rate value + * Returns: Integer representation of the bit-rate + * + * Conversion rules according to [3G 24.008, sec 11.5.6.5] + */ + +static U16 sm_qos_r99aim_to_bitrate(U8 packed_bitrate) /*@*/ +{ + U16 bitrate = 0; + + if (packed_bitrate < (U8)64) { + bitrate = (U16)packed_bitrate; + } else if (packed_bitrate < (U8)128) { + bitrate = (U16)((packed_bitrate - (U8)56) << 3); + } else if (packed_bitrate < (U8)255) { + bitrate = (U16)((packed_bitrate - (U8)119) << 6); + } else { + bitrate = 0; + } + return bitrate; +} + +/* Helper function for converting "human readable" max SDU size values into + * packed 3G air interface equvalents. + * + * Parameters: Integer representation of the SDU size + * Returns: Packed SDU size value + * + * Conversion rules according to [3G 24.008, sec 11.5.6.5] + */ + +static U8 sm_qos_max_sdu_to_r99aim(U16 sdu_size) /*@*/ +{ + U8 result = (U8)0; + + if (sdu_size == (U16)PS_MAX_SDU_SUB) { + result = (U8)PS_MAX_SDU_SUB; + } else if (sdu_size <= (U16)1500) {/* Round up to nearest multiple of 10 and divide by 10. */ + result = (U8)((sdu_size + 9) / 10); + } else if (sdu_size <= (U16)1502) {/* Round 1501-1502 to 1502. */ + result = (U8)PS_MAX_SDU_1502; + } else if (sdu_size <= (U16)1510) {/* Round 1503-1510 to 1510. */ + result = (U8)PS_MAX_SDU_1510; + } else if (sdu_size <= (U16)1520) {/* Round 1511-1520 to 1520. */ + result = (U8)PS_MAX_SDU_1520; + } else { /* > 1520: We are forgiving and just truncate to 1520 */ + result = (U8)PS_MAX_SDU_1520; + (void)TRACE_EVENT( "Warning: Max SDU size specified > 1520! Truncated..." ); + } + return result; +} + +/* + * Helper function for converting packed 3G air interface max SDU size values + * into "human readable" equvalents. + * + * Parameters: Packed max SDU value + * Returns: Integer representation of the SDU size + * + * Conversion rules according to [3G 24.008, sec 11.5.6.5] + */ + +static U16 sm_qos_r99aim_to_max_sdu(U8 packed_sdu_size) /*@*/ +{ + U16 result = 0; + + if (packed_sdu_size < (U8)PS_MAX_SDU_1502) { + result = (U16)packed_sdu_size * (U16)10; + } else if (packed_sdu_size == (U8)PS_MAX_SDU_1502) { + result = (U16)1502; + } else if (packed_sdu_size == (U8)PS_MAX_SDU_1510) { + result = (U16)1510; + } else if (packed_sdu_size == (U8)PS_MAX_SDU_1520) { + result = (U16)1520; + } else { /* Error handling ? */ + result = (U16)1520; + (void)TRACE_EVENT( "Warning: Packed max SDU size value > 153 (1520 octets)! Truncated..."); + } + return result; +} + +/* + * Helper function for converting "human readable" transfer delay values + * into packed 3G air interface equvalents. + * + * Parameters: Integer representation of the transfer delay + * Returns: Packed transfer delay value + * + * Conversion rules according to [3G 24.008, sec 11.5.6.5] + */ + +static U8 sm_qos_xfer_delay_to_r99aim(U16 xfer_delay) /*@*/ +{ + U8 result = (U8)0; + + if (xfer_delay == 0) { + result = (U8)0; + } else if (xfer_delay < (U16)10) { /* Make sure low values do not map to SUBSCRIBED */ + result = (U8)1; + } else if (xfer_delay <= (U16)150) { + /* 10 - 150ms map to values 1 - 15 @ 10ms increments. We round down. */ + result = (U8)(xfer_delay / 10); + } else if (xfer_delay <= (U16)1000) { + /* 200 - 950ms map to values 16 - 31 @ 50ms increments. + * Values not on boundaries are rounded down. + * Formula: result = (xfer_delay / 50) + (16 - (200 / 50)) */ + result = (U8)((xfer_delay + ((16 * 50) - 200)) / 50); + } else if (xfer_delay <= (U16)4000) { + /* 1000 - 4000ms map to values 32-62 @ 100ms increments. + * Values not on boundaries are rounded down. + * Formula: result = (xfer_delay / 100) + (32 - (1000 / 100)) */ + result = (U8)((xfer_delay + ((32 * 100) - 1000)) / 100); + } else { + /* Error */ + (void)TRACE_EVENT( "Warning: Transfer delay out of bounds! Truncated..." ); + result = (U8)62; + } + return result; +} + +/* + * Helper function for converting packed 3G air interface transfer delay values + * into "human readable" equvalents. + * + * Parameters: Packed transfer delay value + * Returns: Integer representation of the transfer delay + * + * Conversion rules according to [3G 24.008, sec 11.5.6.5] + */ + +static U16 sm_qos_r99aim_to_xfer_delay(U8 packed_xfer_delay) /*@*/ +{ + U16 result = 0; + + if (packed_xfer_delay == (U8)0) { + result = (U16)PS_XFER_DELAY_SUB; + } else if (packed_xfer_delay < (U8)16) { + result = (U16)packed_xfer_delay * (U16)10; + } else if (packed_xfer_delay < (U8)32) { + result = ((U16)packed_xfer_delay - (U16)12) * (U16)50; + } else if (packed_xfer_delay < (U8)63) { + result = ((U16)packed_xfer_delay - (U16)22) * (U16)100; + } else { + result = (U16)4000; + (void)TRACE_EVENT( "Warning: R99 transfer delay parameter out of bounds (== 63)! Truncated..." ); + } + + return result; +} + +/* + * Helper function for converting packed 3G air interface traffic class values + * into AT command equivalents as per [3G 27.007]. + * + * Parameters: Packed traffic class value + * Returns: AT command representation of the same traffic class value + */ +static U8 sm_qos_r99aim_to_tc(U8 packed_tc) /*@*/ +{ + switch (packed_tc) { + case M_SM_QOS_TC_CONV: return (U8)PS_TC_CONV; + case M_SM_QOS_TC_STREAM: return (U8)PS_TC_STREAM; + case M_SM_QOS_TC_INTER: return (U8)PS_TC_INTER; + case M_SM_QOS_TC_BG: return (U8)PS_TC_BG; + default: + (void)TRACE_EVENT_P1("Warning: AIM traffic class '%d' out of bounds! Defaulting to SUBSCRIBED...", packed_tc); + return (U8)PS_TC_SUB; + } +} + +/* + * Helper function for converting AT command traffic class values + * into packed 3G air interface equivalents. + * + * Parameters: AT command traffic class value + * Returns: 3G AIM representation of the same traffic class value + */ +static U8 sm_qos_tc_to_r99aim(U8 tc) /*@*/ +{ + switch (tc) { + case PS_TC_CONV: return (U8)M_SM_QOS_TC_CONV; + case PS_TC_STREAM: return (U8)M_SM_QOS_TC_STREAM; + case PS_TC_INTER: return (U8)M_SM_QOS_TC_INTER; + case PS_TC_BG: return (U8)M_SM_QOS_TC_BG; + case PS_TC_SUB: return (U8)M_SM_QOS_TC_SUB; + default: + (void)TRACE_EVENT_P1("ERROR: QoS traffic class '%d' out of bounds! Defaulting to SUBSCRIBED, but expect an imminent crash!", tc); + return (U8)M_SM_QOS_TC_SUB; + } +} + +/* + * Helper function for converting packed 3G air interface delivery order + * parameter values into AT command equivalents as per [3G 27.007]. + * + * Parameters: Packed delivery order parameter + * Returns: AT command representation of the same delivery order value + */ +static U8 sm_qos_r99aim_to_order(U8 packed_order) /*@*/ +{ + switch (packed_order) { + case M_SM_QOS_ORDER_NO: return (U8)PS_ORDER_NO; + case M_SM_QOS_ORDER_YES: return (U8)PS_ORDER_YES; + default: + (void)TRACE_EVENT_P1("Warning: AIM delivery order parameter '%d' out of bounds! Defaulting to SUBSCRIBED...", packed_order); + return (U8)PS_ORDER_SUB; + } +} + +/* + * Helper function for converting AT command delivery order parameter values + * into packed 3G air interface equivalents. + * + * Parameters: AT command delivery order parameter + * Returns: Packed 3G AIM representation of the same delivery order value + */ +static U8 sm_qos_order_to_r99aim(U8 order) /*@*/ +{ + switch (order) { + case PS_ORDER_NO: return (U8)M_SM_QOS_ORDER_NO; + case PS_ORDER_YES: return (U8)M_SM_QOS_ORDER_YES; + case PS_ORDER_SUB: return (U8)M_SM_QOS_ORDER_SUB; + default: + (void)TRACE_EVENT_P1("Warning: Delivery order parameter '%d' out of bounds! Defaulting to SUBSCRIBED...", order); + return (U8)M_SM_QOS_ORDER_SUB; + } +} + +/* + * Helper function for converting packed 3G air interface "delivery of + * erroneous SDUs" parameter values into AT command equivalents as per + * [3G 27.007]. + * + * Parameters: Packed delivery parameter + * Returns: AT command representation of the same delivery parameter + */ +static U8 sm_qos_r99aim_to_del_err_sdu(U8 packed_del_err_sdu) /*@*/ +{ + switch (packed_del_err_sdu) { + case M_SM_QOS_DEL_ERR_NO: return (U8)PS_DEL_ERR_NO; + case M_SM_QOS_DEL_ERR_YES: return (U8)PS_DEL_ERR_YES; + case M_SM_QOS_DEL_ERR_NODETECT: return (U8)PS_DEL_ERR_NODETECT; + default: + (void)TRACE_EVENT_P1("Warning: AIM delivery of err SDU parameter '%d' out of bounds! Defaulting to SUBSCRIBED", packed_del_err_sdu); + return (U8)PS_DEL_ERR_SUB; + } +} + +/* + * Helper function for converting AT command "delivery of erroneous SDUs" + * parameter values into packed 3G air interface equivalents. + * + * Parameters: AT command delivery parameter + * Returns: Packed 3G AIM representation of the same delivery value + */ +static U8 sm_qos_del_err_sdu_to_r99aim(U8 del_err_sdu) /*@*/ +{ + switch (del_err_sdu) { + case PS_DEL_ERR_NO: return (U8)M_SM_QOS_DEL_ERR_NO; + case PS_DEL_ERR_YES: return (U8)M_SM_QOS_DEL_ERR_YES; + case PS_DEL_ERR_NODETECT: return (U8)M_SM_QOS_DEL_ERR_NODETECT; + case PS_DEL_ERR_SUB: return (U8)M_SM_QOS_DEL_ERR_SUB; + default: + (void)TRACE_EVENT_P1("Warning: Delivery of err SDU parameter '%d' out of bounds! Defaulting to SUBSCRIBED...", del_err_sdu); + return (U8)M_SM_QOS_DEL_ERR_SUB; + } +} + +/* + * Function for converting a R97 QoS parameter set in SM internal representation + * into a 3G air message QoS parameter set. + * + * Conversion rules according to [3G 24.008, sec 10.5.6.5] + * + * Parameters: Originating R97 SM QoS parameter struct + * Destination R97/R99 3G QoS parameter struct (overwritten in this function) + */ + +static void sm_qos_convert_r97_to_aim(/*@in@*/ T_PS_qos_r97 *src_qos_r97, + /*@out@*/T_M_SM_qos *dst_qos) + /*@modifies dst_qos->qos_r97@*/ +{ +#ifdef DEBUG_VERBOSE + (void)TRACE_FUNCTION( "sm_qos_convert_r97_to_aim" ); +#endif + + dst_qos->qos_r97.delay = src_qos_r97->delay; + dst_qos->qos_r97.reliability = src_qos_r97->relclass; + dst_qos->qos_r97.peak = src_qos_r97->peak; + dst_qos->qos_r97.precedence = src_qos_r97->preced; + dst_qos->qos_r97.mean = src_qos_r97->mean; +} + +static void sm_qos_convert_r97aim_to_r97(/*@in@*/ T_M_SM_qos_r97 *src_qos, + /*@out@*/T_PS_qos_r97 *dst_qos_r97) + /*@modifies dst_qos_r97@*/ +{ +#ifdef DEBUG_VERBOSE + (void)TRACE_FUNCTION( "sm_qos_convert_r97aim_to_r97" ); +#endif + + dst_qos_r97->delay = src_qos->delay; + dst_qos_r97->relclass = src_qos->reliability; + dst_qos_r97->peak = src_qos->peak; + dst_qos_r97->preced = src_qos->precedence; + dst_qos_r97->mean = src_qos->mean; +} + +/* + * Function for converting a R99 QoS parameter set in SM internal representation + * into a 3G air message QoS parameter set. + * + * Conversion rules according to [3G 24.008, sec 10.5.6.5] + * + * Parameters: Originating R99 SM QoS parameter struct + * Destination R99 3G QoS parameter struct (overwritten in this function) + */ + +static void sm_qos_convert_r99_to_aim(/*@in@*/ T_PS_qos_r99 *src_qos_r99, + /*@out@*/T_M_SM_qos *dst_qos) + /*@globals sm_qos_ber_table, sm_qos_sdu_err_ratio_table, sm_qos_ratio_table@*/ + /*@modifies dst_qos->qos_r99@*/ +{ +#ifdef DEBUG_VERBOSE + (void)TRACE_FUNCTION( "sm_qos_convert_r99_to_aim" ); +#endif + + /* Traffic class */ + dst_qos->qos_r99.tc = sm_qos_tc_to_r99aim(src_qos_r99->tc); + + /* Delivery order */ + dst_qos->qos_r99.order = sm_qos_order_to_r99aim(src_qos_r99->order); + + /* Delivery of erroneous SDUs */ + dst_qos->qos_r99.del_err_sdu = sm_qos_del_err_sdu_to_r99aim(src_qos_r99->del_err_sdu); + + /* Max SDU size */ + dst_qos->qos_r99.max_sdu = sm_qos_max_sdu_to_r99aim(src_qos_r99->max_sdu); + + /* Max uplink bit-rate */ + dst_qos->qos_r99.max_br_ul = sm_qos_bitrate_to_r99aim(src_qos_r99->max_rate_ul); + + /* Max downlink bit-rate */ + dst_qos->qos_r99.max_br_dl = sm_qos_bitrate_to_r99aim(src_qos_r99->max_rate_dl); + + /* Residual BER */ + dst_qos->qos_r99.ber = sm_qos_ratio_to_r99aim(sm_qos_ber_table, + src_qos_r99->ber.ratio_mant, + src_qos_r99->ber.ratio_exp); + + /* SDU error ratio */ + dst_qos->qos_r99.sdu_err_ratio = sm_qos_ratio_to_r99aim(sm_qos_sdu_err_ratio_table, + src_qos_r99->sdu_err_ratio.ratio_mant, + src_qos_r99->sdu_err_ratio.ratio_exp); + + /* Transfer delay */ + dst_qos->qos_r99.xfer_delay = sm_qos_xfer_delay_to_r99aim(src_qos_r99->xfer_delay); + + /* Traffic handling priority */ + dst_qos->qos_r99.handling_pri= src_qos_r99->handling_pri; + + /* Guaranteed uplink bit-rate */ + dst_qos->qos_r99.guar_br_ul = sm_qos_bitrate_to_r99aim(src_qos_r99->guar_br_ul); + + /* Guaranteed downlink bit-rate */ + dst_qos->qos_r99.guar_br_dl = sm_qos_bitrate_to_r99aim(src_qos_r99->guar_br_dl); +} + +/* + * Function for converting a R99 3G air message QoS parameter set into a + * R99 QoS parameter set in SM internal representation + * + * Conversion rules according to [3G 24.008, sec 10.5.6.5] + * + * Parameters: Originating R99 3G QoS parameter struct + * Destination R99 SM QoS parameter struct (overwritten in this function) + */ + +static void sm_qos_convert_r99aim_to_r99(/*@in@*/ T_M_SM_qos_r99 *src_qos_r99, + /*@out@*/T_PS_qos_r99 *dst_qos_r99) + /*@globals sm_qos_ber_table, sm_qos_sdu_err_ratio_table@*/ + /*@modifies dst_qos_r99@*/ +{ +#ifdef DEBUG_VERBOSE + (void)TRACE_FUNCTION( "sm_qos_convert_r99aim_to_r99" ); +#endif + + /* Traffic class */ + dst_qos_r99->tc = sm_qos_r99aim_to_tc(src_qos_r99->tc); + + /* Delivery order */ + dst_qos_r99->order = sm_qos_r99aim_to_order(src_qos_r99->order); + + /* Delivery of erroneous SDUs */ + dst_qos_r99->del_err_sdu = sm_qos_r99aim_to_del_err_sdu(src_qos_r99->del_err_sdu); + + /* Max SDU size */ + dst_qos_r99->max_sdu = sm_qos_r99aim_to_max_sdu(src_qos_r99->max_sdu); + + /* Max uplink bit-rate */ + dst_qos_r99->max_rate_ul = sm_qos_r99aim_to_bitrate(src_qos_r99->max_br_ul); + + /* Max downlink bit-rate */ + dst_qos_r99->max_rate_dl = sm_qos_r99aim_to_bitrate(src_qos_r99->max_br_dl); + + /* Residual BER */ + sm_qos_r99aim_to_ratio(sm_qos_ber_table, src_qos_r99->ber, + &dst_qos_r99->ber.ratio_mant, + &dst_qos_r99->ber.ratio_exp); + + /* SDU error ratio */ + sm_qos_r99aim_to_ratio(sm_qos_sdu_err_ratio_table, src_qos_r99->sdu_err_ratio, + &dst_qos_r99->sdu_err_ratio.ratio_mant, + &dst_qos_r99->sdu_err_ratio.ratio_exp); + + /* Transfer delay */ + dst_qos_r99->xfer_delay = sm_qos_r99aim_to_xfer_delay(src_qos_r99->xfer_delay); + + /* Traffic handling priority */ + dst_qos_r99->handling_pri = src_qos_r99->handling_pri; + + /* Guaranteed uplink bit-rate */ + dst_qos_r99->guar_br_ul = sm_qos_r99aim_to_bitrate(src_qos_r99->guar_br_ul); + + /* Guaranteed downlink bit-rate */ + dst_qos_r99->guar_br_dl = sm_qos_r99aim_to_bitrate(src_qos_r99->guar_br_dl); +} + +/*==== PUBLIC FUNCTIONS =====================================================*/ + +/* + * Function for extracting the traffic class element stored for + * the given context. + */ +U8 sm_qos_get_traffic_class(struct T_SM_CONTEXT_DATA *context) +{ + /*lint -e613 (Possible use of null pointer 'context' in left argument to operator '->') */ + TRACE_ASSERT(context != NULL); + + if (context->requested_qos.ctrl_qos == PS_is_R97) { + T_PS_qos_r99 temp_qos; + + (void)cl_qos_convert_r97_to_r99(&context->requested_qos.qos.qos_r97, + &temp_qos); + + return temp_qos.tc; + } + else if (context->requested_qos.ctrl_qos == PS_is_R99) { + return context->requested_qos.qos.qos_r99.tc; + } + else { + /* Default to SUBSCRIBED */ + return (U8)PS_TC_SUB; + } +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_convert_to_aim ++------------------------------------------------------------------------------ +| Description : Function for converting a QoS parameter set in internal SM +| representation into an air interface QoS parameter set. +| Handles both R97 and R99 types, skipping R99 elements if +| network is R97. +| +| Parameters : src_qos - Source QoS (internal representation) +| dst_qos - Destination air interface QoS structure +| release - Core network release (R97/R99) ++------------------------------------------------------------------------------ +*/ +void sm_qos_convert_to_aim(/*@in@*/ T_SM_qos *src_qos, + /*@out@*/T_M_SM_qos *dst_qos, + T_PS_sgsn_rel release) + /*@globals sm_qos_ber_table, sm_qos_sdu_err_ratio_table, sm_qos_ratio_table@*/ +{ + +#ifdef DEBUG_VERBOSE + (void)TRACE_FUNCTION("sm_qos_convert_to_aim"); +#endif + + /* Is SGSN release = pre-R99 (or R98 and older) ? */ + if (release == PS_SGSN_98_OLDER) { + if (src_qos->ctrl_qos == PS_is_R97) { + sm_qos_convert_r97_to_aim(&src_qos->qos.qos_r97, dst_qos); + } else if (src_qos->ctrl_qos == PS_is_R99) { + /* Convert R99 to R97 values */ + T_PS_qos_r97 tmp_qos_r97; + cl_qos_convert_r99_to_r97(&src_qos->qos.qos_r99, &tmp_qos_r97); + sm_qos_convert_r97_to_aim(&tmp_qos_r97, dst_qos); + } else { + (void)TRACE_ERROR( "Invalid ctrl_qos value!" ); + } + /* Do not include R99 QoS elements in air interface message */ + dst_qos->v_qos_r99 = (U8)FALSE; + dst_qos->tlv_len = (U8)M_SM_SIZE_R97_QOS; + } else if (release == PS_SGSN_99_ONWARDS) { + if (src_qos->ctrl_qos == PS_is_R97) { + T_PS_qos_r99 tmp_qos; + /* Convert R97 to R99 struct */ + (void)cl_qos_convert_r97_to_r99(&src_qos->qos.qos_r97, &tmp_qos); + /* Include both R97 and R99 QoS info in AIM */ + sm_qos_convert_r97_to_aim(&src_qos->qos.qos_r97, dst_qos); + sm_qos_convert_r99_to_aim(&tmp_qos, dst_qos); + } else if (src_qos->ctrl_qos == PS_is_R99) { + T_PS_qos_r97 tmp_qos_r97; + /* Fill in R99 AIM fields */ + sm_qos_convert_r99_to_aim(&src_qos->qos.qos_r99, dst_qos); + /* [3G 24.008] says to always include R97/R98 parameters in QoS IE */ + cl_qos_convert_r99_to_r97(&src_qos->qos.qos_r99, &tmp_qos_r97); + sm_qos_convert_r97_to_aim(&tmp_qos_r97, dst_qos); + } else { + (void)TRACE_ERROR( "Invalid ctrl_qos value!" ); + } + /* Include R99 QoS elements in air interface message */ + dst_qos->v_qos_r99 = (U8)TRUE; + dst_qos->tlv_len = (U8)M_SM_SIZE_R99_QOS; + } else { + (void)TRACE_EVENT_P1("ERROR: Invalid network release union controller %d!", + release); + } +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_assign_from_aim ++------------------------------------------------------------------------------ +| Description : Function for converting an air interface QoS parameter set +| to internal SM representation. Handles both R97 and R99 types, +| and sets the destination QoS union controller to the R97/R99 +| type of the air interface message. +| +| Parameters : dst_qos - Destination QoS (internal representation) +| src_qos - Source air interface QoS structure ++------------------------------------------------------------------------------ +*/ +void sm_qos_assign_from_aim(/*@out@*/T_SM_qos *dst_qos, + /*@in@*/ T_M_SM_qos *src_qos) + /*@globals sm_qos_ber_table, sm_qos_sdu_err_ratio_table@*/ +{ +#ifdef DEBUG_VERBOSE + (void)TRACE_FUNCTION( "sm_qos_assign_from_aim"); +#endif + + /* Does QoS include R99 elements? */ + if (src_qos->v_qos_r99 == (U8)FALSE) { + /* FALSE == No R99 elements present; Set type to R97 */ + dst_qos->ctrl_qos = PS_is_R97; + sm_qos_convert_r97aim_to_r97(&src_qos->qos_r97, &dst_qos->qos.qos_r97); + } else { + /* TRUE == R99 elements present; Set type to R99 */ + dst_qos->ctrl_qos = PS_is_R99; + sm_qos_convert_r99aim_to_r99(&src_qos->qos_r99, &dst_qos->qos.qos_r99); + } +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_compare_r97_lt_r97 ++------------------------------------------------------------------------------ +| Description : Compares an R97 QoS structure with another (minimum) R97 QoS +| structure in internal SM representation. Returns TRUE if +| the supplied QoS is *less than* minimum QoS. +| Parameters : cmp_qos_r97 - comparison QoS structure +| min_qos_r97 - minimum QoS structure ++------------------------------------------------------------------------------ +*/ +/* NOTE: Removed. sm-to-sm comparisons only occur during MO modify + * procedures, which are not possible in R97.*/ +#if 0 +static BOOL sm_qos_compare_r97_lt_r97(/*@in@*/T_PS_qos_r97 *cmp_qos_r97, + /*@in@*/T_PS_qos_r97 *min_qos_r97) +{ + (void)TRACE_FUNCTION( "sm_qos_compare_r97aim_lt_r97"); + + if (min_qos_r97->delay != (U8)NAS_DELAY_SUB && + cmp_qos_r97->delay > min_qos_r97->delay) + { + (void)TRACE_EVENT_P2("R97 DELAY parameter insufficient: %d > %d (min_qos)", + cmp_qos_r97->delay, min_qos_r97->delay); + return TRUE; + } + if (min_qos_r97->relclass != (U8)NAS_RELCLASS_SUB && + cmp_qos_r97->relclass > min_qos_r97->relclass) + { + (void)TRACE_EVENT_P2("R97 RELIABILITY CLASS parameter insufficient: " + "%d > %d (min_qos)", + cmp_qos_r97->relclass, min_qos_r97->relclass); + return TRUE; + } + if (min_qos_r97->peak != (U8)NAS_PEAK_SUB && + cmp_qos_r97->peak < min_qos_r97->peak) + { + (void)TRACE_EVENT_P2("R97 PEAK BITRATE parameter insufficient: " + "%d < %d (min_qos)", + cmp_qos_r97->peak, min_qos_r97->peak); + return TRUE; + } + if (min_qos_r97->preced != (U8)NAS_PRECED_SUB && + cmp_qos_r97->preced > min_qos_r97->preced) + { + (void)TRACE_EVENT_P2("R97 PRECEDENCE CLASS parameter insufficient: " + "%d > %d (min_qos)", + cmp_qos_r97->preced, min_qos_r97->preced); + return TRUE; + } + if (min_qos_r97->mean != (U8)NAS_MEAN_SUB && + cmp_qos_r97->mean < min_qos_r97->mean) + { + (void)TRACE_EVENT_P2("R97 MEAN BITRATE parameter insufficient: " + "%d < %d (min_qos)", + cmp_qos_r97->mean, min_qos_r97->mean); + return TRUE; + } + return FALSE; +} +#endif + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_compare_r99_lt_r99 ++------------------------------------------------------------------------------ +| Description : Compares an R99 QoS structure with a (minimum) R99 QoS +| structure in internal SM representation. Returns TRUE if +| comparison QoS is *less than* minimum QoS. +| Parameters : cmp_qos_r99 - air interface QoS structure +| min_qos_r99 - minimum QoS structure ++------------------------------------------------------------------------------ +*/ +static BOOL sm_qos_compare_r99_lt_r99(/*@in@*/T_PS_qos_r99 *cmp_qos_r99, + /*@in@*/T_PS_qos_r99 *min_qos_r99) +{ + T_PS_tc traffic_class = (T_PS_tc)cmp_qos_r99->tc; +#ifdef DEBUG_VERBOSE + (void)TRACE_FUNCTION( "sm_qos_compare_r99_lt_r99"); +#endif + + /* Traffic class */ + if ((min_qos_r99->tc != (U8)PS_TC_SUB) && + (cmp_qos_r99->tc > min_qos_r99->tc)) + { + (void)TRACE_EVENT_P2("R99 TRAFFIC CLASS parameter insufficient: " + "%d > %d (min_qos)", + cmp_qos_r99->tc, min_qos_r99->tc); + return TRUE; + } + + /* Delivery order */ + if ((min_qos_r99->order != (U8)PS_ORDER_SUB) && + (cmp_qos_r99->order != min_qos_r99->order)) + { + (void)TRACE_EVENT_P2("R99 DELIVERY ORDER parameter insufficient: " + "%d != %d (min_qos)", + cmp_qos_r99->order, min_qos_r99->order); + return TRUE; + } + + /* Delivery of erroneous SDUs */ + if ((min_qos_r99->del_err_sdu != (U8)PS_DEL_ERR_SUB) && + (cmp_qos_r99->del_err_sdu != min_qos_r99->del_err_sdu)) + { + (void)TRACE_EVENT_P2("R99 DELIVERY of ERRONEUOS SDUs parameter " + "insufficient: %d != %d (min_qos)", + cmp_qos_r99->del_err_sdu, min_qos_r99->del_err_sdu); + return TRUE; + } + + /* Max SDU size */ + if ((min_qos_r99->max_sdu != (U16)PS_MAX_SDU_SUB) && + (cmp_qos_r99->max_sdu < min_qos_r99->max_sdu)) + { + (void)TRACE_EVENT_P2("R99 MAX SDU SIZE parameter insufficient: " + "%d < %d (min_qos)", + cmp_qos_r99->max_sdu, min_qos_r99->max_sdu); + return TRUE; + } + + /* Max uplink bit-rate */ + if ((min_qos_r99->max_rate_ul != (U16)PS_MAX_BR_UL_SUB) && + (cmp_qos_r99->max_rate_ul < min_qos_r99->max_rate_ul)) + { + (void)TRACE_EVENT_P2("R99 MAX UPLINK BITRATE parameter insufficient: " + "%d < %d (min_qos)", + cmp_qos_r99->max_rate_ul, min_qos_r99->max_rate_ul); + return TRUE; + } + + /* Max downlink bit-rate */ + if ((min_qos_r99->max_rate_dl != (U16)PS_MAX_BR_DL_SUB) && + (cmp_qos_r99->max_rate_dl < min_qos_r99->max_rate_dl)) + { + (void)TRACE_EVENT_P2("R99 MAX DOWNLINK BITRATE parameter insufficient: " + "%d < %d (min_qos)", + cmp_qos_r99->max_rate_dl, min_qos_r99->max_rate_dl); + return TRUE; + } + + /* Residual BER */ + if ((min_qos_r99->ber.ratio_exp != (U8)0 + && min_qos_r99->ber.ratio_mant != (U8)0) && + (sm_qos_ratio_to_U32(cmp_qos_r99->ber.ratio_mant, + cmp_qos_r99->ber.ratio_exp) < + sm_qos_ratio_to_U32(min_qos_r99->ber.ratio_mant, + min_qos_r99->ber.ratio_exp))) + { + (void)TRACE_EVENT_P4("R99 RESIDUAL BIT ERROR RATE parameter insufficient: " + "%dE-%d < %dE-%d (min_qos)", + cmp_qos_r99->ber.ratio_mant, + cmp_qos_r99->ber.ratio_exp, + min_qos_r99->ber.ratio_mant, + min_qos_r99->ber.ratio_exp); + return TRUE; + } + + /* SDU error ratio */ + if ((min_qos_r99->sdu_err_ratio.ratio_exp != (U8)0 && + min_qos_r99->sdu_err_ratio.ratio_mant != (U8)0) && + (sm_qos_ratio_to_U32(cmp_qos_r99->sdu_err_ratio.ratio_mant, + cmp_qos_r99->sdu_err_ratio.ratio_exp) < + sm_qos_ratio_to_U32(min_qos_r99->sdu_err_ratio.ratio_mant, + min_qos_r99->sdu_err_ratio.ratio_exp))) + { + (void)TRACE_EVENT_P4("R99 SDU ERROR RATIO parameter insufficient: " + "%dE-%d < %dE-%d (min_qos)", + cmp_qos_r99->sdu_err_ratio.ratio_mant, + cmp_qos_r99->sdu_err_ratio.ratio_exp, + min_qos_r99->sdu_err_ratio.ratio_mant, + min_qos_r99->sdu_err_ratio.ratio_exp); + return TRUE; + } + + /* Transfer delay - Note! Only for real-time traffic class traffic! */ + if ((traffic_class == PS_TC_CONV || traffic_class == PS_TC_STREAM) && + (min_qos_r99->xfer_delay != (U16)PS_XFER_DELAY_SUB) && + (cmp_qos_r99->xfer_delay > min_qos_r99->xfer_delay)) + { + (void)TRACE_EVENT_P2("R99 TRANSFER DELAY parameter insufficient: " + "%d > %d (min_qos)", + cmp_qos_r99->xfer_delay, min_qos_r99->xfer_delay); + return TRUE; + } + + /* Traffic handling priority - Note: Only interactive traffic class! */ + if ((traffic_class == PS_TC_INTER) && + (min_qos_r99->handling_pri != (U8)PS_HANDLING_PRI_SUB) && + (cmp_qos_r99->handling_pri > min_qos_r99->handling_pri)) + { + (void)TRACE_EVENT_P2("R99 TRANSFER HANDLING PRIORITY parameter " + "insufficient: %d > %d (min_qos)", + cmp_qos_r99->handling_pri, min_qos_r99->handling_pri); + return TRUE; + } + + /* Guaranteed uplink bit-rate - Note: Only for real-time traffic class traffic! */ + if ((traffic_class == PS_TC_CONV || traffic_class == PS_TC_STREAM) && + (min_qos_r99->guar_br_ul != (U16)PS_GUAR_BR_UL_SUB) && + (cmp_qos_r99->guar_br_ul < min_qos_r99->guar_br_ul)) + { + (void)TRACE_EVENT_P2("R99 GUARANTEED UPLINK BITRATE parameter " + "insufficient: %d < %d (min_qos)", + cmp_qos_r99->guar_br_ul, min_qos_r99->guar_br_ul); + return TRUE; + } + + /* Guaranteed downlink bit-rate - Note: Only for real-time traffic class traffic! */ + if ((traffic_class == PS_TC_CONV || traffic_class == PS_TC_STREAM) && + (min_qos_r99->guar_br_dl != (U16)PS_GUAR_BR_DL_SUB) && + (cmp_qos_r99->guar_br_dl < min_qos_r99->guar_br_dl)) + { + (void)TRACE_EVENT_P2("R99 GUARANTEED DOWNLINK BITRATE parameter " + "insufficient: %d < %d (min_qos)", + cmp_qos_r99->guar_br_dl, min_qos_r99->guar_br_dl); + return TRUE; + } + + return FALSE; +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_compare_r97aim_lt_r97 ++------------------------------------------------------------------------------ +| Description : Compares an R97 air interface QoS structure with an R97 QoS +| structure in internal SM representation. Returns TRUE if +| AIM QoS is *less than* min QoS or *greater than* req QoS. +| Parameters : aim_qos_r97 - air interface QoS structure +| min_qos_r97 - minimum QoS structure +| req_qos_r97 - requested QoS structure ++------------------------------------------------------------------------------ +*/ +static BOOL sm_qos_compare_r97aim_lt_r97(/*@in@*/T_M_SM_qos_r97 *aim_qos_r97, + /*@in@*/T_PS_qos_r97 *min_qos_r97, + /*@in@*/T_PS_qos_r97 *req_qos_r97 ) +{ + (void)TRACE_FUNCTION( "sm_qos_compare_r97aim_lt_r97"); + + /* Compare R97 AIM QoS with R97 parameter struct */ + if ( (min_qos_r97->delay != (U8)PS_DELAY_SUB && + aim_qos_r97->delay > min_qos_r97->delay ) || + (req_qos_r97->delay != (U8)PS_DELAY_SUB && + aim_qos_r97->delay < req_qos_r97->delay) ) + { + (void)TRACE_EVENT_P4("R97 DELAY parameter insufficient: " + "%d > %d (min_qos) || %d < %d (req_qos)", + aim_qos_r97->delay, min_qos_r97->delay, \ + aim_qos_r97->delay, req_qos_r97->delay); + return TRUE; + } + if ( (min_qos_r97->relclass != (U8)PS_RELCLASS_SUB && + aim_qos_r97->reliability > min_qos_r97->relclass) || + (req_qos_r97->relclass != (U8)PS_RELCLASS_SUB && + aim_qos_r97->reliability < req_qos_r97->relclass) && + /*the following line is for the TC 46.1.2.2.1.2*/ + !((aim_qos_r97->reliability ==2) && (req_qos_r97->relclass == 5)) ) + { + (void)TRACE_EVENT_P4("R97 RELIABILITY CLASS parameter insufficient: " + "%d > %d (min_qos) %d < %d (req_qos)", + aim_qos_r97->reliability, min_qos_r97->relclass, \ + aim_qos_r97->reliability, req_qos_r97->relclass); + return TRUE; + } + if ( (min_qos_r97->peak != (U8)PS_PEAK_SUB && + aim_qos_r97->peak < min_qos_r97->peak) || + (req_qos_r97->peak != (U8)PS_PEAK_SUB && + aim_qos_r97->peak > req_qos_r97->peak) ) + { + (void)TRACE_EVENT_P4("R97 PEAK BITRATE parameter insufficient: " + "%d < %d (min_qos) || %d > %d (req_qos)", + aim_qos_r97->peak, min_qos_r97->peak, \ + aim_qos_r97->peak, req_qos_r97->peak); + return TRUE; + } + if ( (min_qos_r97->preced != (U8)PS_PRECED_SUB && + aim_qos_r97->precedence > min_qos_r97->preced) || + (req_qos_r97->preced != (U8)PS_PRECED_SUB && + aim_qos_r97->precedence < req_qos_r97->preced)) + { + (void)TRACE_EVENT_P4("R97 PRECEDENCE CLASS parameter insufficient: " + "%d > %d (min_qos) || %d < %d (req_qos)", + aim_qos_r97->precedence, min_qos_r97->preced, \ + aim_qos_r97->precedence, req_qos_r97->preced); + return TRUE; + } + if ( (min_qos_r97->mean != (U8)PS_MEAN_SUB && + aim_qos_r97->mean < min_qos_r97->mean) || + (req_qos_r97->mean != (U8)PS_MEAN_SUB && + aim_qos_r97->mean > req_qos_r97->mean) ) + { + (void)TRACE_EVENT_P4("R97 MEAN BITRATE parameter insufficient: " + "%d < %d (min_qos) || %d > %d (req_qos)", + aim_qos_r97->mean, min_qos_r97->mean, \ + aim_qos_r97->mean, req_qos_r97->mean); + return TRUE; + } + + return FALSE; +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_compare_r99aim_lt_r99 ++------------------------------------------------------------------------------ +| Description : Compares an R99 air interface QoS structure with an R99 QoS +| structure in internal SM representation. Returns TRUE if +| AIM QoS is *less than* minimum QoS. +| Parameters : aim_qos_r99 - air interface QoS structure +| min_qos_r99 - minimum QoS structure ++------------------------------------------------------------------------------ +*/ +static BOOL sm_qos_compare_r99aim_lt_r99(/*@in@*/T_M_SM_qos_r99 *aim_qos_r99, + /*@in@*/T_PS_qos_r99 *min_qos_r99) +{ + (void)TRACE_FUNCTION( "sm_qos_compare_r99aim_lt_r99" ); + + /* Traffic class */ + if ((min_qos_r99->tc != (U8)PS_TC_SUB) && + (sm_qos_r99aim_to_tc(aim_qos_r99->tc) > min_qos_r99->tc)) + { + (void)TRACE_EVENT_P2("R99 TRAFFIC CLASS parameter insufficient: " + "%d > %d (min_qos)", + sm_qos_r99aim_to_tc(aim_qos_r99->tc), + min_qos_r99->tc); + return TRUE; + } + + /* Delivery order */ + if ((min_qos_r99->order != (U8)PS_ORDER_SUB) && + (sm_qos_r99aim_to_order(aim_qos_r99->order) != min_qos_r99->order)) + { + (void)TRACE_EVENT_P2("R99 DELIVERY ORDER parameter insufficient: " + "%d != %d (min_qos)", + sm_qos_r99aim_to_order(aim_qos_r99->order), + min_qos_r99->order); + return TRUE; + } + + /* Delivery of erroneous SDUs */ + if ((min_qos_r99->del_err_sdu != (U8)PS_DEL_ERR_SUB) && + (sm_qos_r99aim_to_del_err_sdu(aim_qos_r99->del_err_sdu) != min_qos_r99->del_err_sdu)) + { + (void)TRACE_EVENT_P2("R99 DELIVERY of ERRONEUOS SDUs parameter " + "insufficient: %d != %d (min_qos)", + sm_qos_r99aim_to_del_err_sdu(aim_qos_r99->del_err_sdu), + min_qos_r99->del_err_sdu); + return TRUE; + } + + /* Max SDU size */ + if ((min_qos_r99->max_sdu != (U16)PS_MAX_SDU_SUB) && + (sm_qos_r99aim_to_max_sdu(aim_qos_r99->max_sdu) < min_qos_r99->max_sdu)) + { + (void)TRACE_EVENT_P2("R99 MAX SDU SIZE parameter insufficient: " + "%d < %d (min_qos)", + sm_qos_r99aim_to_max_sdu(aim_qos_r99->max_sdu), + min_qos_r99->max_sdu); + return TRUE; + } + + /* Max uplink bit-rate */ + if ((min_qos_r99->max_rate_ul != (U16)PS_MAX_BR_UL_SUB) && + (sm_qos_r99aim_to_bitrate(aim_qos_r99->max_br_ul) < min_qos_r99->max_rate_ul)) + { + (void)TRACE_EVENT_P2("R99 MAX UPLINK BITRATE parameter insufficient: " + "%d < %d (min_qos)", + sm_qos_r99aim_to_bitrate(aim_qos_r99->max_br_ul), + min_qos_r99->max_rate_ul); + return TRUE; + } + + /* Max downlink bit-rate */ + if ((min_qos_r99->max_rate_dl != (U16)PS_MAX_BR_DL_SUB) && + (sm_qos_r99aim_to_bitrate(aim_qos_r99->max_br_dl) < min_qos_r99->max_rate_dl)) + { + (void)TRACE_EVENT_P2("R99 MAX DOWNLINK BITRATE parameter insufficient: " + "%d < %d (min_qos)", + sm_qos_r99aim_to_bitrate(aim_qos_r99->max_br_ul), + min_qos_r99->max_rate_dl); + return TRUE; + } + + /* Residual BER */ + if ((min_qos_r99->ber.ratio_exp != (U8)0 + && min_qos_r99->ber.ratio_mant != (U8)0) && + (sm_qos_r99aim_ratio_to_U32(sm_qos_ber_table, aim_qos_r99->ber) < + sm_qos_ratio_to_U32(min_qos_r99->ber.ratio_mant, + min_qos_r99->ber.ratio_exp))) + { +#ifdef DEBUG + U8 ratio_exp, ratio_mant; + sm_qos_r99aim_to_ratio(sm_qos_ber_table, aim_qos_r99->ber, + &ratio_mant, &ratio_exp); + (void)TRACE_EVENT_P4("R99 RESIDUAL BIT ERROR RATE parameter insufficient: " + "%dE-%d < %dE-%d (min_qos)", + ratio_mant, ratio_exp, + min_qos_r99->ber.ratio_mant, + min_qos_r99->ber.ratio_exp); +#endif + return TRUE; + } + + /* SDU error ratio */ + if ((min_qos_r99->sdu_err_ratio.ratio_exp != (U8)0 && + min_qos_r99->sdu_err_ratio.ratio_mant != (U8)0) && + (sm_qos_r99aim_ratio_to_U32(sm_qos_sdu_err_ratio_table, aim_qos_r99->sdu_err_ratio) < + sm_qos_ratio_to_U32(min_qos_r99->sdu_err_ratio.ratio_mant, + min_qos_r99->sdu_err_ratio.ratio_exp))) + { +#ifdef DEBUG + U8 ratio_exp, ratio_mant; + sm_qos_r99aim_to_ratio(sm_qos_sdu_err_ratio_table, + aim_qos_r99->sdu_err_ratio, + &ratio_mant, &ratio_exp); + (void)TRACE_EVENT_P4("R99 SDU ERROR RATIO parameter insufficient: " + "%dE-%d < %dE-%d (min_qos)", + ratio_mant, ratio_exp, + min_qos_r99->sdu_err_ratio.ratio_mant, + min_qos_r99->sdu_err_ratio.ratio_exp); +#endif + return TRUE; + } + + /* Transfer delay - Note! Only for real-time traffic class traffic! */ + if ((aim_qos_r99->tc == (U8)M_SM_QOS_TC_CONV + || aim_qos_r99->tc == (U8)M_SM_QOS_TC_STREAM) && + (min_qos_r99->xfer_delay != (U16)PS_XFER_DELAY_SUB) && + (sm_qos_r99aim_to_xfer_delay(aim_qos_r99->xfer_delay) > min_qos_r99->xfer_delay)) + { + (void)TRACE_EVENT_P2("R99 TRANSFER DELAY parameter insufficient: " + "%d > %d (min_qos)", + sm_qos_r99aim_to_xfer_delay(aim_qos_r99->xfer_delay), + min_qos_r99->xfer_delay); + return TRUE; + } + + /* Traffic handling priority - Note: Only interactive traffic class! */ + if ((aim_qos_r99->tc == (U8)M_SM_QOS_TC_INTER) && + (min_qos_r99->handling_pri != (U8)PS_HANDLING_PRI_SUB) && + (aim_qos_r99->handling_pri > min_qos_r99->handling_pri)) + { + (void)TRACE_EVENT_P2("R99 TRANSFER HANDLING PRIORITY parameter " + "insufficient: %d > %d (min_qos)", + aim_qos_r99->handling_pri, min_qos_r99->handling_pri); + return TRUE; + } + + /* Guaranteed uplink bit-rate - Note: Only for real-time traffic class traffic! */ + if ((aim_qos_r99->tc == (U8)M_SM_QOS_TC_CONV + || aim_qos_r99->tc == (U8)M_SM_QOS_TC_STREAM) && + (min_qos_r99->guar_br_ul != (U16)PS_GUAR_BR_UL_SUB) && + (sm_qos_r99aim_to_bitrate(aim_qos_r99->guar_br_ul) < min_qos_r99->guar_br_ul)) + { + (void)TRACE_EVENT_P2("R99 GUARANTEED UPLINK BITRATE parameter " + "insufficient: %d < %d (min_qos)", + sm_qos_r99aim_to_bitrate(aim_qos_r99->guar_br_ul), + min_qos_r99->guar_br_ul); + return TRUE; + } + + /* Guaranteed downlink bit-rate - Note: Only for real-time traffic class traffic! */ + if ((aim_qos_r99->tc == (U8)M_SM_QOS_TC_CONV + || aim_qos_r99->tc == (U8)M_SM_QOS_TC_STREAM) && + (min_qos_r99->guar_br_dl != (U16)PS_GUAR_BR_DL_SUB) && + (sm_qos_r99aim_to_bitrate(aim_qos_r99->guar_br_dl) < min_qos_r99->guar_br_dl)) + { + (void)TRACE_EVENT_P2("R99 GUARANTEED DOWNLINK BITRATE parameter " + "insufficient: %d < %d (min_qos)", + sm_qos_r99aim_to_bitrate(aim_qos_r99->guar_br_dl), + min_qos_r99->guar_br_dl); + return TRUE; + } + + return FALSE; +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_is_minimum_satisfied_by_aim ++------------------------------------------------------------------------------ +| Description : Main comparison function. Compares a 3G air interface message +| QoS parameter set (R97 or R99) with the minimum QoS parameter +| set in context data. +| Returns TRUE if the 3G air message parameters are greater than +| or equal to the minimum parameters in SM representation +| ("greater than" is different for each value). +| +| Parameters : context - Context data +| aim_qos - air interface QoS structure ++------------------------------------------------------------------------------ +*/ +BOOL sm_qos_is_minimum_satisfied_by_aim(struct T_SM_CONTEXT_DATA *context, + T_M_SM_qos *aim_qos) +{ + BOOL less_than = TRUE; + +#ifdef DEBUG_VERBOSE + (void)TRACE_FUNCTION( "sm_qos_is_minimum_satisfied_by_aim"); +#endif + /*lint -e613 (Possible use of null pointer 'context' in left argument to operator '->') */ + TRACE_ASSERT(context != NULL); + + if (context->minimum_qos.ctrl_qos == PS_is_qos_not_present) { + /* Accept QoS without any checking */ + return TRUE; + } + if (context->minimum_qos.ctrl_qos == PS_is_R97) { + T_PS_qos_r97 *min_qos = &context->minimum_qos.qos.qos_r97; + T_PS_qos_r97 *req_qos = &context->requested_qos.qos.qos_r97; + if (aim_qos->v_qos_r99 == (U8)FALSE) { + less_than = sm_qos_compare_r97aim_lt_r97(&aim_qos->qos_r97, min_qos, + req_qos); + } else { + + /* This #if.. #else part is required because we currently do not set + * RAT when MMPM_ATTACH_IND is received. When the RAT is set properly + * retain ONLY the #else part. + */ +/*#ifdef SM_EDGE */ /*ONLY FOR GPRS WORLD*/ + /*In GPRS world try comparing only R97 part of QoS*/ + TRACE_EVENT("GSM/GPRS RAT.. Comparing only R97 part of QoS."); + less_than = sm_qos_compare_r97aim_lt_r97(&aim_qos->qos_r97, min_qos, + req_qos); +#if 0 + /*#else*/ /*FOR UMTS and DUAL-MODE*/ + if (sm_get_current_rat() == PS_RAT_GSM){ + /*In GPRS world compare only R97 part of QoS*/ + TRACE_EVENT("GSM/GPRS RAT.. Comparing only R97 part of QoS."); + less_than = sm_qos_compare_r97aim_lt_r97(&aim_qos->qos_r97, min_qos, + req_qos); + } else { /*We should be in UMTS world now..*/ + T_PS_qos_r99 tmp_qos; + TRACE_EVENT("Calling cl_qos_convert_r97_to_r99() for min qos"); + cl_qos_convert_r97_to_r99(&context->minimum_qos.qos.qos_r97, &tmp_qos); + TRACE_EVENT("UMTS RAT.. Comparing only R99 part of QoS."); + less_than = sm_qos_compare_r99aim_lt_r99(&aim_qos->qos_r99, &tmp_qos); + } + /*#endif*/ +#endif + + } + } + else if (context->minimum_qos.ctrl_qos == PS_is_R99) { + T_PS_qos_r99 tmp_qos; + if (aim_qos->v_qos_r99 == (U8)FALSE) { + cl_qos_convert_r97_to_r99(&context->minimum_qos.qos.qos_r97, &tmp_qos); + } + else { + memcpy(&tmp_qos, &context->minimum_qos.qos.qos_r99, sizeof(T_PS_qos_r99)); + } + + less_than = sm_qos_compare_r99aim_lt_r99(&aim_qos->qos_r99, &tmp_qos); + } else { /* if (context->ctrl_minimum_qos) */ + (void)TRACE_EVENT_P1("ERROR! Invalid union controller == %d in minimum QoS!", + context->minimum_qos.ctrl_qos); + } + + return !less_than; +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_is_minimum_satisfied_by_aim ++------------------------------------------------------------------------------ +| Description : Comparison function. Compares a the minimum QoS parameter set +| configured in context data with another QoS structure in +| internal SM representation. Returns TRUE if the comparison QoS +| parameters are greater than or equal to the minimum parameters. +| ("greater than" is different for each value). +| +| Parameters : context - Context data +| sm_qos - comparison QoS structure ++------------------------------------------------------------------------------ +*/ +BOOL sm_qos_is_minimum_satisfied_by_sm(struct T_SM_CONTEXT_DATA *context, + T_SM_qos *sm_qos) +{ + BOOL less_than = TRUE; + +#ifdef DEBUG_VERBOSE + (void)TRACE_FUNCTION( "sm_qos_is_minimum_satisfied_by_sm"); +#endif + /*lint -e613 (Possible use of null pointer 'context' in left argument to operator '->') */ + TRACE_ASSERT(context != NULL); + + if (context->minimum_qos.ctrl_qos == PS_is_qos_not_present) { + /* Accept QoS without any checking */ + return TRUE; + } + if (context->minimum_qos.ctrl_qos == PS_is_R97) { + T_PS_qos_r97 *min_qos = &context->minimum_qos.qos.qos_r97; + if (sm_qos->ctrl_qos == PS_is_R97) { + /* + less_than = sm_qos_compare_r97_lt_r97(&sm_qos->qos.qos_r97, min_qos); + * Construct not used, as this function is called only during + * MO modify procedures, which is a R99 feature. + */ + less_than = FALSE; + } else { + T_PS_qos_r99 tmp_qos; + cl_qos_convert_r97_to_r99(min_qos, &tmp_qos); + + less_than = sm_qos_compare_r99_lt_r99(&sm_qos->qos.qos_r99, &tmp_qos); + } + } else if (context->minimum_qos.ctrl_qos == PS_is_R99) { + T_PS_qos_r99 *min_qos = &context->minimum_qos.qos.qos_r99; + if (sm_qos->ctrl_qos == PS_is_R97) { + T_PS_qos_r99 tmp_qos; + cl_qos_convert_r97_to_r99(&sm_qos->qos.qos_r97, &tmp_qos); + + less_than = sm_qos_compare_r99_lt_r99(&tmp_qos, min_qos); + } else { + less_than = sm_qos_compare_r99_lt_r99(&sm_qos->qos.qos_r99, min_qos); + } + } else { + (void)TRACE_EVENT_P1("ERROR! Invalid union controller == %d in minimum QoS!", + context->minimum_qos.ctrl_qos); + } + + + return !less_than; +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_copy_from_sm ++------------------------------------------------------------------------------ +| Description : Copy QoS structure and union controller from context data to +| another QoS structure (in a primitive etc). +| +| Parameters : dst - Destination QoS structure +| src - Source QoS structure +| dctrl - Destination union controller ++------------------------------------------------------------------------------ +*/ +void sm_qos_copy_from_sm(T_PS_qos *dst, T_SM_qos *src, T_PS_ctrl_qos *dctrl) +{ + *dctrl = src->ctrl_qos; + memcpy(dst, &src->qos, sizeof(T_PS_qos)); +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_copy_to_sm ++------------------------------------------------------------------------------ +| Description : Copy QoS structure and union controller from e.g. a primitive +| to context data. +| +| Parameters : dst - Destination QoS structure (in context data) +| src - Source QoS structure +| ctrl - Source union controller ++------------------------------------------------------------------------------ +*/ +void sm_qos_copy_to_sm(T_SM_qos *dst, T_PS_qos *src, T_PS_ctrl_qos ctrl) +{ + dst->ctrl_qos = ctrl; + memcpy(&dst->qos, src, sizeof(T_PS_qos)); +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_is_requested_qos_present ++------------------------------------------------------------------------------ +| Description : Returns TRUE if requested QoS element is present. +| +| Parameters : context - Context data ++------------------------------------------------------------------------------ +*/ +BOOL sm_qos_is_requested_qos_present(struct T_SM_CONTEXT_DATA *context) +{ + /*lint -e613 (Possible use of null pointer 'context' in left argument to operator '->') */ + TRACE_ASSERT(context != NULL); + + return (context->requested_qos.ctrl_qos != PS_is_qos_not_present); +} + +/* ++------------------------------------------------------------------------------ +| Function : sm_rank_del_contexts_based_on_tc ++------------------------------------------------------------------------------ +| Description : Ranks all contexts linked to a pdp address based on traffic +| class and traffic handling priority. Locally deactivates all +| but the best ranking context. Informs ACI about the deactivation. +| Also sends a pdp context status request to GMM. +| Reference 23.107 Annex C +| +| Parameters : None ++------------------------------------------------------------------------------ +*/ +#ifdef TI_PS_OP_SM_RETAIN_BEST_CONTEXT + +U16 sm_rank_del_contexts_based_on_tc() +{ + U8 nsapi = 0; + U8 temp_ti = 0; + U8 count = 0; + U8 temp_nsapi = 0; + U16 context_ti = 0; + U16 linked_contexts = 0; + U8 best_qos_rank = SM_HIGH_VALUE; /*Initialize with a high value*/ + U16 nsapis_to_deactivate = 0; + + for (nsapi=(int)NAS_NSAPI_5; nsapi < NAS_SIZE_NSAPI; nsapi++) + { + struct T_SM_CONTEXT_DATA *context; + struct T_SM_CONTEXT_DATA *temp_context; + + context = sm_get_context_data_from_nsapi(nsapi); + /* The context_control_state is checked to see if the context is already + * getting deactivated + */ + if ( context != NULL && + (context->context_control_state != SM_CONTEXT_DEACTIVATED) ) + { + if (sm_is_secondary(context)) + { + context_ti = context->linked_ti; + } else { + context_ti = context->ti; + } + linked_contexts = sm_add_nsapi_to_nsapi_set(nsapi, linked_contexts); + count = 1; /*One context is already active*/ + /*Rank this context. May be needed if linked contexts are active*/ + context->qos_rank = sm_qos_rank_context(context->ti); + if (context->qos_rank < best_qos_rank) { + best_qos_rank = context->qos_rank; + } + } else { /*Go to the next nsapi*/ + continue; + } + /* One context active. Check all the remaining active contexts */ + for (temp_nsapi=nsapi; temp_nsapi < NAS_SIZE_NSAPI; temp_nsapi++) + { + temp_context = sm_get_context_data_from_nsapi(temp_nsapi); + if(temp_context != NULL && temp_context->context_control_state + != SM_CONTEXT_DEACTIVATED) + { + if (sm_is_secondary(temp_context)) + { + temp_ti = temp_context->linked_ti; + } else { + temp_ti = temp_context->ti; + } + if ( (temp_nsapi != nsapi) && (temp_ti == context_ti) ) + { + linked_contexts = sm_add_nsapi_to_nsapi_set(temp_nsapi, + linked_contexts); + count++; + /*A second context active. Rank it. Pass the ti of the context*/ + temp_context->qos_rank = sm_qos_rank_context(temp_context->ti); + if (temp_context->qos_rank < best_qos_rank) { + best_qos_rank = temp_context->qos_rank; + } + } + } + } + + if (count >=2 ) + { + for (temp_nsapi=(int)NAS_NSAPI_5; temp_nsapi<NAS_SIZE_NSAPI; temp_nsapi++) + { + struct T_SM_CONTEXT_DATA *context; + if( (linked_contexts & (0x0001 << temp_nsapi)) != 0 ) + { + context = sm_get_context_data_from_nsapi(temp_nsapi); + if ( (context->qos_rank > best_qos_rank) && (context != NULL) + && (context->context_control_state != SM_CONTEXT_DEACTIVATED) ) + { + (void)TRACE_EVENT_P1("Deactivating nsapi >>TC based << %d; ", temp_nsapi); + /*deactivate the context*/ + nsapis_to_deactivate = sm_add_nsapi_to_nsapi_set(temp_nsapi, + nsapis_to_deactivate); + /* Make sure to clear the pending reactivation flag */ + sm_set_context_pending_reactivation(context, FALSE); + /* Order context deactivation */ + sm_context_control(context, SM_I_CONTEXT_LOCAL_DEACTIVATE, + (void *)TRUE); + } + } + } + } + } + +return nsapis_to_deactivate; +} +#endif /*#ifdef TI_PS_OP_SM_RETAIN_BEST_CONTEXT*/ + + +/* ++------------------------------------------------------------------------------ +| Function : sm_qos_rank_context ++------------------------------------------------------------------------------ +| Description : Provides a rank for the context based on the tc and handling pri +| Reference 23.107 Annex C +| +| Parameters : context ti ++------------------------------------------------------------------------------ +*/ +#ifdef TI_PS_OP_SM_RETAIN_BEST_CONTEXT + +U8 sm_qos_rank_context(U16 ti) +{ + struct T_SM_CONTEXT_DATA *context; + T_PS_qos_r99 temp_qos; + U8 qos_rank = 0; + + context = sm_get_context_data_from_ti(ti); + + if(context->accepted_qos.ctrl_qos == PS_is_R97) + { /*R97 QoS. Convert to R99 QoS before ranking*/ + (void)cl_qos_convert_r97_to_r99(&context->accepted_qos.qos.qos_r97, + &temp_qos); + } else + { + temp_qos = context->accepted_qos.qos.qos_r99; + } + + switch(temp_qos.tc) + { + case PS_TC_INTER: + switch(temp_qos.handling_pri) + { + case PS_HANDLING_PRI_1: + qos_rank = 1; + break; + case PS_HANDLING_PRI_2: + qos_rank = 4; + break; + case PS_HANDLING_PRI_3: + qos_rank = 5; + break; + } + break; + case PS_TC_CONV: + qos_rank = 2; + break; + case PS_TC_STREAM: + qos_rank = 3; + break; + case PS_TC_BG: + qos_rank = 6; + break; + default: + qos_rank = 6; + break; + } + return qos_rank; +} +#endif /*#ifdef TI_PS_OP_SM_RETAIN_BEST_CONTEXT*/ + +/* ++------------------------------------------------------------------------------ +| Function : sm_retain_cntxt_wth_best_bitrate ++------------------------------------------------------------------------------ +| Description : Deactivates all the linked pdp contexts except the one with +| highest max bit rate uplink or downlink. Informs ACI about the +| deactivation. +| Also sends a pdp context status request to GMM. +| Reference 23.107 Annex C +| +| Parameters : None ++------------------------------------------------------------------------------ +*/ +#ifdef TI_PS_OP_SM_RETAIN_BEST_CONTEXT + +U16 sm_retain_cntxt_wth_best_bitrate() +{ + U8 nsapi = 0; + U8 temp_nsapi = 0; + U8 count = 0; + U16 linked_contexts = 0; + U16 best_max_bitrate = 0; + U16 nsapis_to_deactivate = 0; + U16 context_ti = 0; + U16 temp_ti = 0; + T_PS_qos_r99 temp_qos; + + + for (nsapi = (int)NAS_NSAPI_5; nsapi < NAS_SIZE_NSAPI; nsapi++) + { + struct T_SM_CONTEXT_DATA *context; + struct T_SM_CONTEXT_DATA *temp_context; + + context = sm_get_context_data_from_nsapi(nsapi); + if ( (context != NULL) && (context->context_control_state + != SM_CONTEXT_DEACTIVATED) ) + { + if (sm_is_secondary(context)) + { + context_ti = context->linked_ti; + } else { + context_ti = context->ti; + } + linked_contexts = sm_add_nsapi_to_nsapi_set(nsapi, linked_contexts); + count = 1; /*One context is already active*/ + } else { /* Process the next nsapi */ + continue; + } + + for(temp_nsapi=nsapi; temp_nsapi < NAS_SIZE_NSAPI; temp_nsapi++) + { + temp_context = sm_get_context_data_from_nsapi(temp_nsapi); + if(temp_context != NULL && temp_context->context_control_state + != SM_CONTEXT_DEACTIVATED) + { + if (sm_is_secondary(temp_context)) + { + temp_ti = temp_context->linked_ti; + } else { + temp_ti = temp_context->ti; + } + if ( (temp_nsapi != nsapi) && (temp_ti == context_ti) ) + { + linked_contexts = sm_add_nsapi_to_nsapi_set(temp_nsapi, + linked_contexts); + count++; + } + } + } + + if (count >=2) + { /*Multiple contexts active for this ti. Find the best_max_bit rate.*/ + (void)TRACE_EVENT( "Multiple contexts active: sm_retain_cntxt_wth_best_bitrate" ); + for (temp_nsapi=(int)NAS_NSAPI_5; temp_nsapi < NAS_SIZE_NSAPI; temp_nsapi++) + { + if( (linked_contexts & (0x0001 << temp_nsapi)) != 0 ) + { + context = sm_get_context_data_from_nsapi(temp_nsapi); + if(context->accepted_qos.ctrl_qos == PS_is_R97) + { /*R97 QoS. Convert to R99 QoS before ranking*/ + (void)cl_qos_convert_r97_to_r99(&context->accepted_qos.qos.qos_r97, + &temp_qos); + } else { + temp_qos = context->accepted_qos.qos.qos_r99; + } + if (temp_qos.max_rate_dl >= best_max_bitrate) + { + best_max_bitrate = temp_qos.max_rate_dl; + } else if (temp_qos.max_rate_ul >= best_max_bitrate) { + best_max_bitrate = temp_qos.max_rate_ul; + } + } + } + + } + + if (count >=2) + { + for (temp_nsapi=(int)NAS_NSAPI_5; temp_nsapi < NAS_SIZE_NSAPI; temp_nsapi++) + { + if( (linked_contexts & (0x0001 << temp_nsapi)) != 0 ) + { + context = sm_get_context_data_from_nsapi(temp_nsapi); + if(context->accepted_qos.ctrl_qos == PS_is_R97) + { /*R97 QoS. Convert to R99 QoS before ranking*/ + (void)cl_qos_convert_r97_to_r99(&context->accepted_qos.qos.qos_r97, + &temp_qos); + } else { + temp_qos = context->accepted_qos.qos.qos_r99; + } + if ( (temp_qos.max_rate_dl == best_max_bitrate) || + (temp_qos.max_rate_ul == best_max_bitrate) ) + { + /* Don't do anything */ + } + else /* Deactivate the context */ + { + (void)TRACE_EVENT_P1("Deactivating nsapi << bit rate based >> %d; ", temp_nsapi); + /*Deactivate the context*/ + nsapis_to_deactivate = sm_add_nsapi_to_nsapi_set(temp_nsapi, + nsapis_to_deactivate); + /* Make sure to clear the pending reactivation flag */ + sm_set_context_pending_reactivation(context, FALSE); + /* Order context deactivation */ + sm_context_control(context, SM_I_CONTEXT_LOCAL_DEACTIVATE, + (void *)TRUE); + } + } + } + } + + } + return nsapis_to_deactivate; +} + +#endif /*#ifdef TI_PS_OP_SM_RETAIN_BEST_CONTEXT*/ + +/* ++------------------------------------------------------------------------------ +| Function : sm_retain_cntxt_with_least_nsapi ++------------------------------------------------------------------------------ +| Description : Deactivates all the linked pdp contexts except the one with +| least nsapi value. Informs ACI about the deactivation. +| Also sends a pdp context status request to GMM. +| Reference 23.107 Annex C +| +| Parameters : None ++------------------------------------------------------------------------------ +*/ +#ifdef TI_PS_OP_SM_RETAIN_BEST_CONTEXT + +U16 sm_retain_cntxt_with_least_nsapi() +{ + struct T_SM_CONTEXT_DATA *context; + struct T_SM_CONTEXT_DATA *temp_context; + U8 nsapi = 0; + U8 temp_nsapi = 0; + U16 linked_contexts = 0; + U16 nsapis_to_deactivate = 0; + U16 best_max_bitrate = 0; + U8 min_nsapi = SM_HIGH_VALUE; /*Initialize to a high value. Here 255*/ + U8 count = 0; + U16 context_ti,temp_ti = 0; + + + for (nsapi = (int)NAS_NSAPI_5; nsapi < NAS_SIZE_NSAPI; nsapi++) + { + context = sm_get_context_data_from_nsapi(nsapi); + if ( (context != NULL) && (context->context_control_state != + SM_CONTEXT_DEACTIVATED) ) + { + if (sm_is_secondary(context)) + { + context_ti = context->linked_ti; + } else { + context_ti = context->ti; + } + linked_contexts = sm_add_nsapi_to_nsapi_set(nsapi, linked_contexts); + count = 1; /*One context is already active*/ + } else { /*Go to the next nsapi*/ + continue; + } + + /* Check all the remaining active contexts */ + for (temp_nsapi=nsapi; temp_nsapi < NAS_SIZE_NSAPI; temp_nsapi++) + { + temp_context = sm_get_context_data_from_nsapi(temp_nsapi); + if(temp_context != NULL && temp_context->context_control_state + != SM_CONTEXT_DEACTIVATED) + { + if (sm_is_secondary(temp_context)) + { + temp_ti = temp_context->linked_ti; + } else { + temp_ti = temp_context->ti; + } + if ( (temp_nsapi != nsapi) && (temp_ti == context_ti) ) + { + linked_contexts = sm_add_nsapi_to_nsapi_set(temp_nsapi, + linked_contexts); + count++; + } + } + } + + + if (count >= 2) + { /*Multiple contexts active for this ti. Try deactivating.*/ + (void)TRACE_EVENT( "Multiple contexts active: sm_retain_cntxt_with_least_nsapi" ); + for (temp_nsapi=(int)NAS_NSAPI_5; temp_nsapi<NAS_SIZE_NSAPI; temp_nsapi++) + { + if( (linked_contexts & (0x0001 << temp_nsapi)) != 0 ) + { + temp_context = sm_get_context_data_from_nsapi(temp_nsapi); + if ((min_nsapi == SM_HIGH_VALUE) && (temp_context != NULL) && + (temp_context->context_control_state != SM_CONTEXT_DEACTIVATED) ) + { + min_nsapi = temp_nsapi; + } else + { + (void)TRACE_EVENT_P1("Deactivating nsapi >>nsapi based << %d; ", temp_nsapi); + /*Deactivate the context*/ + nsapis_to_deactivate = sm_add_nsapi_to_nsapi_set(temp_nsapi, + nsapis_to_deactivate); + /* Make sure to clear the pending reactivation flag */ + sm_set_context_pending_reactivation(temp_context, FALSE); + /* Order context deactivation */ + sm_context_control(temp_context, SM_I_CONTEXT_LOCAL_DEACTIVATE, + (void *)TRUE); + } + } + } + } + } + return nsapis_to_deactivate; +} + +#endif /*#ifdef TI_PS_OP_SM_RETAIN_BEST_CONTEXT*/ +