FreeCalypso > hg > fc-magnetite
view src/g23m-gprs/sm/sm_tft.c @ 638:cab2f315827e
FFS dev.c: added Spansion PL032J to the "generic" table
With the discovery of first GTM900 and then Tango, it now appears that
Openmoko was not the only manuf after all who kept TI's TCS211 firmware
largely intact (as opposed to changing it beyond all recognition like
Compal, Chi-Mei and BenQ did), thus we are now getting new "alien" targets
on which we reuse the original manuf's FFS with IMEI and RF calibration
tables as if it were native. On these targets we use the original
device table for FFS, even though we previously thought that it would
never apply to any target other than dsample, leonardo and gtamodem.
We have previously added Samsung K5L33xxCAM (a new kind of multi-ID device)
to the generic table to support its use in Huawei GTM900-B modules; now
we got news that some slightly older GTM900-B specimen used S71PL032J
instead, so we are now adding PL032J as well.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 30 Jan 2020 17:45:48 +0000 |
parents | 219afcfc6250 |
children |
line wrap: on
line source
/*---------------------------------------------------------------------------- | 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 TFT utility functions implementation in the SM entity. | For design details, see: | 8010.908 SM Detailed Specification +---------------------------------------------------------------------------*/ /*==== DECLARATION CONTROL =================================================*/ /*==== INCLUDES ============================================================*/ #include "sm.h" #include "sm_tft.h" /*==== CONST ===============================================================*/ /*==== LOCAL VARS ===========================================================*/ /*==== PRIVATE FUNCTIONS ====================================================*/ /* +------------------------------------------------------------------------------ | Function : sm_tft_count_tfts_in_mask +------------------------------------------------------------------------------ | Description : Returns the number of filters (set bits) in a TFT mask. | | Parameters : tft_mask - TFT mask +------------------------------------------------------------------------------ */ static U8 sm_tft_count_tfts_in_mask(U8 tft_mask) /*@*/ { U8 count_array[16] = { (U8)0 /* 0000 */, (U8)1 /* 0001 */, (U8)1 /* 0010 */, (U8)2 /* 0011 */, (U8)1 /* 0100 */, (U8)2 /* 0101 */, (U8)2 /* 0110 */, (U8)3 /* 0111 */, (U8)1 /* 1000 */, (U8)2 /* 1001 */, (U8)2 /* 1010 */, (U8)3 /* 1011 */, (U8)2 /* 1100 */, (U8)3 /* 1101 */, (U8)3 /* 1110 */, (U8)4 /* 1111 */ }; return (count_array[(U16)tft_mask >> 4] + count_array[(U16)tft_mask & 15]); } /* +------------------------------------------------------------------------------ | Function : sm_tft_is_tft_in_mask +------------------------------------------------------------------------------ | Description : Returns TRUE if the TFT with the specified ID (bit) is | set in the specified TFT mask. | | Parameters : id - TFT identifier | tft_mask - TFT mask +------------------------------------------------------------------------------ */ static BOOL sm_tft_is_tft_in_mask(U8 id, U8 tft_mask) /*@*/ { return ((tft_mask & (1UL << id)) != 0); } /* +------------------------------------------------------------------------------ | Function : sm_tft_is_port_range +------------------------------------------------------------------------------ | Description : Query function returning TRUE if high_limit is not zero, and | high_limit is greater than (but not equal) to low_limit. | | Parameters : low_limit - lower port limit | high_limit - upper port limit +------------------------------------------------------------------------------ */ static BOOL sm_tft_is_port_range(U16 low_limit, U16 high_limit) { return (high_limit != 0 && low_limit < high_limit); } static /*@exposed@*/T_NAS_tft_pf * sm_tft_get_active_tft_by_id(/*@returned@*/ /*@partial@*/struct T_SM_CONTEXT_DATA *context, U8 id) { TRACE_ASSERT(id < (U8)NAS_SIZE_TFT_FILTER); TRACE_ASSERT(context->active_tft.ptr_tft_pf != NULL); return (&context->active_tft.ptr_tft_pf[id]); } /* +------------------------------------------------------------------------------ | Function : sm_tft_pf_size +------------------------------------------------------------------------------ | Description : Query function returning the packed size of a packet filter. | | Parameters : tft_pf - packet filter +------------------------------------------------------------------------------ */ static U16 sm_tft_pf_size(T_NAS_tft_pf *tft_pf) { U16 tft_pf_size = (U16)3; /* Filter ID, precedence and length octet mandatory */ U16 lower3bits[8] = { (U16) 0, /* 0x00: None */ (U16) 9, /* 0x01: IPv4_SRC_ADDR_MASK */ (U16) 33, /* 0x02: IPv6_SRC_ADDR_MASK */ (U16) 0, /* 0x03: IPv4_SRC_ADDR_MASK + IPv6_SRC_ADDR_MASK -- INVALID! */ (U16) 3, /* 0x04: PROTOCOL_OR_NEXT_HDR */ (U16) 12, /* 0x05: IPv4_SRC_ADDR_MASK + PROTOCOL_OR_NEXT_HDR */ (U16) 36, /* 0x06: IPv6_SRC_ADDR_MASK + PROTOCOL_OR_NEXT_HDR */ (U16) 0 /* 0x07: IPv4_SRC_ADDR_MASK + IPv6_SRC_ADDR_MASK + PROTOCOL_OR_NEXT_HDR -- INVALID! */ }; U16 upper3bits[8] = { (U16) 0, /* 0x00: None */ (U16) 5, /* 0x20: IPSEC_SPI */ (U16) 3, /* 0x40: TOS_AND_MASK */ (U16) 5, /* 0x60: IPSEC_SPI + TOS_AND_MASK */ (U16) 4, /* 0x80: FLOW_LABEL */ (U16) 0, /* 0xa0: IPSEC_SPI + FLOW_LABEL - INVALID! */ (U16) 7, /* 0xc0: TOS_AND_MASK + FLOW_LABEL */ (U16) 0 /* 0xe0: IPSEC_SPI + TOS_AND_MASK + FLOW_LABEL - INVALID! */ }; if ((tft_pf->tft_pf_valid_bits & (U8)0x07) != (U8)0) { tft_pf_size += lower3bits[(U16)tft_pf->tft_pf_valid_bits & 0x07]; } if ((tft_pf->tft_pf_valid_bits & (U8)0xe0) != (U8)0) { tft_pf_size += upper3bits[(U16)tft_pf->tft_pf_valid_bits >> 5]; } if ((tft_pf->tft_pf_valid_bits & (U8)NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0) { T_NAS_tft_dest_port_range *range = &tft_pf->tft_pf_entry.tft_pf_ipv4.tft_dest_port_range; if (sm_tft_is_port_range(range->low_limit, range->high_limit)) { tft_pf_size += (U16)5; /* Destination port range */ } else { tft_pf_size += (U16)3; /* Single destination port */ } } if ((tft_pf->tft_pf_valid_bits & (U8)NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0) { T_NAS_tft_src_port_range *range = &tft_pf->tft_pf_entry.tft_pf_ipv4.tft_src_port_range; if (sm_tft_is_port_range(range->low_limit, range->high_limit)) { tft_pf_size += (U16)5; /* Source port range */ } else { tft_pf_size += (U16)3; /* Single source port */ } } return tft_pf_size; } /* +------------------------------------------------------------------------------ | Function : sm_tft_are_equal +------------------------------------------------------------------------------ | Description : Query function returning TRUE if the two input packet filters | are equal (same parameters). | | Parameters : tft1 - packet filter 1 | tft2 - packet filter 2 +------------------------------------------------------------------------------ */ static BOOL sm_tft_are_equal(T_NAS_tft_pf *tft1, T_NAS_tft_pf *tft2) { U8 valid_bits; /* Compare outer-level parameters */ if (tft1->tft_pf_id != tft2->tft_pf_id || tft1->tft_pf_precedence != tft2->tft_pf_precedence || tft1->tft_pf_valid_bits != tft2->tft_pf_valid_bits || tft1->ctrl_tft_pf_entry != tft2->ctrl_tft_pf_entry) { return FALSE; } valid_bits = tft1->tft_pf_valid_bits; if (tft1->ctrl_tft_pf_entry == NAS_is_tft_pf_ipv4) { T_NAS_tft_pf_ipv4 *v4_pf_1 = &tft1->tft_pf_entry.tft_pf_ipv4; T_NAS_tft_pf_ipv4 *v4_pf_2 = &tft2->tft_pf_entry.tft_pf_ipv4; if (((valid_bits & (U8)NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR) != (U8)0 && v4_pf_1->tft_protocol != v4_pf_2->tft_protocol) || ((valid_bits & (U8)NAS_TFT_ID_TOS_AND_MASK) != (U8)0 && v4_pf_1->tft_tos_and_mask.tos_value != v4_pf_2->tft_tos_and_mask.tos_value && v4_pf_1->tft_tos_and_mask.tos_mask != v4_pf_2->tft_tos_and_mask.tos_mask) || ((valid_bits & (U8)NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0 && memcmp(&v4_pf_1->tft_dest_port_range, &v4_pf_2->tft_dest_port_range, sizeof(T_NAS_tft_dest_port_range)) != 0) || ((valid_bits & (U8)NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0 && memcmp(&v4_pf_1->tft_src_port_range, &v4_pf_2->tft_src_port_range, sizeof(T_NAS_tft_src_port_range)) != 0) || ((valid_bits & (U8)NAS_TFT_ID_IPSEC_SPI) != (U8)0 && v4_pf_1->tft_ipsec_spi != v4_pf_2->tft_ipsec_spi) || ((valid_bits & (U8)NAS_TFT_ID_IPv4_SRC_ADDR_MASK) != (U8)0 && memcmp(&v4_pf_1->tft_ipv4_src_addr_mask, &v4_pf_2->tft_ipv4_src_addr_mask, sizeof(T_NAS_tft_ipv4_src_addr_mask)) != 0)) { return FALSE; } } else if (tft1->ctrl_tft_pf_entry == NAS_is_tft_pf_ipv6) { T_NAS_tft_pf_ipv6 *v6_pf_1 = &tft1->tft_pf_entry.tft_pf_ipv6; T_NAS_tft_pf_ipv6 *v6_pf_2 = &tft2->tft_pf_entry.tft_pf_ipv6; if (((valid_bits & (U8)NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR) != (U8)0 && v6_pf_1->tft_next_hdr != v6_pf_2->tft_next_hdr) || ((valid_bits & (U8)NAS_TFT_ID_TOS_AND_MASK) != (U8)0 && v6_pf_1->tft_tos_and_mask.tos_value != v6_pf_2->tft_tos_and_mask.tos_value && v6_pf_1->tft_tos_and_mask.tos_mask != v6_pf_2->tft_tos_and_mask.tos_mask) || ((valid_bits & (U8)NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0 && memcmp(&v6_pf_1->tft_dest_port_range, &v6_pf_2->tft_dest_port_range, sizeof(T_NAS_tft_dest_port_range)) != 0) || ((valid_bits & (U8)NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0 && memcmp(&v6_pf_1->tft_src_port_range, &v6_pf_2->tft_src_port_range, sizeof(T_NAS_tft_src_port_range)) != 0) || ((valid_bits & (U8)NAS_TFT_ID_IPSEC_SPI) != (U8)0 && v6_pf_1->tft_ipsec_spi != v6_pf_2->tft_ipsec_spi) || ((valid_bits & (U8)NAS_TFT_ID_FLOW_LABEL) != (U8)0 && v6_pf_1->tft_flow_label != v6_pf_2->tft_flow_label) || ((valid_bits & (U8)NAS_TFT_ID_IPv6_SRC_ADDR_MASK) != (U8)0 && memcmp(&v6_pf_1->tft_ipv6_src_addr_mask, &v6_pf_2->tft_ipv6_src_addr_mask, sizeof(T_NAS_tft_ipv6_src_addr_mask)) != 0)) { return FALSE; } } else { (void)TRACE_EVENT_P1("ERROR: Invalid union controller %d in ctrl_tft_pf_entry!", tft1->ctrl_tft_pf_entry); } return TRUE; } /* +------------------------------------------------------------------------------ | Function : sm_tft_copy_ipv4_pf +------------------------------------------------------------------------------ | Description : Copies an IPv4 TFT filter from src_tft to dst_tft AIM struct. | | Parameters : dst_tft - destination aim TFT structs | src_tft - source TFT structs | valid_flag - valid flags for filter components +------------------------------------------------------------------------------ */ static void sm_tft_copy_ipsec_spi(/*@out@*/T_M_SM_tft_ipsec_spi *dst_spi, U32 spi) { M_SM_BUF_ipsec_spi_value *dst = &dst_spi->ipsec_spi_value; #ifdef TFT_DEBUG (void)TRACE_EVENT_P1("tft_copy: Copying IPSEC SPI filter (SPI 0x%08x)", spi); #endif dst->l_ipsec_spi_value = (U16)32; dst->o_ipsec_spi_value = (U16)0; dst->b_ipsec_spi_value[0] = (U8)((spi >> 24) & 255); dst->b_ipsec_spi_value[1] = (U8)((spi >> 16) & 255); dst->b_ipsec_spi_value[2] = (U8)((spi >> 8) & 255); dst->b_ipsec_spi_value[3] = (U8)( spi & 255); } static void sm_tft_copy_ipv4_pf(/*@out@*/ T_M_SM_tft_filter_entry *dst, T_NAS_tft_pf_ipv4 *src, U8 valid_flag) { /* Copy IPv4 address, if present */ if ((valid_flag & NAS_TFT_ID_IPv4_SRC_ADDR_MASK) != (U8)0) { dst->v_tft_ipv4_addr_mask = (U8)TRUE; memcpy(dst->tft_ipv4_addr_mask.src_addr, src->tft_ipv4_src_addr_mask.tft_ipv4_addr, (size_t)NAS_SIZE_IPv4_ADDR); memcpy(dst->tft_ipv4_addr_mask.addr_mask, src->tft_ipv4_src_addr_mask.tft_ipv4_mask, (size_t)NAS_SIZE_IPv4_ADDR); #ifdef TFT_DEBUG { U8 *addr, *mask; addr = dst->tft_ipv4_addr_mask.src_addr; mask = dst->tft_ipv4_addr_mask.addr_mask; (void)TRACE_EVENT_P8("tft_copy: Copy IPv4 src addr/mask filter: " "%u.%u.%u.%u/%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3], mask[0], mask[1], mask[2], mask[3]); } #endif } else { dst->v_tft_ipv4_addr_mask = (U8)FALSE; } /* NAS_TFT_ID_IPv4_SRC_ADDR_MASK */ /* IPv6 addr/mask never invluded in IPv4 packet filter */ dst->v_tft_ipv6_addr_mask = (U8)FALSE; /* Copy IPv4 protocol number field */ if ((valid_flag & NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR) != (U8)0) { dst->v_tft_protocol = (U8)TRUE; dst->tft_protocol.tft_protocol_val = src->tft_protocol; #ifdef TFT_DEBUG (void)TRACE_EVENT_P1("tft_copy: Copy IPv4 protocol: 0x%02x", src->tft_protocol); #endif } else { dst->v_tft_protocol = (U8)FALSE; } /* NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR */ /* Copy destination single port/port range parameter */ if ((valid_flag & NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0) { T_NAS_tft_dest_port_range *port_range = &src->tft_dest_port_range; if (sm_tft_is_port_range(port_range->low_limit, port_range->high_limit)) { dst->v_tft_dest_port_range = (U8)TRUE; dst->v_tft_dest_port = (U8)FALSE; dst->tft_dest_port_range.low_limit = port_range->low_limit; dst->tft_dest_port_range.high_limit = port_range->high_limit; #ifdef TFT_DEBUG (void)TRACE_EVENT_P2("tft_copy: Copying destination port range filter (ports %d-%d)", port_range->low_limit, port_range->high_limit); #endif } else { dst->v_tft_dest_port_range = (U8)FALSE; dst->v_tft_dest_port = (U8)TRUE; dst->tft_dest_port.low_limit = port_range->low_limit; #ifdef TFT_DEBUG (void)TRACE_EVENT_P1("tft_copy: Copying single destination port filter (port %d)", port_range->low_limit); #endif } } else { dst->v_tft_dest_port_range = (U8)FALSE; dst->v_tft_dest_port = (U8)FALSE; } /* NAS_TFT_ID_DEST_PORT_RANGE */ /* Copy source single port/port range parameter */ if ((valid_flag & NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0) { T_NAS_tft_src_port_range *port_range = &src->tft_src_port_range; if (sm_tft_is_port_range(port_range->low_limit, port_range->high_limit)) { dst->v_tft_src_port_range = (U8)TRUE; dst->v_tft_src_port = (U8)FALSE; dst->tft_src_port_range.low_limit = port_range->low_limit; dst->tft_src_port_range.high_limit = port_range->high_limit; #ifdef TFT_DEBUG (void)TRACE_EVENT_P2("tft_copy: Copying source port range filter (ports %d-%d)", port_range->low_limit, port_range->high_limit); #endif } else { dst->v_tft_src_port_range = (U8)FALSE; dst->v_tft_src_port = (U8)TRUE; dst->tft_src_port.low_limit = port_range->low_limit; #ifdef TFT_DEBUG (void)TRACE_EVENT_P1("tft_copy: Copying single source port filter (port %d)", port_range->low_limit); #endif } } else { dst->v_tft_src_port_range = (U8)FALSE; dst->v_tft_src_port = (U8)FALSE; } /* NAS_TFT_ID_SRC_PORT_RANGE */ if ((valid_flag & NAS_TFT_ID_IPSEC_SPI) != (U8)0) { dst->v_tft_ipsec_spi = (U8)TRUE; sm_tft_copy_ipsec_spi(&dst->tft_ipsec_spi, src->tft_ipsec_spi); } else { dst->v_tft_ipsec_spi = (U8)FALSE; }/* NAS_TFT_ID_IPSEC_SPI */ if ((valid_flag & NAS_TFT_ID_TOS_AND_MASK) != (U8)0) { dst->v_tft_tos_and_mask = (U8)TRUE; dst->tft_tos_and_mask.tos_value = src->tft_tos_and_mask.tos_value; dst->tft_tos_and_mask.tos_mask = src->tft_tos_and_mask.tos_mask; } else { dst->v_tft_tos_and_mask = (U8)FALSE; } /* NAS_TFT_ID_TOS_AND_MASK */ if ((valid_flag & NAS_TFT_ID_FLOW_LABEL) != (U8)0) { (void)TRACE_ERROR("tft_copy: Found flow label in IPv4 packet filter - Discarded..."); } /* NAS_TFT_ID_FLOW_LABEL */ dst->v_tft_flow_label = (U8)FALSE; } /* +------------------------------------------------------------------------------ | Function : sm_tft_copy_ipv6_pf +------------------------------------------------------------------------------ | Description : Copies an IPv6 TFT filter from src_tft to dst_tft AIM struct. | | Parameters : dst_tft - destination aim TFT structs | src_tft - source TFT structs | valid_flag - valid flags for filter components +------------------------------------------------------------------------------ */ static void sm_tft_copy_ipv6_pf(/*@out@*/ T_M_SM_tft_filter_entry *dst, T_NAS_tft_pf_ipv6 *src, U8 valid_flag) { /* IPv4 addr/mask never invluded in IPv4 packet filter */ dst->v_tft_ipv4_addr_mask = (U8)FALSE; /* Copy IPv6 address, if present */ if ((valid_flag & NAS_TFT_ID_IPv6_SRC_ADDR_MASK) != (U8)0) { dst->v_tft_ipv6_addr_mask = (U8)TRUE; memcpy(dst->tft_ipv6_addr_mask.src_addr, src->tft_ipv6_src_addr_mask.tft_ipv6_addr, (size_t)NAS_SIZE_IPv6_ADDR); memcpy(dst->tft_ipv6_addr_mask.addr_mask, src->tft_ipv6_src_addr_mask.tft_ipv6_mask, (size_t)NAS_SIZE_IPv6_ADDR); #ifdef TFT_DEBUG /* Dump address/mask */ { char addr[SM_SIZE_FORMATTED_IPv6_ADDR], mask[SM_SIZE_FORMATTED_IPv6_ADDR]; (void)TRACE_EVENT_P2("tft_copy: Copy IPv6 src addr/mask filter: %s/%s", sm_format_ipv6_addr(dst->tft_ipv6_addr_mask.src_addr, addr), sm_format_ipv6_addr(dst->tft_ipv6_addr_mask.addr_mask, mask)); } #endif } else { dst->v_tft_ipv6_addr_mask = (U8)FALSE; } /* NAS_TFT_ID_IPv6_SRC_ADDR_MASK */ /* Copy IPv6 next header field */ if ((valid_flag & NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR) != (U8)0) { dst->v_tft_protocol = (U8)TRUE; dst->tft_protocol.tft_protocol_val = src->tft_next_hdr; #ifdef TFT_DEBUG (void)TRACE_EVENT_P1("tft_copy: Copy IPv6 next header field: 0x%02x", src->tft_next_hdr); #endif } else { dst->v_tft_protocol = (U8)FALSE; } /* NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR */ /* Copy destination single port/port range parameter */ if ((valid_flag & NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0) { T_NAS_tft_dest_port_range *port_range = &src->tft_dest_port_range; if (sm_tft_is_port_range(port_range->low_limit, port_range->high_limit)) { dst->v_tft_dest_port_range = (U8)TRUE; dst->v_tft_dest_port = (U8)FALSE; dst->tft_dest_port_range.low_limit = port_range->low_limit; dst->tft_dest_port_range.high_limit = port_range->high_limit; #ifdef TFT_DEBUG (void)TRACE_EVENT_P2("tft_copy: Copying destination port range filter (ports %d-%d)", port_range->low_limit, port_range->high_limit); #endif } else { dst->v_tft_dest_port_range = (U8)FALSE; dst->v_tft_dest_port = (U8)TRUE; dst->tft_dest_port.low_limit = port_range->low_limit; #ifdef TFT_DEBUG (void)TRACE_EVENT_P1("tft_copy: Copying single destination port filter (port %d)", port_range->low_limit); #endif } } else { dst->v_tft_dest_port_range = (U8)FALSE; dst->v_tft_dest_port = (U8)FALSE; } /* NAS_TFT_ID_DEST_PORT_RANGE */ /* Copy source single port/port range parameter */ if ((valid_flag & NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0) { T_NAS_tft_src_port_range *port_range = &src->tft_src_port_range; if (sm_tft_is_port_range(port_range->low_limit, port_range->high_limit)) { dst->v_tft_src_port_range = (U8)TRUE; dst->v_tft_src_port = (U8)FALSE; dst->tft_src_port_range.low_limit = port_range->low_limit; dst->tft_src_port_range.high_limit = port_range->high_limit; #ifdef TFT_DEBUG (void)TRACE_EVENT_P2("tft_copy: Copying source port range filter (ports %d-%d)", port_range->low_limit, port_range->high_limit); #endif } else { dst->v_tft_src_port_range = (U8)FALSE; dst->v_tft_src_port = (U8)TRUE; dst->tft_src_port.low_limit = port_range->low_limit; #ifdef TFT_DEBUG (void)TRACE_EVENT_P1("tft_copy: Copying single source port filter (port %d)", port_range->low_limit); #endif } } else { dst->v_tft_src_port_range = (U8)FALSE; dst->v_tft_src_port = (U8)FALSE; } /* NAS_TFT_ID_SRC_PORT_RANGE */ if ((valid_flag & NAS_TFT_ID_IPSEC_SPI) != (U8)0) { dst->v_tft_ipsec_spi = (U8)TRUE; sm_tft_copy_ipsec_spi(&dst->tft_ipsec_spi, src->tft_ipsec_spi); } else { dst->v_tft_ipsec_spi = (U8)FALSE; } /* NAS_TFT_ID_IPSEC_SPI */ if ((valid_flag & NAS_TFT_ID_TOS_AND_MASK) != (U8)0) { dst->v_tft_tos_and_mask = (U8)TRUE; dst->tft_tos_and_mask.tos_value = src->tft_tos_and_mask.tos_value; dst->tft_tos_and_mask.tos_mask = src->tft_tos_and_mask.tos_mask; } else { dst->v_tft_tos_and_mask = (U8)FALSE; } /* NAS_TFT_ID_TOS_AND_MASK */ if ((valid_flag & NAS_TFT_ID_FLOW_LABEL) != (U8)0) { dst->v_tft_flow_label = (U8)TRUE; dst->tft_flow_label.flow_label_value = src->tft_flow_label; } else { dst->v_tft_flow_label = (U8)FALSE; } /* NAS_TFT_ID_FLOW_LABEL */ } /* +------------------------------------------------------------------------------ | Function : sm_tft_copy_filters +------------------------------------------------------------------------------ | Description : Copies TFT filters from src_tft to dst_tft AIM structs. | | Parameters : dst_tft - destination aim TFT structs | src_tft - source TFT structs | tft_mask - TFT mask (determines which TFTs to consider) +------------------------------------------------------------------------------ */ static U8 sm_tft_copy_filters(/*@special@*/T_M_SM_tft *dst_tft, /*@in@*/ T_NAS_tft_pf *src_tft, U8 max_count, U8 tft_mask) { int i, count; T_M_SM_tft_filter *dst; U16 size, total_size = 0; U8 change_mask = (U8)0; dst_tft->v_tft_filter = (U8)TRUE; /* Initialize pointer to air interface TFT */ dst = dst_tft->tft_filter; for (i = 0, count = 0; i < (int)max_count; i++) { if (sm_tft_is_tft_in_mask(src_tft->tft_pf_id, tft_mask)) { size = sm_tft_pf_size(src_tft); /* Only include packet filter, if it fits in air interface message */ if (total_size + size > (U16)255) { break; } dst->tft_filter_id = src_tft->tft_pf_id; dst->tft_filter_prio = src_tft->tft_pf_precedence; if (src_tft->ctrl_tft_pf_entry == NAS_is_tft_pf_ipv4) { sm_tft_copy_ipv4_pf(&dst->tft_filter_entry, &src_tft->tft_pf_entry.tft_pf_ipv4, src_tft->tft_pf_valid_bits); } else if (src_tft->ctrl_tft_pf_entry == NAS_is_tft_pf_ipv6) { sm_tft_copy_ipv6_pf(&dst->tft_filter_entry, &src_tft->tft_pf_entry.tft_pf_ipv6, src_tft->tft_pf_valid_bits); } else { (void)TRACE_EVENT_P1("tft_copy: ERROR! Wrong union controller (%d) " "for tft_pf_entry; discarded...", src_tft->ctrl_tft_pf_entry); } /* Update change mask and total TFT size */ change_mask |= (U8)(1UL << dst->tft_filter_id); total_size += size; /* Advance to next destination TFT */ dst++; count++; } /* if (sm_tft_is_tft_in_mask()) */ /* Skip to next input TFT */ src_tft++; } dst_tft->c_tft_filter = (U8)count; return change_mask; } /* +------------------------------------------------------------------------------ | Function : sm_tft_copy_filter_numbers +------------------------------------------------------------------------------ | Description : Copies filter IDs to dst_tft AIM struct (derived from tft_mask) | | Parameters : dst_tft - destination aim TFT structs | tft_mask - TFT mask (determines which TFTs to consider) +------------------------------------------------------------------------------ */ static void sm_tft_copy_filter_numbers(/*@special@*/T_M_SM_tft *dst_tft, U8 tft_mask) { int index, dst_idx; dst_tft->v_tft_filter_id = (U8)TRUE; for (index = 0, dst_idx = 0; index < (int)NAS_SIZE_TFT_FILTER; index++) { if (sm_tft_is_tft_in_mask((U8)index, tft_mask)) { dst_tft->tft_filter_id[dst_idx] = (U8)index; dst_idx++; } } /* for */ /* Set counter to the number of filters numbers inserted */ dst_tft->c_tft_filter_id = (U8)dst_idx; } /* +------------------------------------------------------------------------------ | Function : sm_tft_update_active_tft +------------------------------------------------------------------------------ | Description : Update context data structure with new active TFT as it would | be would the modification succeed. | | Parameters : context - context data | tft_mask - TFT mask (determines which TFTs to consider) +------------------------------------------------------------------------------ */ static void sm_tft_update_active_tft(/*@special@*/struct T_SM_CONTEXT_DATA *context, U8 change_mask) { T_NAS_tft_pf *req_tft, *act_tft; U16 index; U8 req_mask, act_mask, add_mask, delete_mask; req_mask = context->requested_tft.tft_precence_mask; act_mask = context->active_tft.tft_precence_mask; add_mask = req_mask & change_mask; delete_mask = (U8)(0xffUL ^ req_mask) & change_mask; if (req_mask == (U8)0) { sm_nw_free_active_tft(context); return; } TRACE_ASSERT(context->requested_tft.ptr_tft_pf != NULL); /* Allocate active TFT memory, if required */ if (act_mask == (U8)0 && /*req_mask != (U8)0 &&*/ /*commented out because of previous return*/ context->active_tft.ptr_tft_pf == NULL) { sm_nw_allocate_active_tft(context); TRACE_ASSERT(context->active_tft.ptr_tft_pf != NULL); } /* Loop over TFTs, in order to find any TFTs to delete */ for (index = 0; index < (U16)NAS_SIZE_TFT_FILTER; index++) { if (sm_tft_is_tft_in_mask((U8)index, delete_mask)) { /* Was filter removed ? If so, clear filter from mask and store */ act_mask &= (U8)(0xffUL ^ 1UL << index); act_tft = sm_tft_get_active_tft_by_id(context, (U8)index); memset(act_tft, 0, sizeof(T_NAS_tft_pf)); } } for (index = 0, req_tft = context->requested_tft.ptr_tft_pf; index < (U16)context->requested_tft.c_tft_pf; index++, req_tft++) { U8 pf_id = req_tft->tft_pf_id; if (sm_tft_is_tft_in_mask(pf_id, add_mask)) { /* Copy any remaining requested TFTs into active TFT */ act_mask |= (U8)(1UL << pf_id); act_tft = sm_tft_get_active_tft_by_id(context, pf_id); memcpy(act_tft, req_tft, sizeof(T_NAS_tft_pf)); } } /* for */ context->active_tft.tft_precence_mask = act_mask; context->active_tft.c_tft_pf = sm_tft_count_tfts_in_mask(act_mask); } /* +------------------------------------------------------------------------------ | Function : sm_tft_next_action +------------------------------------------------------------------------------ | Description : Determines the next action to perform (opcode) on the TFTs | for a context, and the filters affected. | (8 upper bits is change mask; 8 lower bits is opcode) | | Parameters : context - context data +------------------------------------------------------------------------------ */ static U16 sm_tft_next_action(struct T_SM_CONTEXT_DATA *context) { U8 req_mask, act_mask, missing_mask, surplus_mask, replace_mask; U16 index; req_mask = context->requested_tft.tft_precence_mask; act_mask = context->active_tft.tft_precence_mask; /* If requested TFT contains 0 filters, remove TFT altogether */ if (context->requested_tft.c_tft_pf == (U8)0) { return (U16)M_SM_TFT_OPCODE_DELETE_TFT; } TRACE_ASSERT(context->requested_tft.ptr_tft_pf != NULL); /* If there are no activate TFT filters, and requested != 0, create new TFT */ if (act_mask == (U8)0 && req_mask != (U8)0) { return (U16)M_SM_TFT_OPCODE_CREATE_TFT | (U16)req_mask << 8; } /* Add filters, if requested filter count > active filter count or * requested filters exist, that are not active. */ missing_mask = req_mask & (0xff ^ act_mask); if (context->requested_tft.c_tft_pf > context->active_tft.c_tft_pf || missing_mask != (U8)0) { return (U16)M_SM_TFT_OPCODE_ADD_FILTERS | (U16)missing_mask << 8; } /* Delete filters, if requested filter count < active filter count or * active filters exist, that are not requested. */ surplus_mask = act_mask & (0xff ^ req_mask); if (context->requested_tft.c_tft_pf < context->active_tft.c_tft_pf || surplus_mask != (U8)0) { return (U16)M_SM_TFT_OPCODE_DELETE_FILTERS | (U16)surplus_mask << 8; } /* Now, requested and active TFTs have the same filter *numbers* active; * We then need to check, whether the *contents* of the filters that * have the same number also match. */ for (index = 0, replace_mask = (U8)0; index < (U16)context->requested_tft.c_tft_pf; index++) { T_NAS_tft_pf *req_tft = &context->requested_tft.ptr_tft_pf[index]; T_NAS_tft_pf *act_tft = sm_tft_get_active_tft_by_id(context, req_tft->tft_pf_id); if (!sm_tft_are_equal(req_tft, act_tft)) { replace_mask |= (U8)(1UL << req_tft->tft_pf_id); } } if (replace_mask != (U8)0) { return (U16)M_SM_TFT_OPCODE_REPLACE_FILTERS | (U16)replace_mask << 8; } /* Error. Nothing to change, or invalid configuration */ return (U16)M_SM_TFT_OPCODE_SPARE; } /*==== PUBLIC FUNCTIONS =====================================================*/ U8 sm_tft_precence_mask(T_NAS_tft_pf *tft, U8 count) { U16 index; U8 precence_mask = (U8)0; for (index = 0; index < (U16)count; index++) { precence_mask |= (1UL << tft[index].tft_pf_id); } return precence_mask; } void sm_tft_convert_to_aim(struct T_SM_CONTEXT_DATA *context, /*@out@*/ T_M_SM_tft *dst_tft) { U8 opcode, filter_mask, change_mask, max_count; U16 opcode_and_mask; T_NAS_tft_pf *src_tft = context->requested_tft.ptr_tft_pf; max_count = context->requested_tft.c_tft_pf; if (src_tft == NULL) { return; } opcode_and_mask = sm_tft_next_action(context); opcode = (U8)(opcode_and_mask & 0xff); filter_mask = (U8)(opcode_and_mask >> 8); dst_tft->tft_opcode = opcode; switch (opcode) { case M_SM_TFT_OPCODE_CREATE_TFT: case M_SM_TFT_OPCODE_ADD_FILTERS: case M_SM_TFT_OPCODE_REPLACE_FILTERS: TRACE_ASSERT(src_tft != NULL); /* Copy filter count to air interface message TFT struct */ change_mask = sm_tft_copy_filters(dst_tft, src_tft, max_count, filter_mask); sm_tft_update_active_tft(context, change_mask); dst_tft->tft_filter_count = sm_tft_count_tfts_in_mask(change_mask); break; case M_SM_TFT_OPCODE_DELETE_TFT: /* * DELETE TFT can have no fields other than TFT opcode and * filter count (== 0), and is thus complete. */ context->requested_tft.tft_precence_mask = (U8)0; sm_tft_update_active_tft(context, (U8)0xff); dst_tft->tft_filter_count = (U8)0; break; case M_SM_TFT_OPCODE_DELETE_FILTERS: TRACE_ASSERT(src_tft != NULL); /* Copy filter count to air interface message TFT struct */ sm_tft_copy_filter_numbers(dst_tft, filter_mask); sm_tft_update_active_tft(context, filter_mask); dst_tft->tft_filter_count = sm_tft_count_tfts_in_mask(filter_mask); break; default: (void)TRACE_EVENT_P1("tft_convert_to_aim: ERROR!" "Invalid opcode (%d) - TFT skipped!", opcode); break; } } BOOL sm_tft_more_to_modify(struct T_SM_CONTEXT_DATA *context) { int filter; (void)TRACE_FUNCTION("sm_tft_more_to_modify"); if (context->requested_tft.c_tft_pf != context->active_tft.c_tft_pf || context->requested_tft.tft_precence_mask != context->active_tft.tft_precence_mask) { return TRUE; } if (context->requested_tft.c_tft_pf > (U8)0 && context->requested_tft.ptr_tft_pf != NULL && context->active_tft.ptr_tft_pf != NULL) { for (filter = 0; filter < (int)context->requested_tft.c_tft_pf; filter++) { if (!sm_tft_are_equal(&context->requested_tft.ptr_tft_pf[filter], sm_tft_get_active_tft_by_id(context, context->requested_tft.ptr_tft_pf[filter].tft_pf_id))) { return TRUE; } } /* for */ } /* if (c_tft_pf > 0) */ return FALSE; }