comparison src/g23m-gprs/llc/llc_txf.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 (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