FreeCalypso > hg > fc-magnetite
comparison src/g23m-gprs/llc/llc_rxf.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 +----------------------------------------------------------------------------- | |
3 | Project : | |
4 | Modul : | |
5 +----------------------------------------------------------------------------- | |
6 | Copyright 2002 Texas Instruments Berlin, AG | |
7 | All rights reserved. | |
8 | | |
9 | This file is confidential and a trade secret of Texas | |
10 | Instruments Berlin, AG | |
11 | The receipt of or possession of this file does not convey | |
12 | any rights to reproduce or disclose its contents or to | |
13 | manufacture, use, or sell anything it may describe, in | |
14 | whole, or in part, without the specific written consent of | |
15 | Texas Instruments Berlin, AG. | |
16 +----------------------------------------------------------------------------- | |
17 | Purpose : This modul is part of the entity LLC and implements all | |
18 | procedures and functions as described in the | |
19 | SDL-documentation (RX-statemachine) | |
20 +----------------------------------------------------------------------------- | |
21 */ | |
22 | |
23 #ifndef LLC_RXF_C | |
24 #define LLC_RXF_C | |
25 #endif | |
26 | |
27 #define ENTITY_LLC | |
28 | |
29 /*==== INCLUDES =============================================================*/ | |
30 | |
31 #include <string.h> /* to get memcpy() */ | |
32 | |
33 #include "typedefs.h" /* to get Condat data types */ | |
34 #include "vsi.h" /* to get a lot of macros */ | |
35 #include "macdef.h" | |
36 #include "gprs.h" | |
37 #include "gsm.h" /* to get a lot of macros */ | |
38 #include "cnf_llc.h" /* to get cnf-definitions */ | |
39 #include "mon_llc.h" /* to get mon-definitions */ | |
40 #include "prim.h" /* to get the definitions of used SAP and directions */ | |
41 #include "llc.h" /* to get the global entity definitions */ | |
42 | |
43 #include "llc_rxf.h" /* to get local defines */ | |
44 #include "llc_rxp.h" /* to get the function rx_cci_decipher_cnf */ | |
45 #include "llc_f.h" /* to get global functions, e.g. llc_generate_input */ | |
46 #ifndef TI_PS_OP_CIPH_DRIVER | |
47 #include "cci_fbsf.h" /* to get functional interface */ | |
48 #endif | |
49 /*==== CONST ================================================================*/ | |
50 | |
51 /*==== LOCAL VARS ===========================================================*/ | |
52 | |
53 /*==== PRIVATE FUNCTIONS ====================================================*/ | |
54 #ifndef CF_FAST_EXEC | |
55 | |
56 GLOBAL UBYTE rx_get_desc_octet (T_desc_list *desc_list, | |
57 USHORT offset, | |
58 UBYTE *data_ptr); | |
59 #endif /* CF_FAST_EXEC */ | |
60 | |
61 /*==== PUBLIC FUNCTIONS =====================================================*/ | |
62 | |
63 | |
64 /* | |
65 +------------------------------------------------------------------------------ | |
66 | Function : rx_init | |
67 +------------------------------------------------------------------------------ | |
68 | Description : This procedure initialises all necessary variables of | |
69 | receive_pdu. | |
70 | | |
71 | Parameters : | |
72 | | |
73 +------------------------------------------------------------------------------ | |
74 */ | |
75 #ifndef CF_FAST_EXEC | |
76 | |
77 GLOBAL void rx_init (void) | |
78 { | |
79 TRACE_FUNCTION( "rx_init" ); | |
80 | |
81 /* | |
82 * Initialise service RX with state TLLI_UNASSIGNED. | |
83 */ | |
84 INIT_STATE (RX, RX_TLLI_UNASSIGNED); | |
85 | |
86 return; | |
87 } /* rx_init() */ | |
88 | |
89 #endif /* CF_FAST_EXEC */ | |
90 | |
91 | |
92 /* | |
93 +------------------------------------------------------------------------------ | |
94 | Function : rx_analyse_ctrl_field | |
95 +------------------------------------------------------------------------------ | |
96 | Description : This procedure analyses the received LLC frame control field | |
97 | and sets frame_type according to the frame type (U, UI, I/S). | |
98 | protected_mode is set according to the protected mode of the | |
99 | frame (U and I/S always protected, UI depends on setting of | |
100 | PM bit). The type of protected_mode is the same as in | |
101 | CCI_DECIPHER_REQ. ns is set to N(S) for I frames, N(U) for | |
102 | UI frames, or an undefined value for S and U frames. ciphering | |
103 | is set to TRUE if the frame is ciphered (U never, I/S always, | |
104 | UI depends on setting of E bit), otherwise to FALSE. frame_ok | |
105 | indicates if the frame contains enough octets to contain a | |
106 | known control field (i.e. all necessary information is | |
107 | accessible, not the control field is complete!). | |
108 | | |
109 | Parameters : grlc_unitdata_ind - a valid pointer to a GRLC_UNITDATA_IND | |
110 | primitive | |
111 | frame_type - a valid pointer to a T_PDU_TYPE variable | |
112 | protected_mode - a valid pointer to a UBYTE variable | |
113 | sapi - a valid pointer to a UBYTE variable | |
114 | ns - a valid pointer to a T_FRAME_NUM variable | |
115 | ciphering - a valid pointer to a BOOL variable | |
116 | header_size - a valid pointer to a USHORT variable | |
117 | frame_ok - a valid pointer to a BOOL variable | |
118 | | |
119 +------------------------------------------------------------------------------ | |
120 */ | |
121 | |
122 #ifndef CF_FAST_EXEC | |
123 | |
124 GLOBAL void rx_analyse_ctrl_field (T_GRLC_UNITDATA_IND *grlc_unitdata_ind, | |
125 T_PDU_TYPE *frame_type, | |
126 UBYTE *protected_mode, | |
127 UBYTE *sapi, | |
128 T_FRAME_NUM *ns, | |
129 BOOL *ciphering, | |
130 USHORT *header_size, | |
131 BOOL *frame_ok) | |
132 { | |
133 UBYTE first_octet; | |
134 UBYTE sec_octet; | |
135 UBYTE command_octet; | |
136 UBYTE sack_k_octet; | |
137 | |
138 | |
139 TRACE_FUNCTION( "rx_analyse_ctrl_field" ); | |
140 | |
141 /* | |
142 * Check if the frame contains enough octets to access the first octet of | |
143 * the control field to find out the type of the frame. | |
144 */ | |
145 if (grlc_unitdata_ind->desc_list.list_len < CTRL_MIN_OCTETS) | |
146 { | |
147 *frame_ok = FALSE; | |
148 return; | |
149 } | |
150 | |
151 /* | |
152 * Assume initially that the frame is ok. | |
153 */ | |
154 *frame_ok = TRUE; | |
155 | |
156 /* | |
157 * Set first_octet to the value of the first frame octet (offset 0), which | |
158 * is the address field. | |
159 */ | |
160 rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 0, &first_octet); | |
161 | |
162 *sapi = first_octet & 0x0F; | |
163 | |
164 /* | |
165 * Set sec_octet to the value of the second frame octet (offset 1), which | |
166 * is the first octet of the control field. | |
167 */ | |
168 rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 1, &sec_octet); | |
169 | |
170 | |
171 /* | |
172 * Determine frame_type, along with ns, protected_mode, and ciphering, | |
173 * depending on the frame type. | |
174 */ | |
175 if ((sec_octet & I_FRAME_MASK) EQ I_FRAME_ID) | |
176 { | |
177 /* | |
178 * I frame, protected, ciphered, at least 4 octets required to access all | |
179 * requested information (1 Address, 3 Control). | |
180 */ | |
181 *frame_type = I_FRAME; | |
182 *protected_mode = CCI_PM_PROTECTED; | |
183 *ciphering = TRUE; | |
184 | |
185 /* | |
186 * Check if the frame contains enough octets to access the complete | |
187 * I frame control field. | |
188 */ | |
189 if (grlc_unitdata_ind->desc_list.list_len < I_CTRL_MIN_OCTETS) | |
190 { | |
191 *frame_ok = FALSE; | |
192 return; | |
193 } | |
194 | |
195 /* | |
196 * Determine the header_size | |
197 */ | |
198 *header_size = I_CTRL_MIN_OCTETS; | |
199 | |
200 /* | |
201 * Add bytes in case of SACK-Bitmap (add K+1). Therefore get at first | |
202 * the command octet (offset 3). In case of an SACK, get next the k | |
203 * octet (offset 4) and add the additional size. | |
204 */ | |
205 rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 3, &command_octet); | |
206 | |
207 if ( (command_octet & 0x03) == I_FRAME_SACK ) | |
208 { | |
209 *header_size += 1; /* k octet */ | |
210 | |
211 if (grlc_unitdata_ind->desc_list.list_len < *header_size) | |
212 { | |
213 *frame_ok = FALSE; | |
214 return; | |
215 } | |
216 | |
217 rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 4, &sack_k_octet); | |
218 | |
219 *header_size += (sack_k_octet & 0x1F); /* bitmap size */ | |
220 | |
221 if (grlc_unitdata_ind->desc_list.list_len < *header_size) | |
222 { | |
223 *frame_ok = FALSE; | |
224 return; | |
225 } | |
226 } | |
227 | |
228 /* | |
229 * Extract N(S) and store it in ns. | |
230 */ | |
231 *ns = (((T_FRAME_NUM) | |
232 rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 1, NULL)) & 0x1F) << 4; | |
233 *ns |= (((T_FRAME_NUM) | |
234 rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 2, NULL)) >> 4); | |
235 } | |
236 else if ((sec_octet & S_FRAME_MASK) EQ S_FRAME_ID) | |
237 { | |
238 /* | |
239 * S frame, protected, not ciphered. No N(S) present, only N(R). | |
240 */ | |
241 *frame_type = S_FRAME; | |
242 *protected_mode = CCI_PM_PROTECTED; | |
243 *ciphering = FALSE; | |
244 | |
245 *header_size = S_CTRL_MIN_OCTETS; | |
246 | |
247 /* not necessary to add bytes in case of SACK - value is not used */ | |
248 } | |
249 else if ((sec_octet & UI_FRAME_MASK) EQ UI_FRAME_ID) | |
250 { | |
251 /* | |
252 * UI frame, at least 3 octets required to access all requested | |
253 * information (1 Address, 2 Control). | |
254 */ | |
255 *frame_type = UI_FRAME; | |
256 | |
257 /* | |
258 * Check if the frame contains enough octets to access the complete | |
259 * UI frame control field. | |
260 */ | |
261 if (grlc_unitdata_ind->desc_list.list_len < UI_CTRL_MIN_OCTETS) | |
262 { | |
263 *frame_ok = FALSE; | |
264 return; | |
265 } | |
266 | |
267 /* | |
268 * Extract protected mode setting of frame (PM bit). | |
269 */ | |
270 if (rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 2, NULL) & 0x01) | |
271 { | |
272 *protected_mode = CCI_PM_PROTECTED; | |
273 } | |
274 else | |
275 { | |
276 *protected_mode = CCI_PM_UNPROTECTED; | |
277 } | |
278 | |
279 /* | |
280 * Extract ciphering setting of frame (E bit). | |
281 */ | |
282 if (rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 2, NULL) & 0x02) | |
283 { | |
284 *ciphering = TRUE; | |
285 } | |
286 else | |
287 { | |
288 *ciphering = FALSE; | |
289 } | |
290 | |
291 *header_size = UI_CTRL_MIN_OCTETS; | |
292 | |
293 /* | |
294 * Extract N(U) and store it in ns. | |
295 */ | |
296 *ns = (((T_FRAME_NUM) | |
297 rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 1, NULL)) & 0x07) << 6; | |
298 *ns |= (((T_FRAME_NUM) | |
299 rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 2, NULL)) >> 2); | |
300 } | |
301 else if ((sec_octet & U_FRAME_MASK) EQ U_FRAME_ID) | |
302 { | |
303 /* | |
304 * U frame, protected, not ciphered. No N(S) present. | |
305 */ | |
306 *frame_type = U_FRAME; | |
307 *protected_mode = CCI_PM_PROTECTED; | |
308 *ciphering = FALSE; | |
309 | |
310 *header_size = U_CTRL_MIN_OCTETS; | |
311 } | |
312 | |
313 return; | |
314 } /* rx_analyse_ctrl_field() */ | |
315 | |
316 #endif /* CF_FAST_EXEC */ | |
317 | |
318 /* | |
319 +------------------------------------------------------------------------------ | |
320 | Function : rx_decipher_req | |
321 +------------------------------------------------------------------------------ | |
322 | Description : Handles the function rx_decipher_req. This functions sets the | |
323 | ciphering parameters and calls the deciphering driver function. | |
324 | | |
325 | Parameters : | |
326 | | |
327 +------------------------------------------------------------------------------ | |
328 */ | |
329 | |
330 #ifndef CF_FAST_EXEC | |
331 GLOBAL void rx_decipher_req (T_CCI_DECIPHER_REQ *decipher_req) | |
332 { | |
333 T_CIPH_init_cipher_req_parms init_cipher_req_parms; | |
334 T_CIPH_cipher_req_parms cipher_req_parms; | |
335 T_CIPH_in_data_list in_data_list; | |
336 T_CIPH_out_data out_data; | |
337 T_CIPH_ck ck; | |
338 U16 i; | |
339 U8 status; | |
340 U16 cnt = 0; | |
341 | |
342 TRACE_FUNCTION( "rx_decipher_req" ); | |
343 | |
344 #ifdef LLC_TRACE_CIPHERING | |
345 TRACE_EVENT("DOWNLINK CIPHERED DATA"); | |
346 llc_trace_desc_list(&decipher_req->desc_list); | |
347 #endif | |
348 | |
349 /* | |
350 * Copy pointer to desc's from CIPHER_REQ to the in_data_list | |
351 * The in_data array in allocated dynamically in this func. | |
352 */ | |
353 llc_copy_dl_data_to_list(decipher_req, &in_data_list); | |
354 /* | |
355 * Set ciphering parameters | |
356 */ | |
357 cipher_req_parms.gprs_parameters.pm = decipher_req->pm; | |
358 cipher_req_parms.gprs_parameters.header_size = decipher_req->header_size; | |
359 cipher_req_parms.gprs_parameters.ciphering_input = | |
360 decipher_req->ciphering_input; | |
361 cipher_req_parms.gprs_parameters.threshold = 0; | |
362 init_cipher_req_parms.direction = CIPH_DOWNLINK_DIR; | |
363 init_cipher_req_parms.algo = decipher_req->ciphering_algorithm; | |
364 init_cipher_req_parms.ptr_ck = & ck; | |
365 /* | |
366 * Copy ciphering key | |
367 */ | |
368 for (i = 0; i < 8;i++) { | |
369 init_cipher_req_parms.ptr_ck->ck_element[i] = decipher_req->kc.key[i]; | |
370 } | |
371 | |
372 { | |
373 /* Use GRLC_DATA_REQ instead of CCI_CIPHER_CNF to avoid PPASS in LLC*/ | |
374 PALLOC_SDU (ll_unitdata_ind, LL_UNITDATA_IND, | |
375 (USHORT)((decipher_req->desc_list.list_len*8) - FCS_SIZE_BITS)); | |
376 | |
377 ll_unitdata_ind->sdu.o_buf = 0; | |
378 ll_unitdata_ind->sdu.l_buf = 0; | |
379 out_data.buf = | |
380 (U32)(&ll_unitdata_ind->sdu.buf[ll_unitdata_ind->sdu.o_buf >> 3]); | |
381 /* | |
382 * Initialize ciphering driver and decipher data | |
383 */ | |
384 #ifdef TI_PS_OP_CIPH_DRIVER | |
385 ciph_init_cipher_req (&init_cipher_req_parms, NULL); | |
386 ciph_cipher_req (&cipher_req_parms, &in_data_list, &out_data, &status); | |
387 #else | |
388 ciph_init_cipher_req_sim (&init_cipher_req_parms, NULL); | |
389 ciph_cipher_req_sim (&cipher_req_parms, &in_data_list, &out_data, &status); | |
390 #endif | |
391 /* | |
392 * "Send" DECIPHER_CNF to LLC | |
393 */ | |
394 ll_unitdata_ind->sdu.l_buf = out_data.len * 8; | |
395 ll_unitdata_ind->tlli = decipher_req->reference1; | |
396 ll_unitdata_ind->cipher = (UBYTE)decipher_req->reference2; | |
397 if (status == CIPH_CIPH_PASS){ | |
398 ll_unitdata_ind->sapi = CCI_FCS_PASSED; | |
399 } else { | |
400 ll_unitdata_ind->sapi = CCI_FCS_FAILED; | |
401 } | |
402 | |
403 #ifdef LLC_TRACE_CIPHERING | |
404 TRACE_EVENT("DOWNLINK DECIPHERED DATA"); | |
405 llc_trace_sdu(&ll_unitdata_ind->sdu); | |
406 #endif | |
407 rx_cci_decipher_cnf(ll_unitdata_ind); | |
408 } | |
409 /* | |
410 * Free in_data array from in_data_list allocated in llc_copy_dl_data_to_list | |
411 */ | |
412 if(in_data_list.ptr_in_data != NULL){ | |
413 MFREE(in_data_list.ptr_in_data); | |
414 in_data_list.ptr_in_data = NULL; | |
415 } | |
416 /* | |
417 * Free descriptors from the deipher_req->desc_list | |
418 */ | |
419 if (decipher_req != NULL) | |
420 { | |
421 T_desc *desc = (T_desc *)decipher_req->desc_list.first; | |
422 T_desc *next_desc; | |
423 while (desc NEQ NULL){ | |
424 next_desc = (T_desc *)desc->next; | |
425 MFREE (desc); | |
426 desc = next_desc; | |
427 /* increase freed partitions counter */ | |
428 cnt++; | |
429 } | |
430 MFREE(decipher_req); | |
431 decipher_req = NULL; | |
432 } | |
433 llc_data->fbs.cci_freed_partition +=cnt; | |
434 | |
435 /* trace number of freed partitions */ | |
436 if(llc_data->fbs.cci_info_trace){ | |
437 TRACE_EVENT_P2("INFO CCI: freed partitions %ld, total=%ld", | |
438 cnt,llc_data->fbs.cci_freed_partition); | |
439 } | |
440 | |
441 } /* rx_decipher_req */ | |
442 | |
443 #endif | |
444 | |
445 /* | |
446 +------------------------------------------------------------------------------ | |
447 | Function : rx_send_decipher_req | |
448 +------------------------------------------------------------------------------ | |
449 | Description : This procedure allocates the CCI_DECIPHER_REQ primitive, fills | |
450 | in all necessary parameters and sends the primitive to CCI. | |
451 | | |
452 | Parameters : grlc_unitdata_ind - a valid pointer to a GRLC_UNITDATA_IND | |
453 | primitive | |
454 | frame_type - indicates (un)acknowledged operation mode | |
455 | protected_mode - pm setting for CCI_DECIPHER_REQ | |
456 | ns - N(S)/N(U) for deciphering, otherwise | |
457 | undefined value | |
458 | header_size - size of header bytes (not ciphered bytes) | |
459 | ciphering - indicates deciphering (TRUE/FALSE) | |
460 | | |
461 +------------------------------------------------------------------------------ | |
462 */ | |
463 #ifndef CF_FAST_EXEC | |
464 | |
465 GLOBAL void rx_send_decipher_req (T_GRLC_UNITDATA_IND *grlc_unitdata_ind, | |
466 T_PDU_TYPE frame_type, | |
467 UBYTE protected_mode, | |
468 T_FRAME_NUM ns, | |
469 USHORT header_size, | |
470 BOOL ciphering) | |
471 { | |
472 ULONG oc; | |
473 | |
474 TRACE_FUNCTION ("rx_send_decipher_req"); | |
475 | |
476 { | |
477 /* | |
478 * No need to PPASS GRLC_xDATA_IND, because desc_list contains a pointer | |
479 * which can be simply copied. | |
480 */ | |
481 T_CCI_DECIPHER_REQ *cci_decipher_req; | |
482 MALLOC(cci_decipher_req, sizeof(T_CCI_DECIPHER_REQ)); | |
483 | |
484 /* | |
485 * Requires rx_analyse_ctrl_field() to set a correct CCI value. | |
486 */ | |
487 cci_decipher_req->pm = protected_mode; | |
488 | |
489 if (ciphering EQ TRUE) | |
490 { | |
491 cci_decipher_req->reference2 = LL_CIPHER_ON; /* re-use of reference is ok */ | |
492 cci_decipher_req->ciphering_algorithm = llc_data->ciphering_algorithm; | |
493 memcpy (&cci_decipher_req->kc, &llc_data->kc, sizeof(T_kc)); | |
494 | |
495 /* | |
496 * Calculate the OC which is valid for this ns. This could be the | |
497 * current OC or OC + 1 in case of an modulo overflow of ns | |
498 */ | |
499 switch (frame_type) | |
500 { | |
501 case I_FRAME: | |
502 case S_FRAME: | |
503 if (ns >= llc_data->sapi->vr) | |
504 oc = llc_data->sapi->oc_i_rx; | |
505 else | |
506 oc = llc_data->sapi->oc_i_rx + (MAX_SEQUENCE_NUMBER+1); | |
507 break; | |
508 | |
509 default: | |
510 if (ns >= llc_data->sapi->vur) | |
511 oc = llc_data->sapi->oc_ui_rx; | |
512 else | |
513 oc = llc_data->sapi->oc_ui_rx + (MAX_SEQUENCE_NUMBER+1); | |
514 break; | |
515 } | |
516 | |
517 llc_generate_input (llc_data->current_sapi, frame_type, ns, | |
518 &cci_decipher_req->ciphering_input, oc); | |
519 | |
520 cci_decipher_req->direction = CCI_DIRECTION_DOWNLINK; | |
521 } | |
522 else /* ciphering EQ FALSE */ | |
523 { | |
524 cci_decipher_req->reference2 = LL_CIPHER_OFF; | |
525 cci_decipher_req->ciphering_algorithm = CCI_CIPHER_NO_ALGORITHM; | |
526 } | |
527 | |
528 cci_decipher_req->header_size = header_size; | |
529 | |
530 /* | |
531 * TLLI must be stored somewhere | |
532 */ | |
533 cci_decipher_req->reference1 = grlc_unitdata_ind->tlli; | |
534 | |
535 cci_decipher_req->desc_list = grlc_unitdata_ind->desc_list; | |
536 | |
537 /* TRACE_EVENT ("CCI thread not available, using functional interface"); */ | |
538 | |
539 rx_decipher_req(cci_decipher_req); | |
540 } | |
541 | |
542 return; | |
543 } /* rx_send_decipher_req() */ | |
544 | |
545 #endif /* CF_FAST_EXEC */ | |
546 | |
547 /* | |
548 +------------------------------------------------------------------------------ | |
549 | Function : rx_interpret_frame | |
550 +------------------------------------------------------------------------------ | |
551 | Description : This procedure analyses the LLC header and checksum of the | |
552 | given frame (U, UI, or I) and sets sapi, pdu_type, command, | |
553 | cr_bit, pf_bit, nr, and ns accordingly. The FCS field is not | |
554 | included in frame, it has already been stripped off. frame_ok | |
555 | is set to TRUE if the frame fulfils the following requirements: | |
556 | known PDU type, valid length, valid PD bit, valid SAPI. | |
557 | frame_rej indicates a frame rejection condition if any bit of | |
558 | W4-W1 is set. If a frame is rejected, frame_rej_ctrl_length | |
559 | indicates the length of the control field. If this length | |
560 | could not be determined, frame_rej_ctrl_length is set to the | |
561 | number of control field octets of the frame. | |
562 | | |
563 | Parameters : frame - contains the frame to be analysed, must be | |
564 | a valid pointer | |
565 | sapi - will be set to the SAPI of the frame, must be | |
566 | a valid pointer | |
567 | pdu_type - will be set to the PDU type of the frame, must be | |
568 | a valid pointer | |
569 | command - will be set to the command (I/S, U) of the frame | |
570 | (if available), must be a valid pointer | |
571 | cr_bit - will be set to the C/R bit of the frame, must be | |
572 | a valid pointer | |
573 | pf_bit - will be set to the P/F bit of the frame (if | |
574 | available), must be a valid pointer | |
575 | nr - will be set to N(R) / N(U) of the frame (if | |
576 | available), must be a valid pointer | |
577 | ns - will be set to N(S) of the frame (if available), | |
578 | must be a valid pointer | |
579 | frame_ok - TRUE if the frame is ok, else FALSE, must be | |
580 | a valid pointer | |
581 | frame_rej - indicates a frame rejection condition, must be | |
582 | a valid pointer | |
583 | frame_rej_ctrl_length - number of octets in the rejected | |
584 | control field, must be a valid pointer | |
585 | | |
586 +------------------------------------------------------------------------------ | |
587 */ | |
588 | |
589 /*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \ | |
590 !defined(REL99) || defined(LL_2to1) */ | |
591 | |
592 GLOBAL void rx_interpret_frame (T_sdu *frame, | |
593 UBYTE *sapi, | |
594 T_PDU_TYPE *pdu_type, | |
595 T_COMMAND *command, | |
596 T_BIT *cr_bit, | |
597 T_BIT *pf_bit, | |
598 T_FRAME_NUM *nr, | |
599 T_FRAME_NUM *ns, | |
600 BOOL *frame_ok, | |
601 UBYTE *frame_rej, | |
602 USHORT *frame_rej_ctrl_length, | |
603 UBYTE cipher) | |
604 { | |
605 USHORT min_length = 0; /* minimum required frame length */ | |
606 BOOL check_length; /* check/ignore length at the end */ | |
607 | |
608 TRACE_FUNCTION( "rx_interpret_frame" ); | |
609 | |
610 /* | |
611 * Preset variables with suspected success, control field length is not | |
612 * yet known, so assume complete frame length. | |
613 */ | |
614 *frame_ok = TRUE; | |
615 *frame_rej = FRAME_NOT_REJ; | |
616 *frame_rej_ctrl_length = frame->l_buf/8 - 1; | |
617 | |
618 /* | |
619 * Frame length is selectively activated, depending on frame type, command, | |
620 * etc. Ignore frame length per default. | |
621 */ | |
622 check_length = FALSE; | |
623 | |
624 | |
625 /* | |
626 * Check if the frame contains enough octets to access the first octet of | |
627 * the control field to find out the type of the frame. | |
628 */ | |
629 if (frame->l_buf/8 < CTRL_MIN_OCTETS) | |
630 { | |
631 *frame_ok = FALSE; | |
632 return; | |
633 } | |
634 | |
635 | |
636 /* | |
637 * Check if PD bit is set to 0. If it is not, the frame is invalid. | |
638 * <R.LLC.XCEPTION.A.001> | |
639 */ | |
640 if ((frame->buf[frame->o_buf/8] & 0x80) != 0x00) | |
641 { | |
642 *frame_ok = FALSE; | |
643 return; | |
644 } | |
645 | |
646 | |
647 /* | |
648 * Extract C/R bit. | |
649 */ | |
650 *cr_bit = (frame->buf[frame->o_buf/8] & 0x40) >> 6; | |
651 | |
652 | |
653 /* | |
654 * Extract SAPI and check if the frame contains a reserved SAPI. | |
655 * <R.LLC.XCEPTION.A.001> | |
656 */ | |
657 *sapi = frame->buf[frame->o_buf/8] & 0x0F; | |
658 switch (*sapi) /* !!!!! constants or function/macro to determine invalid sapis */ | |
659 { | |
660 case 0: | |
661 case 2: | |
662 case 4: | |
663 case 6: | |
664 case 8: | |
665 case 10: | |
666 case 12: | |
667 case 13: | |
668 case 14: | |
669 case 15: | |
670 { | |
671 *frame_ok = FALSE; | |
672 return; | |
673 } | |
674 } | |
675 | |
676 | |
677 /* | |
678 * Determine the PDU type of the frame, along with the minimum length | |
679 * required for this PDU type to constitute a complete frame. | |
680 * Additionally, extract available variables for each PDU type. | |
681 */ | |
682 if ((frame->buf[(frame->o_buf/8)+1] & I_FRAME_MASK) EQ I_FRAME_ID) | |
683 { | |
684 /* | |
685 * I frame, at least 5 octets (1 Address, 3 Control, 1(++) | |
686 * Information, no FCS) | |
687 */ | |
688 *pdu_type = I_FRAME; | |
689 min_length = I_FRAME_MIN_OCTETS_WITHOUT_FCS; | |
690 *frame_rej_ctrl_length = I_CTRL_OCTETS; | |
691 | |
692 /* | |
693 * Extract A bit (stored in P/F bit) | |
694 */ | |
695 *pf_bit = (frame->buf[(frame->o_buf/8)+1] & 0x40) >> 6; | |
696 | |
697 /* | |
698 * Check if the frame contains enough octets to access the complete | |
699 * I frame control field. | |
700 */ | |
701 if (frame->l_buf/8 < I_CTRL_MIN_OCTETS) | |
702 { | |
703 *frame_ok = FALSE; | |
704 return; | |
705 } | |
706 | |
707 /* | |
708 * Extract N(S), N(R) | |
709 */ | |
710 *ns = (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+1] & 0x1F) << 4; | |
711 *ns |= (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+2] >> 4); | |
712 | |
713 *nr = (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+2] & 0x07) << 6; | |
714 *nr |= (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+3] >> 2); | |
715 | |
716 /* | |
717 * Determine the command of the I frame (S1 & S2 bits) | |
718 */ | |
719 switch (frame->buf[(frame->o_buf/8)+3] & 0x03) | |
720 { | |
721 case I_FRAME_RR: | |
722 TRACE_4_PARA("I-RR s:%d len:%d nr:%d ns:%d", *sapi, BYTELEN(frame->l_buf), *nr, *ns); | |
723 *command = I_RR; | |
724 break; | |
725 | |
726 case I_FRAME_ACK: | |
727 TRACE_4_PARA("I-ACK s:%d len:%d nr:%d ns:%d", *sapi, BYTELEN(frame->l_buf), *nr, *ns); | |
728 *command = I_ACK; | |
729 break; | |
730 | |
731 case I_FRAME_RNR: | |
732 TRACE_4_PARA("I-RNR s:%d len:%d nr:%d ns:%d", *sapi, BYTELEN(frame->l_buf), *nr, *ns); | |
733 *command = I_RNR; | |
734 break; | |
735 | |
736 case I_FRAME_SACK: | |
737 TRACE_4_PARA("I-SACK s:%d len:%d nr:%d ns:%d", *sapi, BYTELEN(frame->l_buf), *nr, *ns); | |
738 *command = I_SACK; | |
739 | |
740 /* | |
741 * Check if the frame contains enough octets to access the complete | |
742 * I frame SACK control field. K is at octet I_CTRL_MIN_OCTETS + 1 | |
743 * and there must be at least K+1 octets within the bitmap. Therefore | |
744 * the frame must contain a minimum of I_CTRL_MIN_OCTETS+2. | |
745 */ | |
746 if (frame->l_buf/8 < I_CTRL_MIN_OCTETS+2) | |
747 { | |
748 *frame_ok = FALSE; | |
749 return; | |
750 } | |
751 | |
752 /* | |
753 * min_length is being modified to be more accurate for SACK frames, | |
754 * according to the Bitmap Length Indicator K in | |
755 * frame->buf[(frame->o_buf/8)+4]. | |
756 */ | |
757 min_length += (frame->buf[(frame->o_buf/8)+4] & 0x1F) + 1; | |
758 | |
759 check_length = TRUE; | |
760 break; | |
761 | |
762 default: | |
763 /* | |
764 * Frame rejection condition due to receipt of a command or | |
765 * response field that is undefined or not implemented (set | |
766 * W3 bit to 1). | |
767 * <R.LLC.XCEPTION.A.002> | |
768 */ | |
769 *frame_ok = FALSE; | |
770 *frame_rej = FRAME_REJ_W3; | |
771 return; | |
772 } | |
773 } | |
774 else if ((frame->buf[(frame->o_buf/8)+1] & S_FRAME_MASK) EQ S_FRAME_ID) | |
775 { | |
776 /* | |
777 * S frame, fixed 3 octets (1 Address, 2 Control, 0 Information, no FCS) | |
778 */ | |
779 *pdu_type = S_FRAME; | |
780 min_length = S_FRAME_MIN_OCTETS_WITHOUT_FCS; | |
781 *frame_rej_ctrl_length = S_CTRL_OCTETS; | |
782 | |
783 /* | |
784 * Extract A bit (stored in P/F bit) | |
785 */ | |
786 *pf_bit = (frame->buf[(frame->o_buf/8)+1] & 0x20) >> 5; | |
787 | |
788 /* | |
789 * Check if the frame contains enough octets to access the complete | |
790 * S frame control field. | |
791 */ | |
792 if (frame->l_buf/8 < S_CTRL_MIN_OCTETS) | |
793 { | |
794 *frame_ok = FALSE; | |
795 *frame_rej = FRAME_REJ_W1; | |
796 *frame_rej_ctrl_length = frame->l_buf/8 - 1; | |
797 return; | |
798 } | |
799 | |
800 /* | |
801 * Extract N(R) | |
802 */ | |
803 *nr = (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+1] & 0x07) << 6; | |
804 *nr |= (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+2] >> 2); | |
805 | |
806 /* | |
807 * Determine the command of the S frame (S1 & S2 bits) | |
808 */ | |
809 switch (frame->buf[(frame->o_buf/8)+2] & 0x03) | |
810 { | |
811 case I_FRAME_RR: | |
812 TRACE_2_PARA("S-RR s:%d nr:%d", *sapi, *nr); | |
813 *command = I_RR; | |
814 check_length = TRUE; | |
815 break; | |
816 | |
817 case I_FRAME_ACK: | |
818 TRACE_2_PARA("S-ACK s:%d nr:%d", *sapi, *nr); | |
819 *command = I_ACK; | |
820 check_length = TRUE; | |
821 break; | |
822 | |
823 case I_FRAME_RNR: | |
824 TRACE_2_PARA("S-RNR s:%d nr:%d", *sapi, *nr); | |
825 *command = I_RNR; | |
826 check_length = TRUE; | |
827 break; | |
828 | |
829 case I_FRAME_SACK: | |
830 TRACE_2_PARA("S-SACK s:%d nr:%d", *sapi, *nr); | |
831 *command = I_SACK; | |
832 /* | |
833 * min_length is being modified to be more accurate for SACK frames. | |
834 * The S frame SACK format adds a number of up to 32 octets to the | |
835 * control field. | |
836 */ | |
837 min_length += S_FRAME_SACK_MIN_CTRL_OCTETS; | |
838 | |
839 check_length = FALSE; | |
840 break; | |
841 | |
842 default: | |
843 /* | |
844 * Frame rejection condition due to receipt of a command or | |
845 * response field that is undefined or not implemented (set | |
846 * W3 bit to 1). | |
847 * <R.LLC.XCEPTION.A.002> | |
848 */ | |
849 *frame_ok = FALSE; | |
850 *frame_rej = FRAME_REJ_W3; | |
851 return; | |
852 } | |
853 } | |
854 else if ((frame->buf[(frame->o_buf/8)+1] & UI_FRAME_MASK) EQ UI_FRAME_ID) | |
855 { | |
856 /* | |
857 * UI frame, at least 3 octets (1 Address, 2 Control, 0(++) | |
858 * Information, no FCS) | |
859 */ | |
860 *pdu_type = UI_FRAME; | |
861 min_length = UI_FRAME_MIN_OCTETS_WITHOUT_FCS; | |
862 *frame_rej_ctrl_length = UI_CTRL_OCTETS; | |
863 | |
864 /* | |
865 * Check if the frame contains enough octets to access the complete | |
866 * UI frame control field. | |
867 */ | |
868 if (frame->l_buf/8 < UI_CTRL_MIN_OCTETS) | |
869 { | |
870 *frame_ok = FALSE; | |
871 return; | |
872 } | |
873 | |
874 /* | |
875 * Extract N(U) (is stored in N(R)) | |
876 */ | |
877 *nr = (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+1] & 0x07) << 6; | |
878 *nr |= (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+2] >> 2); | |
879 | |
880 TRACE_4_PARA("UI s:%d len:%d nr:%d c:%d", *sapi, BYTELEN(frame->l_buf), *nr, cipher); | |
881 } | |
882 else if ((frame->buf[(frame->o_buf/8)+1] & U_FRAME_MASK) EQ U_FRAME_ID) | |
883 { | |
884 /* | |
885 * U frame, at least 2 octets (1 Address, 1 Control, 0(++) | |
886 * Information, no FCS) | |
887 */ | |
888 *pdu_type = U_FRAME; | |
889 min_length = U_FRAME_MIN_OCTETS_WITHOUT_FCS; | |
890 *frame_rej_ctrl_length = U_CTRL_OCTETS; | |
891 | |
892 /* | |
893 * Extract P/F bit | |
894 */ | |
895 *pf_bit = (frame->buf[(frame->o_buf/8)+1] & 0x10) >> 4; | |
896 | |
897 /* | |
898 * Check if the frame contains enough octets to access the complete | |
899 * U frame control field. | |
900 * NOTE: | |
901 * This check could be omitted, because the U frame control field size | |
902 * is only one octet. | |
903 */ | |
904 if (frame->l_buf/8 < U_CTRL_MIN_OCTETS) | |
905 { | |
906 *frame_ok = FALSE; | |
907 *frame_rej = FRAME_REJ_W1; | |
908 return; | |
909 } | |
910 | |
911 /* | |
912 * Determine the command of the U frame (M4, M3, M2, M1). | |
913 * Adjust the minimum length of the frame, if possible. | |
914 */ | |
915 switch (frame->buf[(frame->o_buf/8)+1] & 0x0F) | |
916 { | |
917 case U_FRAME_DM: | |
918 TRACE_1_PARA("DM s:%d", *sapi); | |
919 *command = U_DM; | |
920 /* | |
921 * No information field is permitted. | |
922 */ | |
923 check_length = TRUE; | |
924 break; | |
925 case U_FRAME_DISC: | |
926 TRACE_1_PARA("DISC s:%d", *sapi); | |
927 *command = U_DISC; | |
928 /* | |
929 * No information field is permitted. | |
930 */ | |
931 check_length = TRUE; | |
932 break; | |
933 case U_FRAME_UA: | |
934 TRACE_2_PARA("UA s:%d len:%d", *sapi, BYTELEN(frame->l_buf)); | |
935 *command = U_UA; | |
936 /* | |
937 * No knowledge if an information field is permitted, because | |
938 * this is only the case when UA is the response to SABM. | |
939 */ | |
940 break; | |
941 case U_FRAME_SABM: | |
942 TRACE_2_PARA("SABM s:%d len:%d", *sapi, BYTELEN(frame->l_buf)); | |
943 *command = U_SABM; | |
944 /* | |
945 * An information field is permitted, containing XID | |
946 * parameters. Therefore the size of the information field | |
947 * is not (yet) known. | |
948 */ | |
949 break; | |
950 case U_FRAME_FRMR: | |
951 TRACE_1_PARA("FRMR s:%d", *sapi); | |
952 *command = U_FRMR; | |
953 /* | |
954 * FRMR response contains an information field of 10 octets. | |
955 * <R.LLC.XCEPTION.A.008> | |
956 */ | |
957 min_length += U_FRAME_FRMR_INFO_OCTETS; | |
958 check_length = TRUE; | |
959 break; | |
960 case U_FRAME_XID: | |
961 if( *cr_bit == SGSN_COMMAND ) | |
962 { | |
963 TRACE_2_PARA("XID REQ s:%d len:%d", *sapi, BYTELEN(frame->l_buf)); | |
964 } | |
965 else | |
966 { | |
967 TRACE_2_PARA("XID RSP s:%d len:%d", *sapi, BYTELEN(frame->l_buf)); | |
968 } | |
969 *command = U_XID; | |
970 /* | |
971 * An information field is required, containing XID | |
972 * parameters. Therefore the size of the information field | |
973 * is not (yet) known. | |
974 */ | |
975 break; | |
976 default: | |
977 TRACE_0_INFO("Not supported U frame received"); | |
978 /* | |
979 * Frame rejection condition due to receipt of a command or | |
980 * response field that is undefined or not implemented (set | |
981 * W3 bit to 1). | |
982 * <R.LLC.XCEPTION.A.002> | |
983 */ | |
984 *frame_ok = FALSE; | |
985 *frame_rej = FRAME_REJ_W3; | |
986 return; | |
987 } | |
988 } | |
989 | |
990 | |
991 /* | |
992 * Determine if it is requested to check the frame length exactly | |
993 * (check_length EQ TRUE), or just to check the minimum frame length | |
994 * (check_length EQ FALSE). | |
995 */ | |
996 if (check_length AND (frame->l_buf/8 NEQ min_length)) | |
997 { | |
998 /* | |
999 * Actual length of frame doesn't correspond with computed length. | |
1000 */ | |
1001 *frame_ok = FALSE; | |
1002 | |
1003 /* | |
1004 * Check if frame rejection condition occured: S or U frame with | |
1005 * incorrect length (= W1 + W3 bits). frame_rej_ctrl_length has already | |
1006 * been set above to the correct control field length. | |
1007 * <R.LLC.XCEPTION.A.002>, <R.LLC.XCEPTION.A.010> | |
1008 */ | |
1009 if ((*pdu_type EQ S_FRAME) OR (*pdu_type EQ U_FRAME)) | |
1010 { | |
1011 *frame_rej = FRAME_REJ_W1 | FRAME_REJ_W3; | |
1012 } | |
1013 return; | |
1014 } | |
1015 else if (frame->l_buf/8 < min_length) | |
1016 { | |
1017 /* | |
1018 * Frame doesn't contain enough octets to include the address field, | |
1019 * control field, information field, and FCS field necessary to constitute | |
1020 * a complete frame according to the PDU type. | |
1021 * <R.LLC.XCEPTION.A.001> | |
1022 */ | |
1023 *frame_ok = FALSE; | |
1024 return; | |
1025 } | |
1026 | |
1027 return; | |
1028 } /* rx_interpret_frame() */ | |
1029 | |
1030 /* #endif */ /* CF_FAST_EXEC || _SIMULATION_ */ | |
1031 | |
1032 | |
1033 /* | |
1034 +------------------------------------------------------------------------------ | |
1035 | Function : rx_strip_llc_header | |
1036 +------------------------------------------------------------------------------ | |
1037 | Description : This procedure strips the LLC header field off of the sdu | |
1038 | so that the sdu contains only the remaining L3-PDU. | |
1039 | | |
1040 | Parameters : sdu - contains the SDU (frame), must be a valid pointer | |
1041 | pdu_type - contains the PDU type of the frame, must be | |
1042 | a valid PDU type | |
1043 | command - contains the command (I/S, U) of the frame, must be | |
1044 | a valid command for the given PDU type | |
1045 | | |
1046 +------------------------------------------------------------------------------ | |
1047 */ | |
1048 | |
1049 #ifndef CF_FAST_EXEC | |
1050 | |
1051 GLOBAL void rx_strip_llc_header (T_sdu *sdu, | |
1052 T_PDU_TYPE pdu_type, | |
1053 T_COMMAND command) | |
1054 { | |
1055 UBYTE header_len = 0; | |
1056 | |
1057 | |
1058 TRACE_FUNCTION ("rx_strip_llc_header"); | |
1059 | |
1060 switch (pdu_type) | |
1061 { | |
1062 case I_FRAME: | |
1063 /* | |
1064 * I frame 4 octets. Leave SACK Bitmap in PDU, will be stripped later! | |
1065 * (1 Address, 3Control). | |
1066 */ | |
1067 header_len = I_CTRL_MIN_OCTETS; | |
1068 break; | |
1069 case S_FRAME: | |
1070 /* | |
1071 * S frame 3 octets. Leave SACK Bitmap in PDU, will be stripped later! | |
1072 * (1 Address, 2(+32 max) Control). | |
1073 */ | |
1074 header_len = S_CTRL_MIN_OCTETS; | |
1075 break; | |
1076 case UI_FRAME: | |
1077 /* | |
1078 * UI frame, 3 octets (1 Address, 2 Control). | |
1079 */ | |
1080 header_len = UI_CTRL_MIN_OCTETS; | |
1081 break; | |
1082 case U_FRAME: | |
1083 /* | |
1084 * U frame, 2 octets (1 Address, 1 Control). | |
1085 */ | |
1086 header_len = U_CTRL_MIN_OCTETS; | |
1087 break; | |
1088 default: | |
1089 TRACE_ERROR ("Unknown PDU type"); | |
1090 break; | |
1091 } | |
1092 | |
1093 /* | |
1094 * Adjust the beginning of the PDU using the determined header_len. | |
1095 */ | |
1096 sdu->o_buf += header_len * 8; | |
1097 | |
1098 /* | |
1099 * Adjust the length of the PDU by the size of the header field. | |
1100 */ | |
1101 sdu->l_buf -= header_len * 8; | |
1102 | |
1103 return; | |
1104 } /* rx_strip_llc_header() */ | |
1105 | |
1106 #endif /* CF_FAST_EXEC */ | |
1107 | |
1108 /* | |
1109 +------------------------------------------------------------------------------ | |
1110 | Function : rx_get_desc_octet | |
1111 +------------------------------------------------------------------------------ | |
1112 | Description : This procedure maps the given linear offset to a descriptor | |
1113 | list and returns the value of the octet at this offset. If | |
1114 | offset is too large for descriptor list, 0x00 is returned. | |
1115 | Each descriptor in descriptor list is evaluated until the | |
1116 | requested offset is reached. The resulting octet value is | |
1117 | written to the referenced parameter data_ptr (if not set to | |
1118 | NULL), and is additionally returned. | |
1119 | | |
1120 | Parameters : desc_list - a valid pointer to a valid descriptor list | |
1121 | offset - linear octet offset, beginning with 0 | |
1122 | data_ptr - a valid pointer to be set to the resulting octet | |
1123 | value, or NULL | |
1124 | | |
1125 +------------------------------------------------------------------------------ | |
1126 */ | |
1127 | |
1128 #ifndef CF_FAST_EXEC | |
1129 | |
1130 GLOBAL UBYTE rx_get_desc_octet (T_desc_list *desc_list, | |
1131 USHORT offset, | |
1132 UBYTE *data_ptr) | |
1133 { | |
1134 T_desc *desc; | |
1135 UBYTE *desc_data; /* local pointer to data octet */ | |
1136 | |
1137 /* | |
1138 * Check if offset is contained in descriptor list. Return 0x00 if not. | |
1139 */ | |
1140 if (offset >= desc_list->list_len) | |
1141 { | |
1142 TRACE_ERROR ("offset too large for descriptor list"); | |
1143 return 0x00; | |
1144 } | |
1145 | |
1146 /* | |
1147 * Search requested data with given linear offset in descriptor list. | |
1148 * Empty descriptors are skipped. Check for each descriptor if requested | |
1149 * offset is in descriptor, until it is found. | |
1150 */ | |
1151 desc = (T_desc *)desc_list->first; | |
1152 desc_data = NULL; | |
1153 do | |
1154 { | |
1155 if (offset < desc->len) | |
1156 { | |
1157 /* | |
1158 * Requested data is in current descriptor. Set desc_data to point to | |
1159 * requested octet with remaining offset (has been decremented by | |
1160 * already passed descriptor payload). | |
1161 */ | |
1162 /*lint -e662 Possible creation of out-of-bounds pointer */ | |
1163 desc_data = &(desc->buffer[offset]); | |
1164 } | |
1165 else | |
1166 { | |
1167 /* | |
1168 * Requested data is not in current descriptor. Remember data payload | |
1169 * of current descriptor as already passed. | |
1170 */ | |
1171 offset -= desc->len; | |
1172 } | |
1173 | |
1174 desc = (T_desc *)desc->next; | |
1175 } | |
1176 while ((desc NEQ NULL) AND (desc_data EQ NULL)); | |
1177 | |
1178 | |
1179 if (desc_data EQ NULL) | |
1180 { | |
1181 TRACE_ERROR ("descriptor list ended before offset found"); | |
1182 | |
1183 if (data_ptr NEQ NULL) | |
1184 { | |
1185 *data_ptr = 0; | |
1186 } | |
1187 | |
1188 return 0; | |
1189 } | |
1190 else | |
1191 { | |
1192 /* | |
1193 * Store value of found octet in data_ptr, if pointer is valid. | |
1194 */ | |
1195 if (data_ptr NEQ NULL) | |
1196 { | |
1197 /*lint -e661 Possible access of out-of-bounds pointer */ | |
1198 *data_ptr = *desc_data; | |
1199 } | |
1200 | |
1201 return *desc_data; | |
1202 } | |
1203 } /* rx_get_desc_octet() */ | |
1204 | |
1205 #endif /* CF_FAST_EXEC */ |