FreeCalypso > hg > fc-selenite
comparison src/g23m-gprs/llc/llc_txf.c @ 1:d393cd9bb723
src/g23m-*: initial import from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 15 Jul 2018 04:40:46 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:b6a5e36de839 | 1:d393cd9bb723 |
---|---|
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 (TX-statemachine) | |
20 +----------------------------------------------------------------------------- | |
21 */ | |
22 | |
23 #ifndef LLC_TXF_C | |
24 #define LLC_TXF_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_f.h" /* to get global functions, e.g. llc_generate_input */ | |
44 #include "llc_txf.h" /* to get the global entity definitions */ | |
45 #include "llc_txp.h" /* to get the function tx_cci_cipher_cnf */ | |
46 | |
47 #include "llc_uitxs.h" /* to get signal interface to UITX */ | |
48 #include "llc_itxs.h" /* to get signal interface to ITX */ | |
49 | |
50 #ifndef TI_PS_OP_CIPH_DRIVER | |
51 #include "cci_fbsf.h" /* to get functional interface */ | |
52 #endif | |
53 | |
54 | |
55 /*==== CONST ================================================================*/ | |
56 | |
57 /*==== LOCAL VARS ===========================================================*/ | |
58 | |
59 /*==== PRIVATE FUNCTIONS ====================================================*/ | |
60 | |
61 /*==== PUBLIC FUNCTIONS =====================================================*/ | |
62 | |
63 | |
64 /* | |
65 +------------------------------------------------------------------------------ | |
66 | Function : tx_init | |
67 +------------------------------------------------------------------------------ | |
68 | Description : This procedure initialises all necessary variables of send_pdu. | |
69 | | |
70 | Parameters : | |
71 | | |
72 +------------------------------------------------------------------------------ | |
73 */ | |
74 GLOBAL void llc_tx_init (void) | |
75 { | |
76 TRACE_FUNCTION( "tx_init" ); | |
77 | |
78 /* | |
79 * Initialise TX with state NOT_READY. | |
80 */ | |
81 INIT_STATE (TX, TX_TLLI_UNASSIGNED_NOT_READY); | |
82 | |
83 /* | |
84 * Flush TX queue, if there is (in case of an LLC | |
85 * restart) old stuff queued. | |
86 */ | |
87 tx_clear_buffer(); | |
88 | |
89 return; | |
90 } /* tx_init() */ | |
91 | |
92 | |
93 /* | |
94 +------------------------------------------------------------------------------ | |
95 | Function : tx_clear_buffer | |
96 +------------------------------------------------------------------------------ | |
97 | Description : This procedure frees all buffered CCI_CIPHER_CNF primitives. | |
98 | | |
99 | Parameters : | |
100 | | |
101 +------------------------------------------------------------------------------ | |
102 */ | |
103 GLOBAL void tx_clear_buffer (void) | |
104 { | |
105 T_TX_QUEUE *elem; | |
106 T_TX_QUEUE *elem_next; | |
107 | |
108 | |
109 TRACE_FUNCTION( "tx_clear_buffer" ); | |
110 | |
111 for (elem = llc_data->tx.queue; elem NEQ NULL; elem = elem_next) | |
112 { | |
113 elem_next = elem->next; | |
114 | |
115 /* | |
116 * Free primitive if any is stored in queue element. | |
117 */ | |
118 if (elem->primitive NEQ (ULONG)NULL) | |
119 { | |
120 PFREE (elem->primitive); | |
121 } | |
122 | |
123 MFREE (elem); | |
124 } | |
125 | |
126 llc_data->tx.queue = NULL; | |
127 | |
128 /* | |
129 * Initialise UITX space counter for each SAPI. | |
130 */ | |
131 llc_data->tx.queue_counter_uitx[0] = UITX_1_QUEUE_SIZE; | |
132 llc_data->tx.queue_counter_uitx[1] = UITX_3_QUEUE_SIZE; | |
133 llc_data->tx.queue_counter_uitx[2] = UITX_5_QUEUE_SIZE; | |
134 llc_data->tx.queue_counter_uitx[3] = UITX_7_QUEUE_SIZE; | |
135 llc_data->tx.queue_counter_uitx[4] = UITX_9_QUEUE_SIZE; | |
136 llc_data->tx.queue_counter_uitx[5] = UITX_11_QUEUE_SIZE; | |
137 | |
138 /* | |
139 * Initialise ITX space counter for each SAPI. | |
140 */ | |
141 llc_data->tx.queue_counter_itx[0] = ITX_3_QUEUE_SIZE; | |
142 llc_data->tx.queue_counter_itx[1] = ITX_5_QUEUE_SIZE; | |
143 llc_data->tx.queue_counter_itx[2] = ITX_9_QUEUE_SIZE; | |
144 llc_data->tx.queue_counter_itx[3] = ITX_11_QUEUE_SIZE; | |
145 | |
146 return; | |
147 } /* tx_clear_buffer() */ | |
148 | |
149 /* | |
150 +------------------------------------------------------------------------------ | |
151 | Function : tx_cipher_req | |
152 +------------------------------------------------------------------------------ | |
153 | Description : Handles the function tx_cipher_req. This functions sets the | |
154 | ciphering parameters and calls the ciphering driver function. | |
155 | | |
156 | Parameters : todo | |
157 | | |
158 +------------------------------------------------------------------------------ | |
159 */ | |
160 GLOBAL void tx_cipher_req | |
161 ( | |
162 #ifdef LL_DESC | |
163 T_CCI_CIPHER_DESC_REQ *cipher_req | |
164 #else | |
165 T_CCI_CIPHER_REQ *cipher_req | |
166 #endif | |
167 ) | |
168 | |
169 { | |
170 T_CIPH_init_cipher_req_parms init_cipher_req_parms; | |
171 T_CIPH_cipher_req_parms cipher_req_parms; | |
172 T_CIPH_in_data_list in_data_list; | |
173 T_CIPH_out_data out_data; | |
174 T_CIPH_ck ck; | |
175 U16 i; | |
176 U8 status; | |
177 | |
178 TRACE_FUNCTION( "tx_cipher_req" ); | |
179 | |
180 #ifdef LLC_TRACE_CIPHERING | |
181 TRACE_EVENT("UPLINK NON CIPHERED DATA"); | |
182 llc_trace_desc_list3_content(cipher_req->desc_list3); | |
183 #endif | |
184 /* | |
185 * Copy pointer to desc's from CIPHER_REQ to the in_data_list | |
186 * The in_data array in allocated dynamically in this func. | |
187 */ | |
188 llc_copy_ul_data_to_list(cipher_req, &in_data_list); | |
189 /* | |
190 * Store ciphering parameters | |
191 */ | |
192 cipher_req_parms.gprs_parameters.pm = cipher_req->pm; | |
193 cipher_req_parms.gprs_parameters.header_size = cipher_req->header_size; | |
194 cipher_req_parms.gprs_parameters.ciphering_input = cipher_req->ciphering_input; | |
195 cipher_req_parms.gprs_parameters.threshold = 0; | |
196 init_cipher_req_parms.direction = CIPH_UPLINK_DIR; | |
197 init_cipher_req_parms.algo = cipher_req->ciphering_algorithm; | |
198 init_cipher_req_parms.ptr_ck = & ck; | |
199 /* | |
200 * Copy ciphering key | |
201 */ | |
202 for (i=0; i<8;i++){ | |
203 init_cipher_req_parms.ptr_ck->ck_element[i] = cipher_req->kc.key[i]; | |
204 } | |
205 | |
206 { | |
207 /* Use GRLC_DATA_REQ instead of CCI_CIPHER_CNF to avoid PPASS in LLC*/ | |
208 PALLOC_SDU (grlc_data_req, GRLC_DATA_REQ, | |
209 (USHORT)(cipher_req->desc_list3.list_len*8 + FCS_SIZE_BITS)); | |
210 | |
211 grlc_data_req->sdu.o_buf = 0; | |
212 grlc_data_req->sdu.l_buf = 0; | |
213 out_data.buf = (U32)(&grlc_data_req->sdu.buf[grlc_data_req->sdu.o_buf]); | |
214 /* | |
215 * Initialize ciphering driver and cipher data | |
216 */ | |
217 #ifdef TI_PS_OP_CIPH_DRIVER | |
218 ciph_init_cipher_req (&init_cipher_req_parms, NULL); | |
219 ciph_cipher_req (&cipher_req_parms, &in_data_list, &out_data, &status); | |
220 #else | |
221 ciph_init_cipher_req_sim (&init_cipher_req_parms, NULL); | |
222 ciph_cipher_req_sim (&cipher_req_parms, &in_data_list, &out_data, &status); | |
223 #endif | |
224 | |
225 /* | |
226 * "Send" CIPHER_CNF to LLC | |
227 */ | |
228 grlc_data_req->sdu.l_buf = out_data.len * 8; | |
229 grlc_data_req->tlli = cipher_req->reference1; | |
230 | |
231 #ifdef LLC_TRACE_CIPHERING | |
232 TRACE_EVENT("UPLINK CIPHERED DATA"); | |
233 llc_trace_sdu(&grlc_data_req->sdu); | |
234 #endif | |
235 tx_cci_cipher_cnf (grlc_data_req); | |
236 | |
237 } | |
238 /* | |
239 * Remove in use mark from the cipher request primitive | |
240 */ | |
241 if (cipher_req != NULL) { | |
242 { | |
243 /* | |
244 * Free cipher request, if not further used by other entities | |
245 */ | |
246 if (cipher_req->attached_counter == CCI_NO_ATTACHE) { | |
247 #ifdef LL_DESC | |
248 llc_cl_desc3_free((T_desc3*)cipher_req->desc_list3.first); | |
249 #endif /* LL_DESC */ | |
250 } | |
251 } | |
252 MFREE (cipher_req); | |
253 cipher_req = NULL; | |
254 } | |
255 /* | |
256 * Free in_data array from in_data_list | |
257 * allocated dynamically in llc_copy_ul_data_to_list() | |
258 */ | |
259 if(in_data_list.ptr_in_data != NULL){ | |
260 MFREE(in_data_list.ptr_in_data); | |
261 in_data_list.ptr_in_data = NULL; | |
262 } | |
263 | |
264 } /* tx_cipher_req() */ | |
265 | |
266 /* | |
267 +------------------------------------------------------------------------------ | |
268 | Function : tx_send_cipher_req | |
269 +------------------------------------------------------------------------------ | |
270 | Description : This procedure fills all necessary parameters in the primitive | |
271 | CCI_CIPHER_REQ and sends the primitive to CCI. | |
272 | | |
273 | Parameters : cci_cipher_req - a valid pointer to a CCI_CIPHER_REQ primitive | |
274 | frame_type - indicates frame type (e.g. UI_FRAME) | |
275 | protected_mode - PM bit setting for CCI_CIPHER_REQ | |
276 | ns - N(U) for UI frames | |
277 | cipher - indicates if frame shall be ciphered or not | |
278 | oc - | |
279 | | |
280 +------------------------------------------------------------------------------ | |
281 */ | |
282 GLOBAL void tx_send_cipher_req | |
283 ( | |
284 #ifdef LL_DESC | |
285 T_CCI_CIPHER_DESC_REQ *cci_cipher_desc_req, | |
286 #else | |
287 T_CCI_CIPHER_REQ *cci_cipher_desc_req, | |
288 #endif | |
289 T_PDU_TYPE frame_type, | |
290 UBYTE protected_mode, | |
291 T_FRAME_NUM ns, | |
292 UBYTE cipher, | |
293 ULONG oc | |
294 ) | |
295 { | |
296 TRACE_FUNCTION( "tx_send_cipher_req" ); | |
297 | |
298 cci_cipher_desc_req->pm = protected_mode; | |
299 | |
300 if ( (cipher EQ LL_CIPHER_ON) AND | |
301 (llc_data->ciphering_algorithm NEQ LLGMM_CIPHER_NO_ALGORITHM) ) | |
302 { | |
303 cci_cipher_desc_req->ciphering_algorithm = llc_data->ciphering_algorithm; | |
304 memcpy (&cci_cipher_desc_req->kc, &llc_data->kc, sizeof(T_kc)); | |
305 | |
306 llc_generate_input (llc_data->current_sapi, frame_type, ns, | |
307 &cci_cipher_desc_req->ciphering_input, oc); | |
308 | |
309 cci_cipher_desc_req->direction = CCI_DIRECTION_UPLINK; | |
310 } | |
311 else /* LL_CIPHER_OFF */ | |
312 { | |
313 cci_cipher_desc_req->ciphering_algorithm = CCI_CIPHER_NO_ALGORITHM; | |
314 } | |
315 | |
316 tx_cipher_req (cci_cipher_desc_req); | |
317 return; | |
318 } /* tx_send_cipher_desc_req() */ | |
319 | |
320 | |
321 /* | |
322 +------------------------------------------------------------------------------ | |
323 | Function : tx_reserve_buffer | |
324 +------------------------------------------------------------------------------ | |
325 | Description : This procedure allocates an element for the local transmit | |
326 | queue. If cause is DEFAULT or MOBILITY_MANAGEMENT, the element | |
327 | is appended at the end of the queue, otherwise it is inserted | |
328 | at the beginning. Necessary data like primitive header | |
329 | information and additional important data for the (resulting) | |
330 | GRLC_xDATA_REQ primitive is stored in the reserved buffer | |
331 | element. The primitive pointer in the element is set to NULL, | |
332 | to indicate that the element is not yet 'ready to send'. | |
333 | Parameter reservation_no will be set to the allocation number | |
334 | of the element. Parameter buffer_available will be set to TRUE | |
335 | if additional data primitives can be buffered for the current | |
336 | sapi, otherwise it will be set to FALSE. | |
337 | | |
338 | Parameters : ll_unitdata_req - a valid pointer to a LL_UNITDATA_REQ | |
339 | primitive, containing the data to be sent | |
340 | prim_type - indicates GRLC_DATA/UNITDATA_REQ | |
341 | cause - frame cause, only valid for GRLC_DATA_REQ | |
342 | rx_service - service for flow control (if any) | |
343 | reservation_no - associated number for the buffer entry | |
344 | buffer_available - still buffer space available for current | |
345 | SAPI | |
346 | | |
347 +------------------------------------------------------------------------------ | |
348 */ | |
349 GLOBAL void tx_reserve_buffer | |
350 ( | |
351 #ifdef LL_DESC | |
352 T_LL_UNITDESC_REQ *ll_unitdesc_req, | |
353 #else | |
354 T_LL_UNITDATA_REQ *ll_unitdesc_req, | |
355 #endif | |
356 T_PRIM_TYPE prim_type, | |
357 UBYTE cause, | |
358 T_SERVICE rx_service, | |
359 ULONG *reservation_no, | |
360 BOOL *buffer_available | |
361 ) | |
362 { | |
363 T_TX_QUEUE *elem; | |
364 T_TX_QUEUE **insert; | |
365 | |
366 static ULONG allocation_number = 0; | |
367 | |
368 TRACE_FUNCTION ("tx_reserve_buffer"); | |
369 | |
370 MALLOC (elem, sizeof(T_TX_QUEUE)); | |
371 | |
372 /* | |
373 * Increase allocation number. Use of reservation_no must correspond | |
374 * to use in tx_store_buffer(). | |
375 */ | |
376 *reservation_no = ++(allocation_number); | |
377 | |
378 /* | |
379 * Store all required information in new queue element. Member primitive | |
380 * is set to NULL to indicate that the element is not yet ready to be sent. | |
381 * Copy necessary primitive header information to ph_* variables. | |
382 */ | |
383 elem->primitive = (ULONG)NULL; | |
384 elem->prim_type = prim_type; | |
385 elem->reference = allocation_number; | |
386 elem->rx_service = rx_service; | |
387 elem->remove_frame = FALSE; | |
388 elem->ph_sapi = ll_unitdesc_req->sapi; | |
389 elem->ph_tlli = ll_unitdesc_req->tlli; | |
390 elem->ph_grlc_qos_peak = ll_unitdesc_req->ll_qos.peak; | |
391 elem->ph_radio_prio = ll_unitdesc_req->radio_prio; | |
392 elem->ph_cause = cause; | |
393 #ifdef REL99 | |
394 elem->ph_pkt_flow_id = (UBYTE)ll_unitdesc_req->pkt_flow_id; | |
395 #endif /* REL99 */ | |
396 | |
397 if ((cause EQ GRLC_DTACS_DEF) OR (cause EQ GRLC_DTACS_MOBILITY_MANAGEMENT)) | |
398 { | |
399 /* | |
400 * "Normal" frame cause, append element at the end of queue. Let insert | |
401 * either point to llc_data->tx.queue or to the member .next of an element. | |
402 */ | |
403 insert = &llc_data->tx.queue; | |
404 while (*insert NEQ NULL) | |
405 { | |
406 insert = &((*insert)->next); | |
407 } | |
408 | |
409 /* | |
410 * Insert new element at found location and mark element as last in queue. | |
411 */ | |
412 *insert = elem; | |
413 elem->next = NULL; | |
414 } | |
415 else /* GRLC_DTACS_PAGE_RESPONSE OR GRLC_DTACS_CELL_UPDATE */ | |
416 { | |
417 /* | |
418 * No "normal" frame cause, thus LLGMM_TRIGGER_REQ must have been | |
419 * received. Insert element at the beginning of queue. | |
420 */ | |
421 elem->next = llc_data->tx.queue; | |
422 llc_data->tx.queue = elem; | |
423 } | |
424 | |
425 /* | |
426 * Check if a service for flow control is specified (currently only | |
427 * SERVICE_UITX and SERVICE_ITX are recognized). | |
428 */ | |
429 *buffer_available = FALSE; | |
430 | |
431 if (rx_service EQ SERVICE_UITX) | |
432 { | |
433 /* | |
434 * Decrement the space counter of UITX primitives in the queue for the | |
435 * current SAPI. This means that one place of the queue is occupied. | |
436 * Check if there is space for one more primitive in the queue. | |
437 */ | |
438 int n = llc_data->tx.queue_counter_uitx[UIMAP(llc_data->current_sapi)]; | |
439 | |
440 if (n > 0) | |
441 { | |
442 llc_data->tx.queue_counter_uitx[UIMAP(llc_data->current_sapi)]--; | |
443 | |
444 if (n > 1) | |
445 { | |
446 *buffer_available = TRUE; | |
447 } | |
448 } | |
449 else | |
450 { | |
451 TRACE_EVENT ("Check uitx-queue flow"); | |
452 } | |
453 } | |
454 else if (rx_service EQ SERVICE_ITX) | |
455 { | |
456 /* | |
457 * Decrement the space counter of ITX primitives in the queue for the | |
458 * current SAPI. This means that one place of the queue is occupied. | |
459 * Check if there is space for one more primitive in the queue. | |
460 */ | |
461 int n = llc_data->tx.queue_counter_itx[IMAP(llc_data->current_sapi)]; | |
462 | |
463 if (n > 0) | |
464 { | |
465 llc_data->tx.queue_counter_itx[IMAP(llc_data->current_sapi)]--; | |
466 | |
467 if (n > 1) | |
468 { | |
469 *buffer_available = TRUE; | |
470 } | |
471 } | |
472 else | |
473 { | |
474 TRACE_EVENT ("Check itx-queue flow"); | |
475 } | |
476 } | |
477 else | |
478 { | |
479 /* | |
480 * All other services (e.g. SERVICE_U) are allowed to send primitives | |
481 * per default. I.E. no flow control, except for service UITX and ITX. | |
482 */ | |
483 *buffer_available = TRUE; | |
484 } | |
485 } /* tx_reserve_buffer() */ | |
486 | |
487 | |
488 /* | |
489 +------------------------------------------------------------------------------ | |
490 | Function : tx_store_buffer | |
491 +------------------------------------------------------------------------------ | |
492 | Description : This procedure stores the given CCI primitive as GRLC primitive | |
493 | in the already reserved local transmit queue element that is | |
494 | given with primitive parameter reference. This queue element | |
495 | is marked as 'ready to send'. The CCI primitive is being | |
496 | PPASSED as GRLC_DATA_REQ/GRLC_UNITDATA_REQ, according to | |
497 | prim_type in the queue element. All header information for | |
498 | the GRLC primitive is being filled in from the already stored | |
499 | data in the element. | |
500 | | |
501 | Parameters : cci_cipher_cnf - a valid pointer to a CCI_CIPHER_CNF primitive | |
502 | | |
503 +------------------------------------------------------------------------------ | |
504 */ | |
505 GLOBAL void tx_store_buffer (T_GRLC_DATA_REQ *grlc_data_req) | |
506 { | |
507 T_TX_QUEUE *elem = llc_data->tx.queue; | |
508 | |
509 | |
510 TRACE_FUNCTION ("tx_store_buffer"); | |
511 | |
512 /* | |
513 * Find corresponding queue entry. Use of reference must correspond to | |
514 * use in tx_reserve_buffer(). | |
515 */ | |
516 while (elem NEQ NULL) | |
517 { | |
518 if (elem->reference EQ grlc_data_req->tlli) | |
519 { | |
520 break; | |
521 } | |
522 | |
523 elem = elem->next; | |
524 } | |
525 | |
526 if (elem NEQ NULL) | |
527 { | |
528 if (elem->prim_type EQ PRIM_DATA) | |
529 { | |
530 /* | |
531 * Copy information from stored primitive header variables (ph_*) to | |
532 * GRLC primitive. | |
533 */ | |
534 grlc_data_req->sapi = elem->ph_sapi; | |
535 grlc_data_req->tlli = elem->ph_tlli; | |
536 #ifdef LL_2to1 | |
537 grlc_data_req->grlc_qos.peak = elem->ph_grlc_qos_peak; | |
538 #else | |
539 grlc_data_req->grlc_qos.peak = elem->ph_grlc_qos_peak; | |
540 #endif | |
541 grlc_data_req->radio_prio = elem->ph_radio_prio; | |
542 grlc_data_req->cause = elem->ph_cause; | |
543 | |
544 #ifdef REL99 | |
545 grlc_data_req->pkt_flow_id[0] = elem->ph_pkt_flow_id; | |
546 #endif /* REL99*/ | |
547 | |
548 #ifdef _SIMULATION_ | |
549 /* | |
550 * Initialize all (unused) members of grlc_qos, because otherwise the test | |
551 * cases fail. | |
552 */ | |
553 #ifdef LL_2to1 | |
554 grlc_data_req->grlc_qos.delay = PS_DELAY_SUB; | |
555 grlc_data_req->grlc_qos.relclass = PS_RELCLASS_SUB; | |
556 grlc_data_req->grlc_qos.preced = PS_PRECED_SUB; | |
557 grlc_data_req->grlc_qos.mean = PS_MEAN_SUB; | |
558 #else | |
559 grlc_data_req->grlc_qos.delay = GRLC_DELAY_SUB; | |
560 grlc_data_req->grlc_qos.relclass = GRLC_RELCLASS_SUB; | |
561 grlc_data_req->grlc_qos.preced = GRLC_PRECED_SUB; | |
562 grlc_data_req->grlc_qos.mean = GRLC_MEAN_SUB; | |
563 #endif | |
564 | |
565 #endif /* _SIMULATION_ */ | |
566 | |
567 elem->primitive = (ULONG)grlc_data_req; | |
568 } | |
569 else /* PRIM_UNITDATA */ | |
570 { | |
571 /* | |
572 * Store CCI primitive as GRLC_UNITDATA_REQ (and mark it as stored). | |
573 */ | |
574 PPASS (grlc_data_req, grlc_unitdata_req, GRLC_UNITDATA_REQ); | |
575 | |
576 /* | |
577 * Copy information from stored primitive header variables (ph_*) to | |
578 * GRLC primitive (omit ph_cause, because it is not present in | |
579 * GRLC_UNITDATA_REQ). | |
580 */ | |
581 grlc_unitdata_req->sapi = elem->ph_sapi; | |
582 grlc_unitdata_req->tlli = elem->ph_tlli; | |
583 #ifdef LL_2to1 | |
584 grlc_unitdata_req->grlc_qos.peak = elem->ph_grlc_qos_peak; | |
585 #else | |
586 grlc_unitdata_req->grlc_qos.peak = elem->ph_grlc_qos_peak; | |
587 #endif | |
588 grlc_unitdata_req->radio_prio = elem->ph_radio_prio; | |
589 #ifdef REL99 | |
590 grlc_unitdata_req->pkt_flow_id[0] = elem->ph_pkt_flow_id; | |
591 #endif /* REL99*/ | |
592 #ifdef _SIMULATION_ | |
593 /* | |
594 * Initialize all (unused) members of grlc_qos, because otherwise the test | |
595 * cases fail. | |
596 */ | |
597 #ifdef LL_2to1 | |
598 grlc_unitdata_req->grlc_qos.delay = PS_DELAY_SUB; | |
599 grlc_unitdata_req->grlc_qos.relclass = PS_RELCLASS_SUB; | |
600 grlc_unitdata_req->grlc_qos.preced = PS_PRECED_SUB; | |
601 grlc_unitdata_req->grlc_qos.mean = PS_MEAN_SUB; | |
602 #else | |
603 grlc_unitdata_req->grlc_qos.delay = GRLC_DELAY_SUB; | |
604 grlc_unitdata_req->grlc_qos.relclass = GRLC_RELCLASS_SUB; | |
605 grlc_unitdata_req->grlc_qos.preced = GRLC_PRECED_SUB; | |
606 grlc_unitdata_req->grlc_qos.mean = GRLC_MEAN_SUB; | |
607 #endif /* LL_2to1 */ | |
608 | |
609 | |
610 | |
611 | |
612 #endif /* _SIMULATION_ */ | |
613 | |
614 elem->primitive = (ULONG)grlc_unitdata_req; | |
615 } | |
616 } | |
617 else /* elem == NULL */ | |
618 { | |
619 /* | |
620 * elem not found is possible in case of an LLC re-init, reset, | |
621 * unassign, ... | |
622 */ | |
623 TRACE_0_INFO("No TX queue entry for given reference found"); | |
624 PFREE (grlc_data_req); | |
625 } | |
626 | |
627 } /* tx_store_buffer() */ | |
628 | |
629 | |
630 /* | |
631 +------------------------------------------------------------------------------ | |
632 | Function : tx_get_next_frame | |
633 +------------------------------------------------------------------------------ | |
634 | Description : When LLC is not suspended, this procedure gets (and removes) | |
635 | the first primitive out of the local transmit queue and stores | |
636 | it in one of the parameters, according to the type of the | |
637 | primitive (which is written in prim_type). If no frame is | |
638 | available in the queue (i.e. first queue element is not marked | |
639 | as 'ready to send', or the queue is empty), the value NO_PRIM | |
640 | is written in prim_type. The parameter rx_service indicates the | |
641 | originator service. In case the rx_service is UITX or ITX an | |
642 | READY signal for flow control will be send after frame | |
643 | transmission. | |
644 | When LLC is suspended, this procedure returns the first | |
645 | primitive for SAPI 1 or the first U frame for any SAPI, which | |
646 | is ready to send. | |
647 | | |
648 | Parameters : grlc_data_req - a valid pointer to a pointer to a GRLC-DATA-REQ | |
649 | primitive | |
650 | grlc_unitdata_req - a valid pointer to a pointer to a | |
651 | GRLC-UNITDATA-REQ primitive | |
652 | prim_type - will be set to PRIM_DATA or PRIM_UNITDATA, must be | |
653 | a valid pointer | |
654 | rx_service - indicates the originater service | |
655 | must be a valid pointer | |
656 | | |
657 +------------------------------------------------------------------------------ | |
658 */ | |
659 GLOBAL void tx_get_next_frame (T_GRLC_DATA_REQ **grlc_data_req, | |
660 T_GRLC_UNITDATA_REQ **grlc_unitdata_req, | |
661 T_PRIM_TYPE *prim_type, | |
662 T_SERVICE *rx_service, | |
663 UBYTE *sapi) | |
664 { | |
665 int frame_len; | |
666 int ctrl_len; | |
667 T_TX_QUEUE *elem; | |
668 T_TX_QUEUE **find; | |
669 | |
670 | |
671 TRACE_FUNCTION( "tx_get_next_frame" ); | |
672 | |
673 | |
674 /* | |
675 * Initialise find w/ queue start. find points always to the element | |
676 * "before" the examined one, to be able to modifiy the queue, if | |
677 * an element is found. | |
678 */ | |
679 find = &llc_data->tx.queue; | |
680 | |
681 /* | |
682 * If LLC is suspended search the queue for the first GRLC_DATA_REQ primitive, | |
683 * otherwise take the first primitive in queue (if any). | |
684 */ | |
685 if (llc_data->suspended EQ TRUE) | |
686 { | |
687 /* | |
688 * LLC is in suspended mode. Search the queue for the first primitive | |
689 * for SAPI 1 or the first U frame for any SAPI | |
690 */ | |
691 while ( (*find NEQ NULL) AND | |
692 ((*find)->ph_sapi NEQ LL_SAPI_1) AND | |
693 ((*find)->rx_service NEQ SERVICE_U) AND | |
694 ((*find)->primitive NEQ (ULONG)NULL) ) | |
695 { | |
696 find = &((*find)->next); | |
697 } | |
698 } | |
699 | |
700 /* | |
701 * Let elem point to queue element (NULL, if no element present/found). | |
702 */ | |
703 elem = *find; | |
704 | |
705 | |
706 /* | |
707 * Check if queue is empty or "first" queue element (depending on suspended | |
708 * mode) is marked as not 'ready to send', i.e. it contains a NULL | |
709 * primitive pointer. | |
710 */ | |
711 if ((elem EQ NULL) OR (elem->primitive EQ (ULONG)NULL)) | |
712 { | |
713 /* | |
714 * Queue is empty or "first" element is not yet 'ready to send'. | |
715 */ | |
716 *prim_type = NO_PRIM; | |
717 } | |
718 else /* (elem NEQ NULL) AND (elem->primitive NEQ NULL) */ | |
719 { | |
720 /* | |
721 * Found a valid (and 'ready to send') element in queue. | |
722 */ | |
723 | |
724 /* | |
725 * Remove found element from queue (set member next of element before | |
726 * the found element to the element behind the found element and thus | |
727 * skip the found element). | |
728 */ | |
729 *find = (*find)->next; | |
730 | |
731 /* | |
732 * Store data of element in the given parameters. | |
733 */ | |
734 *prim_type = elem->prim_type; | |
735 *rx_service = elem->rx_service; | |
736 *sapi = elem->ph_sapi; | |
737 | |
738 if (elem->prim_type EQ PRIM_DATA) | |
739 { | |
740 *grlc_data_req = (T_GRLC_DATA_REQ *)elem->primitive; | |
741 | |
742 frame_len = BYTELEN((*grlc_data_req)->sdu.l_buf); | |
743 } | |
744 else /* PRIM_UNITDATA */ | |
745 { | |
746 *grlc_unitdata_req = (T_GRLC_UNITDATA_REQ *)elem->primitive; | |
747 | |
748 frame_len = BYTELEN((*grlc_unitdata_req)->sdu.l_buf); | |
749 } | |
750 | |
751 /* | |
752 * If the information fild doesn't fit in current N201_U, remove frame | |
753 * (only applies to service U and UITX). | |
754 */ | |
755 if (*rx_service == SERVICE_U || *rx_service == SERVICE_UITX) | |
756 { | |
757 ctrl_len = (*rx_service == SERVICE_U) ? U_FRAME_MIN_OCTETS | |
758 : UI_FRAME_MIN_OCTETS; | |
759 | |
760 if (frame_len > llc_data->n201_u_base[UIMAP(*sapi)] + ctrl_len) | |
761 { | |
762 elem->remove_frame = TRUE; | |
763 TRACE_0_INFO("Primitive in TX exceeds N201-U: marked to remove"); | |
764 } | |
765 } | |
766 | |
767 /* | |
768 * If frame is marked to remove, do it here | |
769 */ | |
770 if (elem->remove_frame == TRUE) | |
771 { | |
772 if (elem->prim_type EQ PRIM_DATA) | |
773 { | |
774 PFREE (*grlc_data_req); | |
775 TRACE_0_INFO("GRLC_DATA_REQ removed from TX queue"); | |
776 } | |
777 else | |
778 { | |
779 PFREE (*grlc_unitdata_req); | |
780 TRACE_0_INFO("GRLC_UNITDATA_REQ removed from TX queue"); | |
781 } | |
782 | |
783 *prim_type = PRIM_REMOVED; | |
784 } | |
785 | |
786 /* | |
787 * Remove TX queue entry management element | |
788 */ | |
789 MFREE (elem); | |
790 | |
791 /* | |
792 * Check if service queue space should be tracked (at the moment only | |
793 * for service UITX and ITX, due to flow control to this service). | |
794 */ | |
795 if (*rx_service EQ SERVICE_UITX) | |
796 { | |
797 /* | |
798 * Increment the UITX space counter for the SAPI of the primitive | |
799 * to indicate that the primitive has been stored in queue. | |
800 */ | |
801 if (*prim_type EQ PRIM_DATA) | |
802 { | |
803 llc_data->tx.queue_counter_uitx[UIMAP(*sapi)]++; | |
804 } | |
805 else /* PRIM_UNITDATA */ | |
806 { | |
807 llc_data->tx.queue_counter_uitx[UIMAP(*sapi)]++; | |
808 } | |
809 } | |
810 else if (*rx_service EQ SERVICE_ITX) | |
811 { | |
812 /* | |
813 * Increment the ITX space counter for the SAPI of the primitive | |
814 * to indicate that the primitive has been stored in queue. | |
815 */ | |
816 llc_data->tx.queue_counter_itx[IMAP(*sapi)]++; | |
817 } | |
818 } | |
819 | |
820 return; | |
821 } /* tx_get_next_frame() */ | |
822 | |
823 | |
824 /* | |
825 +------------------------------------------------------------------------------ | |
826 | Function : tx_get_first_data_frame | |
827 +------------------------------------------------------------------------------ | |
828 | Description : This procedure finds the first GRLC_DATA_REQ primitive in the | |
829 | local transmit queue and stores its queue element in the | |
830 | parameter element, if any. The primitive (element) stays in | |
831 | the queue. If no GRLC_DATA_REQ primitive is found in the queue, | |
832 | no element is stored in element, but the value NULL. | |
833 | | |
834 | Parameters : elem - must be a valid pointer to a pointer to a | |
835 | TX queue element | |
836 | | |
837 +------------------------------------------------------------------------------ | |
838 */ | |
839 GLOBAL void tx_get_first_data_frame (T_TX_QUEUE **elem) | |
840 { | |
841 TRACE_FUNCTION( "tx_get_first_data_frame" ); | |
842 | |
843 /* | |
844 * Check the local transmit queue until a GRLC_DATA_REQ is found or the end | |
845 * of the queue has been reached. In the latter case, *elem is automatically | |
846 * set to NULL. | |
847 */ | |
848 for (*elem = llc_data->tx.queue; *elem NEQ NULL; *elem = (*elem)->next) | |
849 { | |
850 /* | |
851 * Check if primitive is a GRLC_DATA_REQ primitive. | |
852 */ | |
853 if ((*elem)->prim_type EQ PRIM_DATA) | |
854 { | |
855 break; | |
856 } | |
857 } | |
858 | |
859 return; | |
860 } /* tx_get_first_data_frame() */ | |
861 | |
862 | |
863 /* | |
864 +------------------------------------------------------------------------------ | |
865 | Function : tx_remove_data_frames | |
866 +------------------------------------------------------------------------------ | |
867 | Description : This procedure removes all PRIM_DATA for given SAPI and service | |
868 | from TX queue. If an element is removed and | |
869 | | |
870 | Parameters : service - service which requests to delete its primitives | |
871 | sapi - the sapi of the primitives to delete | |
872 | | |
873 +------------------------------------------------------------------------------ | |
874 */ | |
875 GLOBAL void tx_remove_data_frames (T_SERVICE service, T_SAPI sapi) | |
876 { | |
877 T_TX_QUEUE *elem; | |
878 T_TX_QUEUE **find = &llc_data->tx.queue; | |
879 BOOL elem_removed = FALSE; | |
880 | |
881 TRACE_FUNCTION( "tx_remove_data_frames" ); | |
882 | |
883 while (*find NEQ NULL) | |
884 { | |
885 /* | |
886 * Let elem point to queue element | |
887 */ | |
888 elem = *find; | |
889 | |
890 /* | |
891 * Check if primitive is a GRLC_DATA_REQ primitive and | |
892 * check the sapi of the queue element | |
893 */ | |
894 if ((elem->prim_type EQ PRIM_DATA) AND | |
895 (elem->ph_sapi EQ sapi) AND | |
896 (elem->rx_service EQ service) ) | |
897 { | |
898 elem_removed = TRUE; | |
899 | |
900 /* | |
901 * Remove found element from queue (set member next of element before | |
902 * the found element to the element behind the found element and thus | |
903 * skip the found element). | |
904 */ | |
905 *find = (*find)->next; | |
906 | |
907 /* | |
908 * Check if we have a valid pointer to a primitive | |
909 */ | |
910 if ((elem->primitive NEQ (ULONG)NULL)) | |
911 { | |
912 PFREE ((T_GRLC_DATA_REQ *)elem->primitive); | |
913 | |
914 TRACE_0_INFO("TX queue element and primitive removed"); | |
915 } | |
916 else | |
917 { | |
918 /* | |
919 * Primitive is in use at CCI. | |
920 * It is no problem if the corresponding primitive to this entry | |
921 * returns from CCI, because the reference number will not be found | |
922 * and the primitive data will then be freed. | |
923 */ | |
924 TRACE_0_INFO("In use TX queue element removed"); | |
925 } | |
926 | |
927 /* | |
928 * Remove TX queue entry management element. | |
929 */ | |
930 MFREE (elem); | |
931 | |
932 /* | |
933 * Check if service queue space should be tracked (at the moment only | |
934 * for service UITX and ITX, due to flow control to this service). | |
935 * In this case increment the space counter for the SAPI of the | |
936 * primitive to indicate that the primitive has been stored in queue. | |
937 */ | |
938 if (service EQ SERVICE_UITX) | |
939 { | |
940 llc_data->tx.queue_counter_uitx[UIMAP(sapi)]++; | |
941 } | |
942 else if (service EQ SERVICE_ITX) | |
943 { | |
944 llc_data->tx.queue_counter_itx[IMAP(sapi)]++; | |
945 } | |
946 } | |
947 else | |
948 { | |
949 /* | |
950 * Point to the next queue element pointer | |
951 */ | |
952 find = &((*find)->next); | |
953 } | |
954 } | |
955 | |
956 /* | |
957 * Now check, if a ready indication must be send must be send to the | |
958 * requesting service (if at least one elem was removed, send one). | |
959 * Currently only service UITX and ITX are requesting a signal. | |
960 */ | |
961 if (elem_removed) | |
962 { | |
963 SWITCH_LLC (sapi); | |
964 | |
965 if (service EQ SERVICE_UITX) | |
966 { | |
967 sig_tx_uitx_ready_ind(); | |
968 } | |
969 else if (service EQ SERVICE_ITX) | |
970 { | |
971 sig_tx_itx_ready_ind(); | |
972 } | |
973 } | |
974 | |
975 return; | |
976 } /* tx_remove_data_frames() */ | |
977 |