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 |
