FreeCalypso > hg > fc-magnetite
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 } |