comparison src/g23m-gprs/llc/llc_irxf.c @ 1:fa8dc04885d8

src/g23m-*: import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 06:25:50 +0000
parents
children
comparison
equal deleted inserted replaced
0:4e78acac3d88 1:fa8dc04885d8
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 (IRX-statemachine)
20 +-----------------------------------------------------------------------------
21 */
22
23 #ifndef LLC_IRXF_C
24 #define LLC_IRXF_C
25 #endif
26
27 #define ENTITY_LLC
28
29 /*==== INCLUDES =============================================================*/
30
31 #include <string.h>
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_itxs.h" /* to get ITX signal definitions */
44 #include "llc_irxf.h" /* to get IRX local functions */
45
46
47 /*==== CONST ================================================================*/
48
49 /*==== LOCAL VARS ===========================================================*/
50
51 /*==== PRIVATE FUNCTIONS ====================================================*/
52
53 /*==== PUBLIC FUNCTIONS =====================================================*/
54
55
56
57 /*
58 +------------------------------------------------------------------------------
59 | Function : irx_init
60 +------------------------------------------------------------------------------
61 | Description : This procedure initialises all necessary variables of
62 | i_frames_rx for all SAPIs.
63 |
64 | Parameters :
65 |
66 +------------------------------------------------------------------------------
67 */
68 GLOBAL void irx_init (void)
69 {
70 UBYTE inc;
71
72 TRACE_FUNCTION( "irx_init" );
73
74 /*
75 * Initialise all 4 SAPIs
76 */
77 SWITCH_SERVICE (llc, irx, 0);
78 INIT_STATE (IRX_0, IRX_TLLI_UNASSIGNED);
79
80 SWITCH_SERVICE (llc, irx, 1);
81 INIT_STATE (IRX_1, IRX_TLLI_UNASSIGNED);
82
83 SWITCH_SERVICE (llc, irx, 2);
84 INIT_STATE (IRX_2, IRX_TLLI_UNASSIGNED);
85
86 SWITCH_SERVICE (llc, irx, 3);
87 INIT_STATE (IRX_3, IRX_TLLI_UNASSIGNED);
88
89 /*
90 * Initialise the IRX data structure
91 */
92 for (inc = 0; inc < IRX_NUM_INC; inc++)
93 {
94 SWITCH_SERVICE (llc, irx, inc);
95
96 /*
97 * Free old used resources (in case of an LLC restart):
98 * memory, stored primitives, running timer.
99 */
100 irx_queue_clean ();
101
102 llc_data->irx->ll_send_ready = FALSE;
103 llc_data->irx->last_ns = NS_EQUAL_VR;
104
105 llc_data->irx->queue = NULL;
106 }
107
108 return;
109 } /* irx_init() */
110
111
112 /*
113 +------------------------------------------------------------------------------
114 | Function : irx_init_sapi
115 +------------------------------------------------------------------------------
116 | Description : This procedure initialises all necessary variables of
117 | i_frames_rx for the given SAPI.
118 |
119 | Parameters :
120 |
121 +------------------------------------------------------------------------------
122 */
123 GLOBAL void irx_init_sapi (void)
124 {
125 TRACE_FUNCTION( "irx_init_sapi" );
126
127 llc_data->sapi->va = 0;
128 llc_data->sapi->vs = 0;
129 llc_data->sapi->vr = 0;
130
131 llc_data->irx->vf = 0;
132 llc_data->irx->last_ns = NS_EQUAL_VR;
133 llc_data->irx->B_rx = 0;
134
135 return;
136 } /* irx_init_sapi() */
137
138
139 /*
140 +------------------------------------------------------------------------------
141 | Function : irx_init_abm
142 +------------------------------------------------------------------------------
143 | Description : This procedure initialises all necessary variables of
144 | i_frames_rx for the given SAPI when switching into ABM.
145 |
146 | Parameters :
147 |
148 +------------------------------------------------------------------------------
149 */
150 GLOBAL void irx_init_abm (void)
151 {
152 TRACE_FUNCTION( "irx_init_abm" );
153
154 llc_data->sapi->va = 0;
155 llc_data->sapi->vs = 0;
156 llc_data->sapi->vr = 0;
157
158 llc_data->irx->vf = 0;
159 llc_data->irx->last_ns = NS_EQUAL_VR;
160
161 /*
162 * Reset OCs for acknowledged transfer.
163 */
164 llc_data->sapi->oc_i_tx = 0L;
165 llc_data->sapi->oc_i_rx = 0L;
166
167 return;
168 } /* irx_init_abm() */
169
170
171
172 /*
173 +------------------------------------------------------------------------------
174 | Function : irx_queue_store
175 +------------------------------------------------------------------------------
176 | Description : This procedure stores the primitive into the per ns sorted
177 | queue. If the queue is full, is_busy set to TRUE will be
178 | returnd.
179 |
180 | Parameters :
181 |
182 +------------------------------------------------------------------------------
183 */
184 GLOBAL void irx_queue_store (T_LL_UNITDATA_IND *ll_unitdata_ind,
185 T_FRAME_NUM ns,
186 BOOL *is_busy)
187 {
188 T_IRX_QUEUE** entry = &(llc_data->irx->queue);
189 T_IRX_QUEUE* next;
190 T_FRAME_NUM n = llc_data->irx->vf;
191 ULONG M = *(llc_data->md) * 16;
192
193 TRACE_FUNCTION( "irx_queue_store" );
194
195 /*
196 * First skip already for L3 ready waiting entries
197 */
198 while (*entry && (*entry)->ns == n)
199 {
200 n++;
201 n %= (MAX_SEQUENCE_NUMBER+1);
202
203 if ((*entry)->ns == ns)
204 {
205 /*
206 * Ignore duplicate frame
207 */
208 *is_busy = FALSE;
209
210 TRACE_0_INFO( "Unexpected duplicate frame number" );
211 PFREE (ll_unitdata_ind);
212
213 return;
214 }
215
216 entry = &((*entry)->next);
217 }
218
219 /*
220 * Now find the inserting position (queue sorted per ns,
221 * 'lower' frame numbers stored first)
222 */
223 while (*entry)
224 {
225 if ((*entry)->ns == ns)
226 {
227 /*
228 * Ignore duplicate frame
229 */
230 *is_busy = FALSE;
231
232 TRACE_0_INFO( "Duplicate frame number received" );
233 PFREE (ll_unitdata_ind);
234
235 return;
236 }
237
238 /*
239 * n <= ns <= (*entry)->ns - 1
240 */
241 if (FRAME_NUM_VALID( n, ns, (*entry)->ns - 1))
242 {
243 /*
244 * Found a nice place in between
245 */
246 break;
247 }
248
249 entry = &((*entry)->next);
250 }
251
252 /*
253 * Position found - save ptr to next entry
254 */
255 next = *entry;
256
257 /*
258 * Allocate memory
259 */
260 MALLOC( *entry, sizeof(T_IRX_QUEUE) );
261
262 if( *entry )
263 {
264 /*
265 * Memory successful allocated. Fill in struct entries.
266 */
267 (*entry)->next = next;
268 (*entry)->ns = ns;
269 (*entry)->frame = ll_unitdata_ind;
270
271 /*
272 * Increase amount of stored Information in rx queue
273 */
274 llc_data->irx->B_rx += BYTELEN(ll_unitdata_ind->sdu.l_buf);
275
276 /*
277 * Determine 'own receiver busy' condition
278 */
279 if ((M == 0) || (*(llc_data->n201_i) <= M - llc_data->irx->B_rx))
280 {
281 *is_busy = FALSE;
282 }
283 else
284 {
285 *is_busy = TRUE;
286 }
287 }
288 else
289 {
290 /*
291 * Out of memory
292 */
293 *is_busy = TRUE;
294 TRACE_ERROR( "Out of memory in irx_queue_store()" );
295 PFREE (ll_unitdata_ind);
296 }
297
298 } /* irx_queue_store() */
299
300
301 /*
302 +------------------------------------------------------------------------------
303 | Function : irx_update_vr
304 +------------------------------------------------------------------------------
305 | Description : This procedure increments V(R) if the next following frames
306 | are already stored in the queue.
307 |
308 | Parameters :
309 |
310 +------------------------------------------------------------------------------
311 */
312 GLOBAL void irx_update_vr (void)
313 {
314 T_IRX_QUEUE* entry = llc_data->irx->queue;
315
316 TRACE_FUNCTION( "irx_update_vr" );
317
318 /*
319 * Search the queue from the beginning to entry V(R)
320 */
321 while (entry)
322 {
323 if (entry->ns == llc_data->sapi->vr)
324 {
325 /*
326 * Increment V(R) and continue searching
327 */
328 llc_data->sapi->vr++;
329
330 if (llc_data->sapi->vr > MAX_SEQUENCE_NUMBER)
331 {
332 llc_data->sapi->oc_i_rx += (MAX_SEQUENCE_NUMBER+1);
333 llc_data->sapi->vr = 0;
334 }
335 }
336
337 entry = entry->next;
338 }
339
340 } /* irx_update_vr() */
341
342
343 /*
344 +------------------------------------------------------------------------------
345 | Function : irx_get_last_queued_ns
346 +------------------------------------------------------------------------------
347 | Description : This procedure returns the frame number of the last queue entry
348 |
349 | Parameters : *found - set to TRUE if ns found, FALSE otherwise
350 |
351 +------------------------------------------------------------------------------
352 */
353 GLOBAL void irx_get_last_queued_ns (BOOL *found, T_FRAME_NUM *num)
354 {
355 T_IRX_QUEUE* entry = llc_data->irx->queue;
356
357 TRACE_FUNCTION( "irx_get_last_queued_ns" );
358
359 /*
360 * Search the queue from the beginning to last entry
361 */
362 while (entry AND entry->next)
363 entry = entry->next;
364
365 if (entry)
366 {
367 *found = TRUE;
368 *num = entry->ns;
369 }
370 else
371 {
372 *found = FALSE;
373 *num = 0;
374 }
375
376 } /* irx_get_last_queued_ns() */
377
378
379 /*
380 +------------------------------------------------------------------------------
381 | Function : irx_queue_retrieve
382 +------------------------------------------------------------------------------
383 | Description : If the next frame in sequence is stored in the queue then this
384 | procedure will return the primitive pointer, sets found to
385 | TRUE and removes the frame from the queue.
386 |
387 | Parameters :
388 |
389 +------------------------------------------------------------------------------
390 */
391 GLOBAL void irx_queue_retrieve (T_LL_UNITDATA_IND **ll_unitdata_ind, BOOL *found)
392 {
393 T_IRX_QUEUE** entry = &(llc_data->irx->queue);
394
395 TRACE_FUNCTION( "irx_queue_retrieve" );
396
397 /*
398 * Take the first queue entry, if this is the next one (queue is sorted per ns)
399 */
400 if ((*entry != NULL) && ((*entry)->ns == llc_data->irx->vf))
401 {
402 /*
403 * Store pointer to the entry
404 */
405 T_IRX_QUEUE* current = *entry;
406
407 /*
408 * Remove entry from the queue (make second to first)
409 */
410 *entry = current->next;
411
412 *ll_unitdata_ind = current->frame;
413
414 /*
415 * Decrease amount of stored Information in rx queue
416 */
417 if (llc_data->irx->B_rx >= (ULONG)(BYTELEN((*ll_unitdata_ind)->sdu.l_buf)))
418 {
419 llc_data->irx->B_rx -= BYTELEN((*ll_unitdata_ind)->sdu.l_buf);
420 }
421 else
422 {
423 llc_data->irx->B_rx = 0;
424 TRACE_0_INFO("Unexpected SDU lenght handled");
425 }
426
427 /*
428 * Free retrieved entry
429 */
430 MFREE (current);
431
432 *found = TRUE;
433
434 /*
435 * Increment V(f) (= Next frame number to forward to L3)
436 */
437 llc_data->irx->vf += 1;
438 llc_data->irx->vf %= (MAX_SEQUENCE_NUMBER+1);
439
440 return;
441 }
442
443 /*
444 * Set default return values
445 */
446 *ll_unitdata_ind = NULL;
447 *found = FALSE;
448 }
449
450
451
452 /*
453 +------------------------------------------------------------------------------
454 | Function : irx_queue_clean
455 +------------------------------------------------------------------------------
456 | Description : This procedure removes all entries from the IRX queue
457 |
458 | Parameters :
459 |
460 +------------------------------------------------------------------------------
461 */
462 GLOBAL void irx_queue_clean (void)
463 {
464 T_IRX_QUEUE** entry = &(llc_data->irx->queue);
465
466 TRACE_FUNCTION( "irx_queue_clean" );
467
468 while (*entry)
469 {
470 /*
471 * get pointer to next (=first) entry
472 */
473 T_IRX_QUEUE* current = *entry;
474
475 /*
476 * Free frame, if one is attached to the entry
477 */
478 if (current->frame != NULL)
479 {
480 PFREE (current->frame);
481 }
482
483 /*
484 * remove next entry from the entry (make second to first)
485 */
486 *entry = current->next;
487
488 /*
489 * free the removed entry
490 */
491 MFREE (current);
492 }
493
494 /*
495 * Adjust amount of stored Information in rx queue
496 */
497 llc_data->irx->B_rx = 0;
498
499 } /* irx_queue_clean() */
500
501
502
503 /*
504 +------------------------------------------------------------------------------
505 | Function : irx_build_sack_bitmap
506 +------------------------------------------------------------------------------
507 | Description : This procedure builds a SACK bitmap, depending on current
508 | status
509 |
510 | Parameters :
511 |
512 +------------------------------------------------------------------------------
513 */
514 GLOBAL void irx_build_sack_bitmap ( T_SACK_BITMAP *bitmap )
515 {
516 T_IRX_QUEUE* entry = llc_data->irx->queue;
517 int start_ns = (llc_data->sapi->vr + 1) % (MAX_SEQUENCE_NUMBER+1);
518 T_FRAME_NUM num = llc_data->irx->vf;
519 USHORT d;
520
521
522 TRACE_FUNCTION( "irx_build_sack_bitmap" );
523
524 /*
525 * Init bitmap to 0 (= frame not successfully received)
526 */
527 memset (bitmap, 0, sizeof(T_SACK_BITMAP));
528
529 /*
530 * Skip already for L3 ready waiting entries
531 */
532 while (entry && entry->ns == num)
533 {
534 num++;
535 num %= (MAX_SEQUENCE_NUMBER+1);
536
537 entry = entry->next;
538 }
539
540
541 /*
542 * Check the queue for successful received entries
543 */
544 while (entry)
545 {
546 /*
547 * If frame is successful received, mark it in bitmap
548 */
549 d = FRAME_NUM_DISTANCE(start_ns, entry->ns);
550
551 if (d < (S_FRAME_SACK_MAX_CTRL_OCTETS * 8))
552 {
553 bitmap->data[d>>3] |= 0x80>>(d%8);
554 }
555
556 entry = entry->next;
557 }
558 } /* irx_build_sack_bitmap () */
559
560
561 /*
562 +------------------------------------------------------------------------------
563 | Function : irx_ack_all_to
564 +------------------------------------------------------------------------------
565 | Description : This procedure handles the acknowledgement of transmitted I-
566 | frames from va to n (which is equal to nr -1)
567 | Parameters :
568 |
569 +------------------------------------------------------------------------------
570 */
571 GLOBAL void irx_ack_all_to (T_FRAME_NUM n)
572 {
573 TRACE_FUNCTION( "irx_ack_all_to" );
574
575 n %= (MAX_SEQUENCE_NUMBER+1);
576
577 if (FRAME_WIN_VALID(n, llc_data->sapi->va, *(llc_data->ku)))
578 {
579 while (llc_data->sapi->va != (n+1)%(MAX_SEQUENCE_NUMBER+1))
580 {
581 sig_irx_itx_ack_ind (TRUE, llc_data->sapi->va);
582
583 llc_data->sapi->va++;
584 llc_data->sapi->va %= (MAX_SEQUENCE_NUMBER+1);
585 }
586
587 /*
588 * Sending L3 Data confirmations
589 */
590 sig_irx_itx_cnf_l3data_req ();
591 }
592
593 } /* irx_ack_all_to () */
594
595
596 /*
597 +------------------------------------------------------------------------------
598 | Function : irx_handle_sack
599 +------------------------------------------------------------------------------
600 | Description : This procedure handles the acknowledge bits of a SACK
601 | supervisory frame and strips the SACK bitmap from the SDU
602 |
603 | Parameters :
604 |
605 +------------------------------------------------------------------------------
606 */
607 GLOBAL void irx_handle_sack (T_FRAME_NUM nr,
608 T_LL_UNITDATA_IND *ll_unitdata_ind,
609 T_PDU_TYPE frame_type)
610 {
611 int i, n, bytes;
612 T_FRAME_NUM rn = 0;
613 T_SACK_BITMAP *bm;
614
615 TRACE_FUNCTION( "irx_handle_sack" );
616
617 /*
618 * Extract SACK bitmap and number of Ptr to bits from sdu:
619 */
620 if (frame_type == I_FRAME)
621 {
622 bm = (T_SACK_BITMAP*)&(ll_unitdata_ind->sdu.buf[
623 (ll_unitdata_ind->sdu.o_buf >> 3) + 1]);
624 bytes = ll_unitdata_ind->sdu.buf[
625 (ll_unitdata_ind->sdu.o_buf >> 3)] & 0xF1;
626 }
627 else
628 {
629 bm = (T_SACK_BITMAP*)&(ll_unitdata_ind->sdu.buf[
630 (ll_unitdata_ind->sdu.o_buf >> 3)]);
631 bytes = ll_unitdata_ind->sdu.l_buf >> 3;
632 }
633
634 /*
635 * Little Protection
636 */
637 if ( bytes > S_FRAME_SACK_MAX_CTRL_OCTETS )
638 {
639 bytes = S_FRAME_SACK_MAX_CTRL_OCTETS;
640 TRACE_ERROR ("Illegal SACK bitmap size received");
641 }
642
643 /*
644 * For each bit, which is set, send an acknowledge to ITX
645 */
646 for (i = 0; i < bytes; i++)
647 {
648 for (n = 7; n >= 0; n--)
649 {
650 /*
651 * first increment rn (must begin with 1)
652 */
653 rn++;
654
655 /*
656 * check if bit is set from MSB to LSB
657 */
658 if ( bm->data[i] & (1 << n) )
659 {
660 /*
661 * set frame acknowledged
662 */
663 sig_irx_itx_ack_ind ( TRUE, (T_FRAME_NUM)(nr + rn));
664 }
665 else
666 {
667 /*
668 * mark frame for retransmission
669 */
670 sig_irx_itx_ack_ind ( FALSE, (T_FRAME_NUM)(nr + rn));
671 }
672 }
673 }
674
675 /*
676 * send L3 data confirmation
677 */
678 sig_irx_itx_cnf_l3data_req ();
679
680 /*
681 * Strip SACK bitmap from I frame SDUs to get clean L3 PDU
682 */
683 if (frame_type == I_FRAME)
684 {
685 ll_unitdata_ind->sdu.o_buf += bytes << 3;
686 ll_unitdata_ind->sdu.l_buf -= bytes << 3;
687 }
688
689 } /* irx_handle_sack () */
690
691
692 /*
693 +------------------------------------------------------------------------------
694 | Function : irx_send_ack
695 +------------------------------------------------------------------------------
696 | Description : This procedure handles the detection of sequence errors and
697 | the sending of appropriate acknowledgements
698 |
699 | Parameters :
700 |
701 +------------------------------------------------------------------------------
702 */
703 GLOBAL void irx_send_ack (T_BIT a_bit)
704 {
705 TRACE_FUNCTION( "irx_send_ack" );
706
707 /*
708 * Send S frame depending on last N(S) / V(R) condition
709 */
710 switch (llc_data->irx->last_ns)
711 {
712 case NS_EQUAL_VR:
713 /*
714 * Send an RR only, if requested
715 */
716 if (a_bit)
717 {
718 sig_irx_itx_send_rr_req (ABIT_NO_REQ);
719 }
720 else
721 {
722 /*
723 * Trigger ITX to check queue and send frames
724 * This is done inside the other signals, too.
725 */
726 sig_irx_itx_trigger_ind ();
727 }
728 break;
729
730 case NS_EQUAL_VR_PLUS_1:
731 /*
732 * Sequence error - one missing
733 */
734 sig_irx_itx_send_ack_req (ABIT_NO_REQ);
735 break;
736
737 case NS_NO_SEQUENCE_ERROR:
738 /*
739 * Send an SACK only, if requested
740 */
741 if (a_bit)
742 {
743 T_SACK_BITMAP bitmap;
744
745 irx_build_sack_bitmap( &bitmap );
746 sig_irx_itx_send_sack_req (ABIT_NO_REQ, &bitmap);
747 }
748 else
749 {
750 /*
751 * Trigger ITX to check queue and send frames
752 * This is done inside the other signals, too.
753 */
754 sig_irx_itx_trigger_ind ();
755 }
756 break;
757
758 default:
759 /*
760 * Sequence error - one or more missing
761 */
762 {
763 T_SACK_BITMAP bitmap;
764
765 irx_build_sack_bitmap( &bitmap );
766 sig_irx_itx_send_sack_req (ABIT_NO_REQ, &bitmap);
767 }
768 break;
769 }
770
771 } /* irx_send_ack () */
772
773
774 /*
775 +------------------------------------------------------------------------------
776 | Function : irx_send_rnr
777 +------------------------------------------------------------------------------
778 | Description : This procedure sends an RNR to ITX
779 |
780 | Parameters :
781 |
782 +------------------------------------------------------------------------------
783 */
784 GLOBAL void irx_send_rnr ()
785 {
786 TRACE_FUNCTION( "irx_send_rnr" );
787
788 sig_irx_itx_send_rnr_req (ABIT_NO_REQ);
789
790 } /* irx_send_rnr() */
791
792