comparison src/g23m-gprs/sm/sm_tft.c @ 183:219afcfc6250

src/g23m-gprs: initial import from TCS3.2/LoCosto
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 13 Oct 2016 04:24:13 +0000
parents
children
comparison
equal deleted inserted replaced
182:f02d0a0e1849 183:219afcfc6250
1 /*----------------------------------------------------------------------------
2 | Project : 3G PS
3 | Module : SM
4 +-----------------------------------------------------------------------------
5 | Copyright 2003 Texas Instruments.
6 | All rights reserved.
7 |
8 | This file is confidential and a trade secret of Texas
9 | Instruments .
10 | The receipt of or possession of this file does not convey
11 | any rights to reproduce or disclose its contents or to
12 | manufacture, use, or sell anything it may describe, in
13 | whole, or in part, without the specific written consent of
14 | Texas Instruments.
15 +-----------------------------------------------------------------------------
16 | Purpose: 3G TFT utility functions implementation in the SM entity.
17 | For design details, see:
18 | 8010.908 SM Detailed Specification
19 +---------------------------------------------------------------------------*/
20
21 /*==== DECLARATION CONTROL =================================================*/
22
23 /*==== INCLUDES ============================================================*/
24
25 #include "sm.h"
26
27 #include "sm_tft.h"
28
29 /*==== CONST ===============================================================*/
30
31 /*==== LOCAL VARS ===========================================================*/
32
33 /*==== PRIVATE FUNCTIONS ====================================================*/
34
35 /*
36 +------------------------------------------------------------------------------
37 | Function : sm_tft_count_tfts_in_mask
38 +------------------------------------------------------------------------------
39 | Description : Returns the number of filters (set bits) in a TFT mask.
40 |
41 | Parameters : tft_mask - TFT mask
42 +------------------------------------------------------------------------------
43 */
44 static U8 sm_tft_count_tfts_in_mask(U8 tft_mask) /*@*/
45 {
46 U8 count_array[16] = {
47 (U8)0 /* 0000 */, (U8)1 /* 0001 */, (U8)1 /* 0010 */, (U8)2 /* 0011 */,
48 (U8)1 /* 0100 */, (U8)2 /* 0101 */, (U8)2 /* 0110 */, (U8)3 /* 0111 */,
49 (U8)1 /* 1000 */, (U8)2 /* 1001 */, (U8)2 /* 1010 */, (U8)3 /* 1011 */,
50 (U8)2 /* 1100 */, (U8)3 /* 1101 */, (U8)3 /* 1110 */, (U8)4 /* 1111 */
51 };
52 return (count_array[(U16)tft_mask >> 4] + count_array[(U16)tft_mask & 15]);
53 }
54
55 /*
56 +------------------------------------------------------------------------------
57 | Function : sm_tft_is_tft_in_mask
58 +------------------------------------------------------------------------------
59 | Description : Returns TRUE if the TFT with the specified ID (bit) is
60 | set in the specified TFT mask.
61 |
62 | Parameters : id - TFT identifier
63 | tft_mask - TFT mask
64 +------------------------------------------------------------------------------
65 */
66 static BOOL sm_tft_is_tft_in_mask(U8 id, U8 tft_mask) /*@*/
67 {
68 return ((tft_mask & (1UL << id)) != 0);
69 }
70
71 /*
72 +------------------------------------------------------------------------------
73 | Function : sm_tft_is_port_range
74 +------------------------------------------------------------------------------
75 | Description : Query function returning TRUE if high_limit is not zero, and
76 | high_limit is greater than (but not equal) to low_limit.
77 |
78 | Parameters : low_limit - lower port limit
79 | high_limit - upper port limit
80 +------------------------------------------------------------------------------
81 */
82 static BOOL sm_tft_is_port_range(U16 low_limit, U16 high_limit)
83 {
84 return (high_limit != 0 && low_limit < high_limit);
85 }
86
87 static /*@exposed@*/T_NAS_tft_pf *
88 sm_tft_get_active_tft_by_id(/*@returned@*/ /*@partial@*/struct T_SM_CONTEXT_DATA *context,
89 U8 id)
90 {
91 TRACE_ASSERT(id < (U8)NAS_SIZE_TFT_FILTER);
92 TRACE_ASSERT(context->active_tft.ptr_tft_pf != NULL);
93 return (&context->active_tft.ptr_tft_pf[id]);
94 }
95
96 /*
97 +------------------------------------------------------------------------------
98 | Function : sm_tft_pf_size
99 +------------------------------------------------------------------------------
100 | Description : Query function returning the packed size of a packet filter.
101 |
102 | Parameters : tft_pf - packet filter
103 +------------------------------------------------------------------------------
104 */
105 static U16 sm_tft_pf_size(T_NAS_tft_pf *tft_pf)
106 {
107 U16 tft_pf_size = (U16)3; /* Filter ID, precedence and length octet mandatory */
108
109 U16 lower3bits[8] = {
110 (U16) 0, /* 0x00: None */
111 (U16) 9, /* 0x01: IPv4_SRC_ADDR_MASK */
112 (U16) 33, /* 0x02: IPv6_SRC_ADDR_MASK */
113 (U16) 0, /* 0x03: IPv4_SRC_ADDR_MASK + IPv6_SRC_ADDR_MASK -- INVALID! */
114 (U16) 3, /* 0x04: PROTOCOL_OR_NEXT_HDR */
115 (U16) 12, /* 0x05: IPv4_SRC_ADDR_MASK + PROTOCOL_OR_NEXT_HDR */
116 (U16) 36, /* 0x06: IPv6_SRC_ADDR_MASK + PROTOCOL_OR_NEXT_HDR */
117 (U16) 0 /* 0x07: IPv4_SRC_ADDR_MASK + IPv6_SRC_ADDR_MASK + PROTOCOL_OR_NEXT_HDR -- INVALID! */
118 };
119 U16 upper3bits[8] = {
120 (U16) 0, /* 0x00: None */
121 (U16) 5, /* 0x20: IPSEC_SPI */
122 (U16) 3, /* 0x40: TOS_AND_MASK */
123 (U16) 5, /* 0x60: IPSEC_SPI + TOS_AND_MASK */
124 (U16) 4, /* 0x80: FLOW_LABEL */
125 (U16) 0, /* 0xa0: IPSEC_SPI + FLOW_LABEL - INVALID! */
126 (U16) 7, /* 0xc0: TOS_AND_MASK + FLOW_LABEL */
127 (U16) 0 /* 0xe0: IPSEC_SPI + TOS_AND_MASK + FLOW_LABEL - INVALID! */
128 };
129
130 if ((tft_pf->tft_pf_valid_bits & (U8)0x07) != (U8)0)
131 {
132 tft_pf_size += lower3bits[(U16)tft_pf->tft_pf_valid_bits & 0x07];
133 }
134
135 if ((tft_pf->tft_pf_valid_bits & (U8)0xe0) != (U8)0)
136 {
137 tft_pf_size += upper3bits[(U16)tft_pf->tft_pf_valid_bits >> 5];
138 }
139
140 if ((tft_pf->tft_pf_valid_bits & (U8)NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0)
141 {
142 T_NAS_tft_dest_port_range *range = &tft_pf->tft_pf_entry.tft_pf_ipv4.tft_dest_port_range;
143 if (sm_tft_is_port_range(range->low_limit, range->high_limit))
144 {
145 tft_pf_size += (U16)5; /* Destination port range */
146 } else {
147 tft_pf_size += (U16)3; /* Single destination port */
148 }
149 }
150
151 if ((tft_pf->tft_pf_valid_bits & (U8)NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0)
152 {
153 T_NAS_tft_src_port_range *range = &tft_pf->tft_pf_entry.tft_pf_ipv4.tft_src_port_range;
154 if (sm_tft_is_port_range(range->low_limit, range->high_limit))
155 {
156 tft_pf_size += (U16)5; /* Source port range */
157 } else {
158 tft_pf_size += (U16)3; /* Single source port */
159 }
160 }
161
162 return tft_pf_size;
163 }
164
165 /*
166 +------------------------------------------------------------------------------
167 | Function : sm_tft_are_equal
168 +------------------------------------------------------------------------------
169 | Description : Query function returning TRUE if the two input packet filters
170 | are equal (same parameters).
171 |
172 | Parameters : tft1 - packet filter 1
173 | tft2 - packet filter 2
174 +------------------------------------------------------------------------------
175 */
176 static BOOL sm_tft_are_equal(T_NAS_tft_pf *tft1, T_NAS_tft_pf *tft2)
177 {
178 U8 valid_bits;
179
180 /* Compare outer-level parameters */
181 if (tft1->tft_pf_id != tft2->tft_pf_id ||
182 tft1->tft_pf_precedence != tft2->tft_pf_precedence ||
183 tft1->tft_pf_valid_bits != tft2->tft_pf_valid_bits ||
184 tft1->ctrl_tft_pf_entry != tft2->ctrl_tft_pf_entry)
185 {
186 return FALSE;
187 }
188
189 valid_bits = tft1->tft_pf_valid_bits;
190
191 if (tft1->ctrl_tft_pf_entry == NAS_is_tft_pf_ipv4) {
192 T_NAS_tft_pf_ipv4 *v4_pf_1 = &tft1->tft_pf_entry.tft_pf_ipv4;
193 T_NAS_tft_pf_ipv4 *v4_pf_2 = &tft2->tft_pf_entry.tft_pf_ipv4;
194
195 if (((valid_bits & (U8)NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR) != (U8)0
196 && v4_pf_1->tft_protocol != v4_pf_2->tft_protocol)
197 || ((valid_bits & (U8)NAS_TFT_ID_TOS_AND_MASK) != (U8)0
198 && v4_pf_1->tft_tos_and_mask.tos_value != v4_pf_2->tft_tos_and_mask.tos_value
199 && v4_pf_1->tft_tos_and_mask.tos_mask != v4_pf_2->tft_tos_and_mask.tos_mask)
200 || ((valid_bits & (U8)NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0
201 && memcmp(&v4_pf_1->tft_dest_port_range, &v4_pf_2->tft_dest_port_range, sizeof(T_NAS_tft_dest_port_range)) != 0)
202 || ((valid_bits & (U8)NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0
203 && memcmp(&v4_pf_1->tft_src_port_range, &v4_pf_2->tft_src_port_range, sizeof(T_NAS_tft_src_port_range)) != 0)
204 || ((valid_bits & (U8)NAS_TFT_ID_IPSEC_SPI) != (U8)0
205 && v4_pf_1->tft_ipsec_spi != v4_pf_2->tft_ipsec_spi)
206 || ((valid_bits & (U8)NAS_TFT_ID_IPv4_SRC_ADDR_MASK) != (U8)0
207 && 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))
208 {
209 return FALSE;
210 }
211 } else if (tft1->ctrl_tft_pf_entry == NAS_is_tft_pf_ipv6)
212 {
213 T_NAS_tft_pf_ipv6 *v6_pf_1 = &tft1->tft_pf_entry.tft_pf_ipv6;
214 T_NAS_tft_pf_ipv6 *v6_pf_2 = &tft2->tft_pf_entry.tft_pf_ipv6;
215
216 if (((valid_bits & (U8)NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR) != (U8)0
217 && v6_pf_1->tft_next_hdr != v6_pf_2->tft_next_hdr)
218 || ((valid_bits & (U8)NAS_TFT_ID_TOS_AND_MASK) != (U8)0
219 && v6_pf_1->tft_tos_and_mask.tos_value != v6_pf_2->tft_tos_and_mask.tos_value
220 && v6_pf_1->tft_tos_and_mask.tos_mask != v6_pf_2->tft_tos_and_mask.tos_mask)
221 || ((valid_bits & (U8)NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0
222 && memcmp(&v6_pf_1->tft_dest_port_range, &v6_pf_2->tft_dest_port_range, sizeof(T_NAS_tft_dest_port_range)) != 0)
223 || ((valid_bits & (U8)NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0
224 && memcmp(&v6_pf_1->tft_src_port_range, &v6_pf_2->tft_src_port_range, sizeof(T_NAS_tft_src_port_range)) != 0)
225 || ((valid_bits & (U8)NAS_TFT_ID_IPSEC_SPI) != (U8)0
226 && v6_pf_1->tft_ipsec_spi != v6_pf_2->tft_ipsec_spi)
227 || ((valid_bits & (U8)NAS_TFT_ID_FLOW_LABEL) != (U8)0
228 && v6_pf_1->tft_flow_label != v6_pf_2->tft_flow_label)
229 || ((valid_bits & (U8)NAS_TFT_ID_IPv6_SRC_ADDR_MASK) != (U8)0
230 && 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))
231 {
232 return FALSE;
233 }
234 } else {
235 (void)TRACE_EVENT_P1("ERROR: Invalid union controller %d in ctrl_tft_pf_entry!",
236 tft1->ctrl_tft_pf_entry);
237 }
238 return TRUE;
239 }
240
241 /*
242 +------------------------------------------------------------------------------
243 | Function : sm_tft_copy_ipv4_pf
244 +------------------------------------------------------------------------------
245 | Description : Copies an IPv4 TFT filter from src_tft to dst_tft AIM struct.
246 |
247 | Parameters : dst_tft - destination aim TFT structs
248 | src_tft - source TFT structs
249 | valid_flag - valid flags for filter components
250 +------------------------------------------------------------------------------
251 */
252 static void sm_tft_copy_ipsec_spi(/*@out@*/T_M_SM_tft_ipsec_spi *dst_spi,
253 U32 spi)
254 {
255 M_SM_BUF_ipsec_spi_value *dst = &dst_spi->ipsec_spi_value;
256 #ifdef TFT_DEBUG
257 (void)TRACE_EVENT_P1("tft_copy: Copying IPSEC SPI filter (SPI 0x%08x)", spi);
258 #endif
259 dst->l_ipsec_spi_value = (U16)32;
260 dst->o_ipsec_spi_value = (U16)0;
261 dst->b_ipsec_spi_value[0] = (U8)((spi >> 24) & 255);
262 dst->b_ipsec_spi_value[1] = (U8)((spi >> 16) & 255);
263 dst->b_ipsec_spi_value[2] = (U8)((spi >> 8) & 255);
264 dst->b_ipsec_spi_value[3] = (U8)( spi & 255);
265 }
266
267 static void
268 sm_tft_copy_ipv4_pf(/*@out@*/ T_M_SM_tft_filter_entry *dst,
269 T_NAS_tft_pf_ipv4 *src, U8 valid_flag)
270 {
271 /* Copy IPv4 address, if present */
272 if ((valid_flag & NAS_TFT_ID_IPv4_SRC_ADDR_MASK) != (U8)0)
273 {
274 dst->v_tft_ipv4_addr_mask = (U8)TRUE;
275 memcpy(dst->tft_ipv4_addr_mask.src_addr,
276 src->tft_ipv4_src_addr_mask.tft_ipv4_addr,
277 (size_t)NAS_SIZE_IPv4_ADDR);
278 memcpy(dst->tft_ipv4_addr_mask.addr_mask,
279 src->tft_ipv4_src_addr_mask.tft_ipv4_mask,
280 (size_t)NAS_SIZE_IPv4_ADDR);
281 #ifdef TFT_DEBUG
282 {
283 U8 *addr, *mask;
284 addr = dst->tft_ipv4_addr_mask.src_addr;
285 mask = dst->tft_ipv4_addr_mask.addr_mask;
286 (void)TRACE_EVENT_P8("tft_copy: Copy IPv4 src addr/mask filter: "
287 "%u.%u.%u.%u/%u.%u.%u.%u",
288 addr[0], addr[1], addr[2], addr[3],
289 mask[0], mask[1], mask[2], mask[3]);
290 }
291 #endif
292 } else {
293 dst->v_tft_ipv4_addr_mask = (U8)FALSE;
294 } /* NAS_TFT_ID_IPv4_SRC_ADDR_MASK */
295
296 /* IPv6 addr/mask never invluded in IPv4 packet filter */
297 dst->v_tft_ipv6_addr_mask = (U8)FALSE;
298
299 /* Copy IPv4 protocol number field */
300 if ((valid_flag & NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR) != (U8)0)
301 {
302 dst->v_tft_protocol = (U8)TRUE;
303 dst->tft_protocol.tft_protocol_val = src->tft_protocol;
304 #ifdef TFT_DEBUG
305 (void)TRACE_EVENT_P1("tft_copy: Copy IPv4 protocol: 0x%02x",
306 src->tft_protocol);
307 #endif
308 } else {
309 dst->v_tft_protocol = (U8)FALSE;
310 } /* NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR */
311
312 /* Copy destination single port/port range parameter */
313 if ((valid_flag & NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0)
314 {
315 T_NAS_tft_dest_port_range *port_range = &src->tft_dest_port_range;
316 if (sm_tft_is_port_range(port_range->low_limit, port_range->high_limit)) {
317 dst->v_tft_dest_port_range = (U8)TRUE;
318 dst->v_tft_dest_port = (U8)FALSE;
319 dst->tft_dest_port_range.low_limit = port_range->low_limit;
320 dst->tft_dest_port_range.high_limit = port_range->high_limit;
321 #ifdef TFT_DEBUG
322 (void)TRACE_EVENT_P2("tft_copy: Copying destination port range filter (ports %d-%d)",
323 port_range->low_limit, port_range->high_limit);
324 #endif
325 } else {
326 dst->v_tft_dest_port_range = (U8)FALSE;
327 dst->v_tft_dest_port = (U8)TRUE;
328 dst->tft_dest_port.low_limit = port_range->low_limit;
329 #ifdef TFT_DEBUG
330 (void)TRACE_EVENT_P1("tft_copy: Copying single destination port filter (port %d)",
331 port_range->low_limit);
332 #endif
333 }
334 } else {
335 dst->v_tft_dest_port_range = (U8)FALSE;
336 dst->v_tft_dest_port = (U8)FALSE;
337 } /* NAS_TFT_ID_DEST_PORT_RANGE */
338
339 /* Copy source single port/port range parameter */
340 if ((valid_flag & NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0)
341 {
342 T_NAS_tft_src_port_range *port_range = &src->tft_src_port_range;
343 if (sm_tft_is_port_range(port_range->low_limit, port_range->high_limit))
344 {
345 dst->v_tft_src_port_range = (U8)TRUE;
346 dst->v_tft_src_port = (U8)FALSE;
347 dst->tft_src_port_range.low_limit = port_range->low_limit;
348 dst->tft_src_port_range.high_limit = port_range->high_limit;
349 #ifdef TFT_DEBUG
350 (void)TRACE_EVENT_P2("tft_copy: Copying source port range filter (ports %d-%d)",
351 port_range->low_limit, port_range->high_limit);
352 #endif
353 } else {
354 dst->v_tft_src_port_range = (U8)FALSE;
355 dst->v_tft_src_port = (U8)TRUE;
356 dst->tft_src_port.low_limit = port_range->low_limit;
357 #ifdef TFT_DEBUG
358 (void)TRACE_EVENT_P1("tft_copy: Copying single source port filter (port %d)",
359 port_range->low_limit);
360 #endif
361 }
362 } else {
363 dst->v_tft_src_port_range = (U8)FALSE;
364 dst->v_tft_src_port = (U8)FALSE;
365 } /* NAS_TFT_ID_SRC_PORT_RANGE */
366
367 if ((valid_flag & NAS_TFT_ID_IPSEC_SPI) != (U8)0)
368 {
369 dst->v_tft_ipsec_spi = (U8)TRUE;
370 sm_tft_copy_ipsec_spi(&dst->tft_ipsec_spi, src->tft_ipsec_spi);
371 } else {
372 dst->v_tft_ipsec_spi = (U8)FALSE;
373 }/* NAS_TFT_ID_IPSEC_SPI */
374
375 if ((valid_flag & NAS_TFT_ID_TOS_AND_MASK) != (U8)0)
376 {
377 dst->v_tft_tos_and_mask = (U8)TRUE;
378 dst->tft_tos_and_mask.tos_value = src->tft_tos_and_mask.tos_value;
379 dst->tft_tos_and_mask.tos_mask = src->tft_tos_and_mask.tos_mask;
380 } else {
381 dst->v_tft_tos_and_mask = (U8)FALSE;
382 } /* NAS_TFT_ID_TOS_AND_MASK */
383
384 if ((valid_flag & NAS_TFT_ID_FLOW_LABEL) != (U8)0) {
385 (void)TRACE_ERROR("tft_copy: Found flow label in IPv4 packet filter - Discarded...");
386 } /* NAS_TFT_ID_FLOW_LABEL */
387 dst->v_tft_flow_label = (U8)FALSE;
388 }
389
390 /*
391 +------------------------------------------------------------------------------
392 | Function : sm_tft_copy_ipv6_pf
393 +------------------------------------------------------------------------------
394 | Description : Copies an IPv6 TFT filter from src_tft to dst_tft AIM struct.
395 |
396 | Parameters : dst_tft - destination aim TFT structs
397 | src_tft - source TFT structs
398 | valid_flag - valid flags for filter components
399 +------------------------------------------------------------------------------
400 */
401 static void
402 sm_tft_copy_ipv6_pf(/*@out@*/ T_M_SM_tft_filter_entry *dst,
403 T_NAS_tft_pf_ipv6 *src, U8 valid_flag)
404 {
405 /* IPv4 addr/mask never invluded in IPv4 packet filter */
406 dst->v_tft_ipv4_addr_mask = (U8)FALSE;
407
408 /* Copy IPv6 address, if present */
409 if ((valid_flag & NAS_TFT_ID_IPv6_SRC_ADDR_MASK) != (U8)0)
410 {
411 dst->v_tft_ipv6_addr_mask = (U8)TRUE;
412 memcpy(dst->tft_ipv6_addr_mask.src_addr,
413 src->tft_ipv6_src_addr_mask.tft_ipv6_addr,
414 (size_t)NAS_SIZE_IPv6_ADDR);
415 memcpy(dst->tft_ipv6_addr_mask.addr_mask,
416 src->tft_ipv6_src_addr_mask.tft_ipv6_mask,
417 (size_t)NAS_SIZE_IPv6_ADDR);
418 #ifdef TFT_DEBUG
419 /* Dump address/mask */
420 {
421 char addr[SM_SIZE_FORMATTED_IPv6_ADDR], mask[SM_SIZE_FORMATTED_IPv6_ADDR];
422 (void)TRACE_EVENT_P2("tft_copy: Copy IPv6 src addr/mask filter: %s/%s",
423 sm_format_ipv6_addr(dst->tft_ipv6_addr_mask.src_addr, addr),
424 sm_format_ipv6_addr(dst->tft_ipv6_addr_mask.addr_mask, mask));
425 }
426 #endif
427 } else {
428 dst->v_tft_ipv6_addr_mask = (U8)FALSE;
429 } /* NAS_TFT_ID_IPv6_SRC_ADDR_MASK */
430
431 /* Copy IPv6 next header field */
432 if ((valid_flag & NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR) != (U8)0)
433 {
434 dst->v_tft_protocol = (U8)TRUE;
435 dst->tft_protocol.tft_protocol_val = src->tft_next_hdr;
436 #ifdef TFT_DEBUG
437 (void)TRACE_EVENT_P1("tft_copy: Copy IPv6 next header field: 0x%02x",
438 src->tft_next_hdr);
439 #endif
440 } else {
441 dst->v_tft_protocol = (U8)FALSE;
442 } /* NAS_TFT_ID_PROTOCOL_OR_NEXT_HDR */
443
444 /* Copy destination single port/port range parameter */
445 if ((valid_flag & NAS_TFT_ID_DEST_PORT_RANGE) != (U8)0)
446 {
447 T_NAS_tft_dest_port_range *port_range = &src->tft_dest_port_range;
448 if (sm_tft_is_port_range(port_range->low_limit, port_range->high_limit))
449 {
450 dst->v_tft_dest_port_range = (U8)TRUE;
451 dst->v_tft_dest_port = (U8)FALSE;
452 dst->tft_dest_port_range.low_limit = port_range->low_limit;
453 dst->tft_dest_port_range.high_limit = port_range->high_limit;
454 #ifdef TFT_DEBUG
455 (void)TRACE_EVENT_P2("tft_copy: Copying destination port range filter (ports %d-%d)",
456 port_range->low_limit, port_range->high_limit);
457 #endif
458 } else {
459 dst->v_tft_dest_port_range = (U8)FALSE;
460 dst->v_tft_dest_port = (U8)TRUE;
461 dst->tft_dest_port.low_limit = port_range->low_limit;
462 #ifdef TFT_DEBUG
463 (void)TRACE_EVENT_P1("tft_copy: Copying single destination port filter (port %d)",
464 port_range->low_limit);
465 #endif
466 }
467 } else {
468 dst->v_tft_dest_port_range = (U8)FALSE;
469 dst->v_tft_dest_port = (U8)FALSE;
470 } /* NAS_TFT_ID_DEST_PORT_RANGE */
471
472 /* Copy source single port/port range parameter */
473 if ((valid_flag & NAS_TFT_ID_SRC_PORT_RANGE) != (U8)0)
474 {
475 T_NAS_tft_src_port_range *port_range = &src->tft_src_port_range;
476 if (sm_tft_is_port_range(port_range->low_limit, port_range->high_limit))
477 {
478 dst->v_tft_src_port_range = (U8)TRUE;
479 dst->v_tft_src_port = (U8)FALSE;
480 dst->tft_src_port_range.low_limit = port_range->low_limit;
481 dst->tft_src_port_range.high_limit = port_range->high_limit;
482 #ifdef TFT_DEBUG
483 (void)TRACE_EVENT_P2("tft_copy: Copying source port range filter (ports %d-%d)",
484 port_range->low_limit, port_range->high_limit);
485 #endif
486 } else {
487 dst->v_tft_src_port_range = (U8)FALSE;
488 dst->v_tft_src_port = (U8)TRUE;
489 dst->tft_src_port.low_limit = port_range->low_limit;
490 #ifdef TFT_DEBUG
491 (void)TRACE_EVENT_P1("tft_copy: Copying single source port filter (port %d)",
492 port_range->low_limit);
493 #endif
494 }
495 } else {
496 dst->v_tft_src_port_range = (U8)FALSE;
497 dst->v_tft_src_port = (U8)FALSE;
498 } /* NAS_TFT_ID_SRC_PORT_RANGE */
499
500 if ((valid_flag & NAS_TFT_ID_IPSEC_SPI) != (U8)0)
501 {
502 dst->v_tft_ipsec_spi = (U8)TRUE;
503 sm_tft_copy_ipsec_spi(&dst->tft_ipsec_spi, src->tft_ipsec_spi);
504 } else {
505 dst->v_tft_ipsec_spi = (U8)FALSE;
506 } /* NAS_TFT_ID_IPSEC_SPI */
507
508 if ((valid_flag & NAS_TFT_ID_TOS_AND_MASK) != (U8)0)
509 {
510 dst->v_tft_tos_and_mask = (U8)TRUE;
511 dst->tft_tos_and_mask.tos_value = src->tft_tos_and_mask.tos_value;
512 dst->tft_tos_and_mask.tos_mask = src->tft_tos_and_mask.tos_mask;
513 } else {
514 dst->v_tft_tos_and_mask = (U8)FALSE;
515 } /* NAS_TFT_ID_TOS_AND_MASK */
516
517 if ((valid_flag & NAS_TFT_ID_FLOW_LABEL) != (U8)0)
518 {
519 dst->v_tft_flow_label = (U8)TRUE;
520 dst->tft_flow_label.flow_label_value = src->tft_flow_label;
521 } else {
522 dst->v_tft_flow_label = (U8)FALSE;
523 } /* NAS_TFT_ID_FLOW_LABEL */
524 }
525
526 /*
527 +------------------------------------------------------------------------------
528 | Function : sm_tft_copy_filters
529 +------------------------------------------------------------------------------
530 | Description : Copies TFT filters from src_tft to dst_tft AIM structs.
531 |
532 | Parameters : dst_tft - destination aim TFT structs
533 | src_tft - source TFT structs
534 | tft_mask - TFT mask (determines which TFTs to consider)
535 +------------------------------------------------------------------------------
536 */
537 static U8
538 sm_tft_copy_filters(/*@special@*/T_M_SM_tft *dst_tft,
539 /*@in@*/ T_NAS_tft_pf *src_tft,
540 U8 max_count, U8 tft_mask)
541 {
542 int i, count;
543 T_M_SM_tft_filter *dst;
544 U16 size, total_size = 0;
545 U8 change_mask = (U8)0;
546
547 dst_tft->v_tft_filter = (U8)TRUE;
548
549 /* Initialize pointer to air interface TFT */
550 dst = dst_tft->tft_filter;
551
552 for (i = 0, count = 0; i < (int)max_count; i++)
553 {
554 if (sm_tft_is_tft_in_mask(src_tft->tft_pf_id, tft_mask))
555 {
556 size = sm_tft_pf_size(src_tft);
557 /* Only include packet filter, if it fits in air interface message */
558 if (total_size + size > (U16)255) {
559 break;
560 }
561
562 dst->tft_filter_id = src_tft->tft_pf_id;
563 dst->tft_filter_prio = src_tft->tft_pf_precedence;
564
565 if (src_tft->ctrl_tft_pf_entry == NAS_is_tft_pf_ipv4) {
566 sm_tft_copy_ipv4_pf(&dst->tft_filter_entry,
567 &src_tft->tft_pf_entry.tft_pf_ipv4,
568 src_tft->tft_pf_valid_bits);
569 } else if (src_tft->ctrl_tft_pf_entry == NAS_is_tft_pf_ipv6) {
570 sm_tft_copy_ipv6_pf(&dst->tft_filter_entry,
571 &src_tft->tft_pf_entry.tft_pf_ipv6,
572 src_tft->tft_pf_valid_bits);
573 } else {
574 (void)TRACE_EVENT_P1("tft_copy: ERROR! Wrong union controller (%d) "
575 "for tft_pf_entry; discarded...",
576 src_tft->ctrl_tft_pf_entry);
577 }
578 /* Update change mask and total TFT size */
579 change_mask |= (U8)(1UL << dst->tft_filter_id);
580 total_size += size;
581 /* Advance to next destination TFT */
582 dst++;
583 count++;
584 } /* if (sm_tft_is_tft_in_mask()) */
585 /* Skip to next input TFT */
586 src_tft++;
587 }
588
589 dst_tft->c_tft_filter = (U8)count;
590
591 return change_mask;
592 }
593
594 /*
595 +------------------------------------------------------------------------------
596 | Function : sm_tft_copy_filter_numbers
597 +------------------------------------------------------------------------------
598 | Description : Copies filter IDs to dst_tft AIM struct (derived from tft_mask)
599 |
600 | Parameters : dst_tft - destination aim TFT structs
601 | tft_mask - TFT mask (determines which TFTs to consider)
602 +------------------------------------------------------------------------------
603 */
604 static void
605 sm_tft_copy_filter_numbers(/*@special@*/T_M_SM_tft *dst_tft,
606 U8 tft_mask)
607 {
608 int index, dst_idx;
609
610 dst_tft->v_tft_filter_id = (U8)TRUE;
611
612 for (index = 0, dst_idx = 0; index < (int)NAS_SIZE_TFT_FILTER; index++)
613 {
614 if (sm_tft_is_tft_in_mask((U8)index, tft_mask))
615 {
616 dst_tft->tft_filter_id[dst_idx] = (U8)index;
617 dst_idx++;
618 }
619 } /* for */
620
621 /* Set counter to the number of filters numbers inserted */
622 dst_tft->c_tft_filter_id = (U8)dst_idx;
623 }
624
625 /*
626 +------------------------------------------------------------------------------
627 | Function : sm_tft_update_active_tft
628 +------------------------------------------------------------------------------
629 | Description : Update context data structure with new active TFT as it would
630 | be would the modification succeed.
631 |
632 | Parameters : context - context data
633 | tft_mask - TFT mask (determines which TFTs to consider)
634 +------------------------------------------------------------------------------
635 */
636 static void
637 sm_tft_update_active_tft(/*@special@*/struct T_SM_CONTEXT_DATA *context,
638 U8 change_mask)
639 {
640 T_NAS_tft_pf *req_tft, *act_tft;
641 U16 index;
642 U8 req_mask, act_mask, add_mask, delete_mask;
643
644 req_mask = context->requested_tft.tft_precence_mask;
645 act_mask = context->active_tft.tft_precence_mask;
646 add_mask = req_mask & change_mask;
647 delete_mask = (U8)(0xffUL ^ req_mask) & change_mask;
648
649 if (req_mask == (U8)0) {
650 sm_nw_free_active_tft(context);
651 return;
652 }
653
654 TRACE_ASSERT(context->requested_tft.ptr_tft_pf != NULL);
655
656 /* Allocate active TFT memory, if required */
657 if (act_mask == (U8)0 &&
658 /*req_mask != (U8)0 &&*/ /*commented out because of previous return*/
659 context->active_tft.ptr_tft_pf == NULL)
660 {
661 sm_nw_allocate_active_tft(context);
662 TRACE_ASSERT(context->active_tft.ptr_tft_pf != NULL);
663 }
664
665 /* Loop over TFTs, in order to find any TFTs to delete */
666 for (index = 0; index < (U16)NAS_SIZE_TFT_FILTER; index++)
667 {
668 if (sm_tft_is_tft_in_mask((U8)index, delete_mask))
669 {
670 /* Was filter removed ? If so, clear filter from mask and store */
671 act_mask &= (U8)(0xffUL ^ 1UL << index);
672 act_tft = sm_tft_get_active_tft_by_id(context, (U8)index);
673 memset(act_tft, 0, sizeof(T_NAS_tft_pf));
674 }
675 }
676
677 for (index = 0, req_tft = context->requested_tft.ptr_tft_pf;
678 index < (U16)context->requested_tft.c_tft_pf;
679 index++, req_tft++)
680 {
681 U8 pf_id = req_tft->tft_pf_id;
682
683 if (sm_tft_is_tft_in_mask(pf_id, add_mask))
684 {
685 /* Copy any remaining requested TFTs into active TFT */
686 act_mask |= (U8)(1UL << pf_id);
687 act_tft = sm_tft_get_active_tft_by_id(context, pf_id);
688 memcpy(act_tft, req_tft, sizeof(T_NAS_tft_pf));
689 }
690 } /* for */
691
692 context->active_tft.tft_precence_mask = act_mask;
693 context->active_tft.c_tft_pf = sm_tft_count_tfts_in_mask(act_mask);
694 }
695
696 /*
697 +------------------------------------------------------------------------------
698 | Function : sm_tft_next_action
699 +------------------------------------------------------------------------------
700 | Description : Determines the next action to perform (opcode) on the TFTs
701 | for a context, and the filters affected.
702 | (8 upper bits is change mask; 8 lower bits is opcode)
703 |
704 | Parameters : context - context data
705 +------------------------------------------------------------------------------
706 */
707 static U16 sm_tft_next_action(struct T_SM_CONTEXT_DATA *context)
708 {
709 U8 req_mask, act_mask, missing_mask, surplus_mask, replace_mask;
710 U16 index;
711
712 req_mask = context->requested_tft.tft_precence_mask;
713 act_mask = context->active_tft.tft_precence_mask;
714
715 /* If requested TFT contains 0 filters, remove TFT altogether */
716 if (context->requested_tft.c_tft_pf == (U8)0)
717 {
718 return (U16)M_SM_TFT_OPCODE_DELETE_TFT;
719 }
720
721 TRACE_ASSERT(context->requested_tft.ptr_tft_pf != NULL);
722
723 /* If there are no activate TFT filters, and requested != 0, create new TFT */
724 if (act_mask == (U8)0 && req_mask != (U8)0)
725 {
726 return (U16)M_SM_TFT_OPCODE_CREATE_TFT | (U16)req_mask << 8;
727 }
728
729 /* Add filters, if requested filter count > active filter count or
730 * requested filters exist, that are not active. */
731 missing_mask = req_mask & (0xff ^ act_mask);
732
733 if (context->requested_tft.c_tft_pf > context->active_tft.c_tft_pf ||
734 missing_mask != (U8)0)
735 {
736 return (U16)M_SM_TFT_OPCODE_ADD_FILTERS | (U16)missing_mask << 8;
737 }
738
739 /* Delete filters, if requested filter count < active filter count or
740 * active filters exist, that are not requested. */
741 surplus_mask = act_mask & (0xff ^ req_mask);
742
743 if (context->requested_tft.c_tft_pf < context->active_tft.c_tft_pf ||
744 surplus_mask != (U8)0)
745 {
746 return (U16)M_SM_TFT_OPCODE_DELETE_FILTERS | (U16)surplus_mask << 8;
747 }
748
749 /* Now, requested and active TFTs have the same filter *numbers* active;
750 * We then need to check, whether the *contents* of the filters that
751 * have the same number also match. */
752 for (index = 0, replace_mask = (U8)0;
753 index < (U16)context->requested_tft.c_tft_pf;
754 index++)
755 {
756 T_NAS_tft_pf *req_tft = &context->requested_tft.ptr_tft_pf[index];
757 T_NAS_tft_pf *act_tft = sm_tft_get_active_tft_by_id(context, req_tft->tft_pf_id);
758
759 if (!sm_tft_are_equal(req_tft, act_tft))
760 {
761 replace_mask |= (U8)(1UL << req_tft->tft_pf_id);
762 }
763 }
764
765 if (replace_mask != (U8)0) {
766 return (U16)M_SM_TFT_OPCODE_REPLACE_FILTERS | (U16)replace_mask << 8;
767 }
768
769 /* Error. Nothing to change, or invalid configuration */
770 return (U16)M_SM_TFT_OPCODE_SPARE;
771 }
772
773 /*==== PUBLIC FUNCTIONS =====================================================*/
774
775 U8 sm_tft_precence_mask(T_NAS_tft_pf *tft, U8 count)
776 {
777 U16 index;
778 U8 precence_mask = (U8)0;
779
780 for (index = 0; index < (U16)count; index++)
781 {
782 precence_mask |= (1UL << tft[index].tft_pf_id);
783 }
784
785 return precence_mask;
786 }
787
788 void sm_tft_convert_to_aim(struct T_SM_CONTEXT_DATA *context,
789 /*@out@*/ T_M_SM_tft *dst_tft)
790 {
791 U8 opcode, filter_mask, change_mask, max_count;
792 U16 opcode_and_mask;
793
794 T_NAS_tft_pf *src_tft = context->requested_tft.ptr_tft_pf;
795 max_count = context->requested_tft.c_tft_pf;
796
797 if (src_tft == NULL)
798 {
799 return;
800 }
801
802 opcode_and_mask = sm_tft_next_action(context);
803 opcode = (U8)(opcode_and_mask & 0xff);
804 filter_mask = (U8)(opcode_and_mask >> 8);
805
806 dst_tft->tft_opcode = opcode;
807
808 switch (opcode)
809 {
810 case M_SM_TFT_OPCODE_CREATE_TFT:
811 case M_SM_TFT_OPCODE_ADD_FILTERS:
812 case M_SM_TFT_OPCODE_REPLACE_FILTERS:
813 TRACE_ASSERT(src_tft != NULL);
814 /* Copy filter count to air interface message TFT struct */
815 change_mask = sm_tft_copy_filters(dst_tft, src_tft, max_count, filter_mask);
816 sm_tft_update_active_tft(context, change_mask);
817 dst_tft->tft_filter_count = sm_tft_count_tfts_in_mask(change_mask);
818 break;
819
820 case M_SM_TFT_OPCODE_DELETE_TFT:
821 /*
822 * DELETE TFT can have no fields other than TFT opcode and
823 * filter count (== 0), and is thus complete.
824 */
825 context->requested_tft.tft_precence_mask = (U8)0;
826 sm_tft_update_active_tft(context, (U8)0xff);
827 dst_tft->tft_filter_count = (U8)0;
828 break;
829
830 case M_SM_TFT_OPCODE_DELETE_FILTERS:
831 TRACE_ASSERT(src_tft != NULL);
832 /* Copy filter count to air interface message TFT struct */
833 sm_tft_copy_filter_numbers(dst_tft, filter_mask);
834 sm_tft_update_active_tft(context, filter_mask);
835 dst_tft->tft_filter_count = sm_tft_count_tfts_in_mask(filter_mask);
836 break;
837
838 default:
839 (void)TRACE_EVENT_P1("tft_convert_to_aim: ERROR!"
840 "Invalid opcode (%d) - TFT skipped!", opcode);
841 break;
842 }
843 }
844
845 BOOL sm_tft_more_to_modify(struct T_SM_CONTEXT_DATA *context)
846 {
847 int filter;
848
849 (void)TRACE_FUNCTION("sm_tft_more_to_modify");
850
851 if (context->requested_tft.c_tft_pf != context->active_tft.c_tft_pf ||
852 context->requested_tft.tft_precence_mask != context->active_tft.tft_precence_mask)
853 {
854 return TRUE;
855 }
856 if (context->requested_tft.c_tft_pf > (U8)0
857 && context->requested_tft.ptr_tft_pf != NULL
858 && context->active_tft.ptr_tft_pf != NULL)
859 {
860 for (filter = 0; filter < (int)context->requested_tft.c_tft_pf; filter++)
861 {
862 if (!sm_tft_are_equal(&context->requested_tft.ptr_tft_pf[filter],
863 sm_tft_get_active_tft_by_id(context, context->requested_tft.ptr_tft_pf[filter].tft_pf_id)))
864 {
865 return TRUE;
866 }
867 } /* for */
868 } /* if (c_tft_pf > 0) */
869 return FALSE;
870 }