/* $Id: mcl_rlc.cpp,v 1.2 2003/10/27 09:55:48 roca Exp $ */ /* * Copyright (c) 1999-2003 INRIA - Universite Paris 6 - All rights reserved * (main author: Julien Laboure - julien.laboure@inrialpes.fr * Vincent Roca - vincent.roca@inrialpes.fr) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* * This file contains implementations for RLC congestion control. */ #include "mcl_includes.h" #ifdef RLC /* { */ static int rlc_SP_spacing (rlccb_t *rlccb, int layer); /* static int CheckHeader(rlc_hdr_t rlc_header); */ static int CheckSequence(mclcb_t *mclcb, u_int8_t layer, u_int16_t seqid); static void RxProcessSP(mclcb_t *mclcb, rlccb_t *rlccb, u_int8_t layer); static int AddLate(mclcb_t *mclcb, int layer, int nseq); static int RemoveLate(mclcb_t *mclcb, int layer, int nseq); static int UpdateLateList(mclcb_t *mclcb); static int AddLost (mclcb_t *mclcb); static int UpdateLossList(mclcb_t *mclcb); static void FreeLists(mclcb_t *mclcb); /* * calculate the SP spacing * returns the time (in the mcl_time_count timeline) when next SP will occur */ int rlc_SP_spacing (rlccb_t *rlccb, int layer) { int spacing; if (rlccb->rlc_lan_cc) { /* aggressive RLC setup for LAN only tx */ if (layer <= 1) spacing = (int)(rlccb->rlc_sp_cycle / MCL_TIMER_PERIOD) * (layer + 1); else spacing = (int)(1000000 / MCL_TIMER_PERIOD); /* 1s */ } else { /* use a linear spacing of SPs on the layers */ /*spacing = (int)(rlccb->rlc_sp_cycle / MCL_TIMER_PERIOD)*/ /* * (layer + 1);*/ /* use expon. spacing of SPs on the layers with upper bound */ spacing = (int)(rlccb->rlc_sp_cycle / MCL_TIMER_PERIOD) * (min((1 << layer), 128 + layer)); } return(mcl_time_count + spacing); } /**** rlc_init_session() **** * Init. the RLC congestion control mechanism for a given session * This must be the called before any other calls to RLC functions * Parameters: mclcb: points to the session Control Block * Return Value: N/A */ void rlc_init_session ( mclcb_t *mclcb) { int i; rlccb_t *rlccb; TRACELVL( 5, (mcl_stdout, "-> RLC:rlc_init_session: mclcb=x%x\n", (int) mclcb)) rlccb = &(mclcb->rlccb); memset((void *)rlccb, 0, sizeof(rlccb_t)); rlccb->rlc_sp_cycle = RLC_SP_CYCLE; rlccb->rlc_pkt_timeout = RLC_PKT_TIMEOUT; rlccb->rlc_deaf_period = RLC_DEAF_PERIOD; rlccb->rlc_loss_accepted = RLC_LOSS_ACCEPTED; rlccb->rlc_late_accepted = RLC_LATE_ACCEPTED; rlccb->rlc_loss_limit = RLC_LOSS_LIMIT; rlccb->rlc_loss_timeout = RLC_LOSS_TIMEOUT; /* do it now (and later on after the FIRST packet tx) */ /*rlc_reset_sp(mclcb);*/ for (i = 0 ; i < MAX_TX_LEVEL; i++) { rlccb->rx_first_pkt[i] = 1; /* * init first_sp to 0 to start normally, and * with 1 for a really slow start (i.e. the first SP of * each layer will be ignored) */ /*rlccb->rx_first_sp[i] = 1;*/ rlccb->rx_first_sp[i] = 0; /* used to test overflows */ /* rlccb->tx_layers_seq[i]=65500; */ } TRACELVL(5, (mcl_stdout, "<- RLC:rlc_init_session\n")) } /**** rlc_reset_sp () **** * reset all SP variables at the sending side * done just after transmitting the first packet to have synchronized SPs * Return Value: N/A */ void rlc_reset_tx_sp (mclcb_t *mclcb) { int i; rlccb_t *rlccb = &(mclcb->rlccb); for (i = 0 ; i < MAX_TX_LEVEL; i++) { rlccb->tx_next_sp[i] = rlc_SP_spacing(rlccb, i); TRACELVL(3, (mcl_stdout, " RLC: rlc_reset_tx_sp: layer=%d, SP_spacing=%d, next_SP=%d\n", i, rlccb->tx_next_sp[i] - mcl_time_count, rlccb->tx_next_sp[i])) } } /**** rlc_end_session () **** * Must be called when ending a session * Parameters: mclcb: points to the session Control Block * Return Value: N/A */ void rlc_end_session ( mclcb_t *mclcb ) { TRACELVL(5, (mcl_stdout, "-> RLC: rlc_end_session\n")) FreeLists(mclcb); TRACELVL(5, (mcl_stdout, "<- RLC: rlc_end_session\n")) } /**** rlc_tx_fill_header () **** * Fill the RLC header for each packet to send * * Parameters: mclcb: points to the session Control Block * hdr_buff: points to a buffer receiving the RLC header * layer: The layer of this packet * Return Value: MCL_OK (0) if success, else an error code */ int rlc_tx_fill_header ( mclcb_t *mclcb, rlc_hdr_t *hdr_buff, u_int8_t layer ) { u_int16_t hdr_seqid; rlccb_t *rlccb; ASSERT(mclcb!=NULL) rlccb = &(mclcb->rlccb); TRACELVL(5, (mcl_stdout, "-> RLC: rlc_fill_header: mclcb=x%x, layer=%d\n", (int) mclcb, layer)) ASSERT(layer < MAX_TX_LEVEL && layer < mclcb->nb_level) hdr_seqid = rlccb->tx_layers_seq[layer]; (rlccb->tx_layers_seq[layer])++; ASSERT(hdr_buff!=NULL) hdr_buff->rlc_reserved = 0x55; /* unused: rlc_reserved=1010101 */ hdr_buff->rlc_layer = layer; hdr_buff->rlc_seqid = htons(hdr_seqid); #if 0 if(rlccb->tx_next_sp[layer] <= mcl_time_count) #else /* no SP if we are in single_layer mode */ if(!mclcb->single_layer_mode && rlccb->tx_next_sp[layer] <= mcl_time_count) #endif { /* OK this is a new SP for this layer */ hdr_buff->rlc_sp = 1; /* calculate when next SP will occur */ rlccb->tx_next_sp[layer] = rlc_SP_spacing(rlccb, layer); if (mclcb->verbose == 2) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tSP_all %d\n", time.tv_sec, time.tv_usec, layer)) } TRACELVL(3, (mcl_stdout, " RLC hdr info: layer=%d, seq=%d, SP=yes, next_SP=%d\n", layer, hdr_seqid, rlccb->tx_next_sp[layer])) if (layer+1 < MAX_TX_LEVEL && mclcb->txlvl_tab[layer+1].wait_sp == 1) { /* start tx on upper layers (if not already done) */ /* nb: do not start before the first packet tx */ mclcb->txlvl_tab[layer+1].wait_sp = 0; /* nb: wait_after_sp_count already initialized */ } } else { /* not a SP... */ hdr_buff->rlc_sp = 0; TRACELVL(3, (mcl_stdout, " RLC hdr info: layer=%d, seq=%d, SP=no\n", layer, hdr_seqid)) } TRACELVL(5, (mcl_stdout, "<- RLC: rlc_fill_header: ok\n")) return MCL_OK; } /**** rlc_rx_analyze_packet () **** * Analyse each packets' RLC headers. * * Parameters: * Return Value: layer >=0 if success, else the error code as defined * in mcl_error.h. */ int rlc_rx_analyze_packet ( mclcb_t *mclcb, rlc_hdr_t *hdr_buff ) { /* rlc_hdr_t rlc_header;*/ u_int8_t hdr_layer; u_int16_t hdr_seqid; char hdr_sp; rlccb_t *rlccb; ASSERT(hdr_buff!=NULL) TRACELVL(5, (mcl_stdout, "-> RLC: rlc_rx_analyze_packet\n")) ASSERT(mclcb!=NULL) rlccb = &(mclcb->rlccb); hdr_seqid = ntohs(hdr_buff->rlc_seqid); hdr_layer = hdr_buff->rlc_layer; hdr_sp = hdr_buff->rlc_sp; if(hdr_buff->rlc_reserved != 0x55) { /* Unrecognized/corrupt RLC header, so ignore... */ TRACELVL(5, (mcl_stdout, "<- RLC: rlc_rx_analyze_packet (CORRUPT_HDR)\n")) return ERR_CORRUPT_HDR; } if(hdr_layer >= mclcb->nb_level) { /* Bad layer, should not receive on it, so ignore... */ TRACELVL(5, (mcl_stdout, "<- RLC: rlc_rx_analyze_packet (BAD_LAYER)\n")) return ERR_BAD_LAYER; } UpdateLossList(mclcb); if ( rlccb->rx_deaf_wait ) { TRACELVL(3, (mcl_stdout, "rlc_rx_analyze_packet: in DEAF!!! rlccb->rx_deaf_wait=%d\n", rlccb->rx_deaf_wait)) /* Do nothing more as we're in deaf period */ rlccb->rx_wait_for[hdr_layer]= hdr_seqid + 1; goto fin; } if(rlccb->rx_first_pkt[hdr_layer]) { /* First packet on this layer... */ rlccb->rx_wait_for[hdr_layer] = hdr_seqid + 1; rlccb->rx_first_pkt[hdr_layer] = 0; /* continue as this pkt may contain an SP */ } else { /* check if some pkts have been lost or not */ CheckSequence(mclcb, hdr_layer, hdr_seqid); } if(hdr_sp) { if (mclcb->verbose == 2) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tSP_all %d\n", time.tv_sec, time.tv_usec, hdr_layer)) } if(hdr_layer == mclcb->nb_level-1) { /* This is a Synchronisation Point */ if(rlccb->rx_first_sp[hdr_layer] == 1) { /* skip 1st SP, especially after deaf-period */ rlccb->rx_first_sp[hdr_layer] = 0; } else { RxProcessSP(mclcb, rlccb, hdr_layer); } } } fin: TRACELVL(5, (mcl_stdout, "<- RLC: rlc_rx_analyze_packet (ok)\n")) return hdr_layer; } /**** rlc_rx_timer () **** * * u_int mcl_rlc_rx_period = MCL_RLC_RX_PERIOD; * is the period in microseconds between two calls to this function * * Parameters: * Return Value: 1 if success. */ int rlc_rx_timer(mclcb_t *mclcb) { rlccb_t *rlccb = &(mclcb->rlccb); TRACELVL(5, (mcl_stdout, "-> RLC: rlc_rx_timer mclcb=x%x\n",(int)mclcb)) if ( rlccb->rx_deaf_wait > 0 ) { (rlccb->rx_deaf_wait)--; TRACELVL(3, (mcl_stdout, "rlc_rx_timer: new rlccb->rx_deaf_wait=%d\n", rlccb->rx_deaf_wait)) if (rlccb->rx_deaf_wait == 0) { TRACELVL(3, (mcl_stdout, " RLC: End of Deaf Period\n")) /* * skip next SP to be sure to wait for a complete * SP period */ /*for (i=0; irx_first_sp[i] = 1;*/ rlccb->rx_first_sp[mclcb->nb_level-1] = 1; if (mclcb->verbose == 2 ) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT(( stdout, "\n%ld.%06ld\tend_deaf\n", time.tv_sec, time.tv_usec)) } } } else { UpdateLateList(mclcb); } TRACELVL(5, (mcl_stdout, "<- RLC: rlc_rx_timer (ok)\n")) return MCL_OK; } /**** rlc_ctl () **** * Used to set various RLC options and parameters. * Parameters: mclcb : point to the mclcl structure of the session. optname : a defined option name -> RLC_OPT_* optvalue : the value for the option. optlen : size of optvalue. * Return Value: 1 if success. */ int rlc_ctl (mclcb_t *mclcb, int optname, void *optvalue, int optlen) { rlccb_t *rlccb = &(mclcb->rlccb); TRACELVL(5, (mcl_stdout, "-> RLC: rcl_ctl: optname=%d, optvalue=x%x, optlen=%d\n", optname, (int)optvalue, optlen)) switch (optname) { case RLC_OPT_SP_CYCLE: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR RLC_OPT_SP_CYCLE: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) < 0 ) { PRINT_ERR((mcl_stderr,"rlc_ctl ERROR: RLC_OPT_SP_CYCLE must be positive (got %d)\n",(*(int*)optvalue))) goto error; } rlccb->rlc_sp_cycle = *(int*)optvalue; break; case RLC_OPT_PKT_TIMEOUT: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR(( stderr, "rlc_ctl ERROR RLC_OPT_PKT_TIMEOUT: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) < 0 ) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR: RLC_OPT_PKT_TIMEOUT must be positive (got %d)\n",(*(int*)optvalue))) goto error; } rlccb->rlc_pkt_timeout = *(int*)optvalue; break; case RLC_OPT_DEAF_PERIOD: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR(( stderr, "rlc_ctl ERROR RLC_OPT_DEAF_PERIOD: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) < 0 ) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR: RLC_OPT_DEAF_PERIOD must be positive (got %d)\n",(*(int*)optvalue))) goto error; } rlccb->rlc_deaf_period = *(int*)optvalue; break; case RLC_OPT_LOSS_ACCEPTED: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR(( stderr, "rlc_ctl ERROR RLC_OPT_LOSS_ACCEPTED: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) < 0 ) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR: RLC_OPT_LOSS_ACCEPTED must be positive (got %d)\n",(*(int*)optvalue))) goto error; } rlccb->rlc_loss_accepted = *(int*)optvalue; break; case RLC_OPT_LATE_ACCEPTED: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR(( stderr, "rlc_ctl ERROR RLC_OPT_LATE_ACCEPTED: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) < 0 ) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR: RLC_OPT_LATE_ACCEPTED must be positive (got %d)\n",(*(int*)optvalue))) goto error; } rlccb->rlc_late_accepted = *(int*)optvalue; break; case RLC_OPT_LOSS_LIMIT: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR RLC_OPT_LOSS_LIMIT: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) < 0 ) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR: RLC_OPT_LOSS_LIMIT must be positive (got %d)\n",(*(int*)optvalue))) goto error; } rlccb->rlc_loss_limit = *(int*)optvalue; break; case RLC_OPT_LOSS_TIMEOUT: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR RLC_OPT_LOSS_TIMEOUT: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) < 0 ) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR: RLC_OPT_LOSS_TIMEOUT must be positive (got %d)\n",(*(int*)optvalue))) goto error; } rlccb->rlc_loss_timeout = *(int*)optvalue; break; case RLC_OPT_AGGRESSIVE_CC: if (!optvalue || optlen != sizeof(int)) { PRINT_ERR(( stderr, "rlc_ctl ERROR RLC_OPT_AGGRESSIVE_CC: null optvalue or bad optlen (got %d, expected %d)\n", optlen, sizeof(int))) goto error; } if ((*(int*)optvalue) != 0 && (*(int*)optvalue) != 1) { PRINT_ERR((mcl_stderr, "rlc_ctl ERROR: RLC_OPT_AGGRESSIVE_CC must be 0 or 1 (got %d)\n",(*(int*)optvalue))) goto error; } rlccb->rlc_lan_cc = *(int*)optvalue; if (rlccb->rlc_lan_cc) { /* * if we indeed have a LAN congestion control profile, then * adapt various parameters: SP spacing, death period... */ /* nb: SP spacing will be done in rlc_SP_spacing() function */ rlccb->rlc_deaf_period = RLC_LAN_DEAF_PERIOD; rlccb->rlc_late_accepted = RLC_LAN_LATE_ACCEPTED; rlccb->rlc_loss_accepted = RLC_LAN_LOSS_ACCEPTED; rlccb->rlc_loss_limit = RLC_LAN_LOSS_LIMIT; } TRACELVL(5, (mcl_stdout, " mcl_ctl: RLC_OPT_AGGRESSIVE_CC (%d)\n", rlccb->rlc_lan_cc)) break; default: TRACELVL(5, (mcl_stdout, "<- RLC: rlc_ctl (Unknown option)\n")) return ERR_OPT_UNKNOWN; break; } TRACELVL(5, (mcl_stdout, "<- RLC: rlc_ctl (ok)\n")) return MCL_OK; error: TRACELVL(5, (mcl_stdout, "<- RLC: rlc_ctl (Failure)\n")) return MCL_ERROR; } int CheckSequence(mclcb_t *mclcb, u_int8_t layer, u_int16_t seqid) { rlccb_t *rlccb; u_int16_t Delta1, Delta2 = 0; int i, late_limit; TRACELVL(5, (mcl_stdout, "-> RLC: CheckSequence\n")) ASSERT(mclcb!=NULL) rlccb = &(mclcb->rlccb); if( rlccb->rx_wait_for[layer] == seqid ) { /* This is the packet we're waiting for, let's go on! */ (rlccb->rx_wait_for[layer])++; TRACELVL(5, (mcl_stdout, "<- RLC: CheckSequence (good seq)\n")) return MCL_OK; } /* This is not the one we're waiting for... */ if( rlccb->rx_wait_for[layer] < seqid ) { Delta1 = seqid - rlccb->rx_wait_for[layer]; Delta2 = 65535 - Delta1; if ( Delta1 < Delta2 ) { /* Some packet(s) are missing */ /* eg. wait seq 1512 and get 1513, so 1512 is missing */ /* FIX 14/12/01 */ late_limit=RLC_MAX_LATES; for ( i = rlccb->rx_wait_for[layer]; i < seqid; i++) { AddLate(mclcb, layer, i); late_limit--; if(late_limit <= 0 ) { TRACELVL(3, (mcl_stdout, " RLC Warning*** Max number of LATE packets reached\n")) break; } } /* EOFIX */ rlccb->rx_wait_for[layer] = seqid +1; } else { /* Late arrival packet (uint16 overflow) */ /* eg. we're waiting seq 4 and we get seq 65532 */ RemoveLate(mclcb, layer, seqid); } } else /* rx_wait_for > rlc_seqid */ { Delta1 = rlccb->rx_wait_for[layer] - seqid; Delta2 = 65535 - Delta1; if ( Delta1 < Delta2 ) {/* Late arrival packet */ /* ie: we're waiting seq 501 and we get seq 498 */ RemoveLate(mclcb, layer, seqid); } else { /* Some packet(s) are missing (uint16 overflow) */ /* ie: waiting seq 65531 and get seq 3 */ /* FIX 14/12/01 */ late_limit=RLC_MAX_LATES; for ( i=rlccb->rx_wait_for[layer]; i != (seqid-1); i++) { AddLate(mclcb, layer, i); late_limit--; if(late_limit <= 0 ) { TRACELVL(3, (mcl_stdout, " RLC Warning*** Max number of LATE packets reached\n")) break; } } /* EOFIX */ rlccb->rx_wait_for[layer] = seqid +1; } } TRACELVL(5, (mcl_stdout, "<- RLC: CheckSequence (seq broken)\n")) return MCL_ERROR; } void RxProcessSP(mclcb_t *mclcb, rlccb_t *rlccb, u_int8_t layer) { TRACELVL(5, (mcl_stdout, "-> RLC: RxProcessSP\n")) TRACELVL(3, (mcl_stdout, " RLC: Sync Point (toplevel=%d)\n", layer)) if (mclcb->verbose == 2) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tSP_received %d\n", time.tv_sec, time.tv_usec, layer)) } if (rlccb->rx_nblost_since_sp <= rlccb->rlc_loss_accepted && rlccb->rx_nblate_since_sp <= rlccb->rlc_late_accepted) { mcl_add_layer(mclcb, MCL_HIGHEST_LAYER); /*rlccb->rx_first_sp[mclcb->nb_level-1] = 1;*/ TRACELVL(2, (mcl_stdout, " RLC: add a new layer, now receiving from %d layers\n", mclcb->nb_level)) } rlccb->rx_nblost_since_sp = 0; rlccb->rx_nblate_since_sp = 0; TRACELVL(5, (mcl_stdout, "<- RLC: RxProcessSP\n")) } /* a packet is late, remember it */ int AddLate(mclcb_t *mclcb, int layer, int nseq) { rlccb_t *rlccb; late_list_t *new_missing; TRACELVL(5, (mcl_stdout, "-> RLC: AddLate\n")) ASSERT(mclcb!=NULL && layer<=mclcb->nb_level) rlccb = &(mclcb->rlccb); if( !( new_missing = (late_list_t *)malloc(sizeof(late_list_t))) ) { PRINT_ERR((mcl_stderr, "AddLate: no memory")) mcl_exit(-1); } new_missing->seq_num = nseq; ASSERT(mcl_rlc_rx_period!=0) new_missing->ttw = rlccb->rlc_pkt_timeout / mcl_rlc_rx_period; new_missing->next = rlccb->rx_missing[layer].next; rlccb->rx_missing[layer].next = new_missing; (rlccb->rx_nblate)++; (rlccb->rx_nblate_since_sp)++; if (mclcb->verbose == 2) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tlate_detected %d %d %d\n", time.tv_sec, time.tv_usec, layer, nseq, rlccb->rx_nblate)) } /* update stats: assume a late pkt is lost (corrected later if req.) */ mclcb->stats.rx_lost_pkts++; mclcb->stats.rx_lost_per_lvl[layer]++; TRACELVL(3, (mcl_stdout, " RLC: pkt %d of layer %d late, total %d late\n", nseq, layer, rlccb->rx_nblate)) TRACELVL(5, (mcl_stdout, "<- RLC: AddLate: ok\n")) return MCL_OK; } /* we finally received the delayed packet */ int RemoveLate(mclcb_t *mclcb, int layer, int nseq) { rlccb_t *rlccb; late_list_t *prev, *current; TRACELVL(5, (mcl_stdout, "-> RLC: RemoveLate seq=%d on layer %d\n", nseq, layer)) ASSERT(mclcb!=NULL && layer<=mclcb->nb_level) rlccb = &(mclcb->rlccb); prev = &(rlccb->rx_missing[layer]); current = prev->next;; while ( current != NULL && current->seq_num != nseq ) { prev = current; current = current->next; } if(current == NULL) { TRACELVL(5, (mcl_stdout, "<- RLC: RemoveLate (Missing)\n")) return MCL_ERROR; } else { prev->next = current->next; free(current); (rlccb->rx_nblate)--; (rlccb->rx_nblate_since_sp)--; } /* correct stats... */ mclcb->stats.rx_lost_pkts--; mclcb->stats.rx_lost_per_lvl[layer]--; TRACELVL(5, (mcl_stdout, "<- RLC: RemoveLate (Removed)\n")) return MCL_OK; } int UpdateLateList( mclcb_t *mclcb ) { int layer; rlccb_t *rlccb; late_list_t *prev, *current; TRACELVL(5, (mcl_stdout, "-> RLC: UpdateLateList\n")) ASSERT(mclcb!=NULL) rlccb = &(mclcb->rlccb); #ifdef DEBUG if( rlccb->rx_nblate > 0 ) { TRACELVL(3, (mcl_stdout, " RLC: packets late:\n")) } #endif for ( layer = 0; layer < mclcb->nb_level; layer++) { prev = &(rlccb->rx_missing[layer]); current = prev->next; while ( current != NULL) { ASSERT( current->ttw !=0 ) TRACELVL(3, (mcl_stdout, "\t layer=%d nseq=%d ttw=%d\n", layer, current->seq_num, current->ttw)) if((--(current->ttw)) == 0) { /* this one is lost! */ int nseq = current->seq_num; prev->next = current->next; free(current); (rlccb->rx_nblate)--; (rlccb->rx_nblate_since_sp)--; UpdateLossList(mclcb); if (mclcb->verbose == 2) { struct timeval time; time = mcl_get_tvtime(); PRINT_OUT((mcl_stdout, "\n%ld.%06ld\tloss_detected %d %d %d\n", time.tv_sec, time.tv_usec, layer, nseq, rlccb->rx_nblost+1)) } TRACELVL(3, (mcl_stdout, " RLC: pkt %d of layer %d lost! total: %d lost\n", nseq, layer, rlccb->rx_nblost+1)) if( AddLost(mclcb) == TOO_MANY_LOSSES ) goto fin; } else prev = current; current = prev->next; } } fin: TRACELVL(5, (mcl_stdout, "<- RLC: UpdateLateList (ok)\n")) return MCL_OK; } int AddLost( mclcb_t *mclcb ) { rlccb_t *rlccb; lost_list_t *new_lost; TRACELVL(5, (mcl_stdout, "-> RLC: AddLost\n")) ASSERT(mclcb!=NULL) rlccb = &(mclcb->rlccb); rlccb->rx_nblost ++; rlccb->rx_nblost_since_sp ++; if ( rlccb->rx_nblost >= rlccb->rlc_loss_limit ) { /* too many losses... drop a layer! */ if (mcl_drop_layer(mclcb, MCL_HIGHEST_LAYER, MCL_DO_IT ) < 0) { /* error, cannot drop layer */ TRACELVL(5, (mcl_stdout, "<- RLC: AddLost: cant drop layer, ignore\n")) return MCL_OK; } TRACELVL(2, (mcl_stdout, " RLC: congestion, drop a layer, now receiving from %d layers\n", mclcb->nb_level)) /* initial state for futur potential use of this layer*/ rlccb->rx_first_pkt[mclcb->nb_level]=1; /* Clean up late and lost lists... */ FreeLists(mclcb); /* entering the deaf period... */ ASSERT(mcl_rlc_rx_period!=0) rlccb->rx_deaf_wait = rlccb->rlc_deaf_period/mcl_rlc_rx_period; TRACELVL(3, (mcl_stdout, "AddLost: LOSS, rlccb->rx_deaf_wait=%d\n", rlccb->rx_deaf_wait)) TRACELVL(5, (mcl_stdout, "<- RLC: AddLost: too many losses, layer dropped\n")) return TOO_MANY_LOSSES; } if( !( new_lost = (lost_list_t *)malloc(sizeof(lost_list_t)))) { PRINT_ERR((mcl_stderr, "AddLost: no memory")) mcl_exit(-1); } new_lost->pkt_remaining = rlccb->rlc_loss_timeout; new_lost->next = rlccb->rx_lost.next; rlccb->rx_lost.next = new_lost; TRACELVL(5, (mcl_stdout, "<- RLC:AddLost (ok)\n")) return MCL_OK; } int UpdateLossList( mclcb_t *mclcb ) { rlccb_t *rlccb; lost_list_t *prev, *current; TRACELVL(5, (mcl_stdout, "-> RLC: UpdateLossList\n")) ASSERT(mclcb!=NULL) rlccb = &(mclcb->rlccb); prev = &(rlccb->rx_lost); current = prev->next; while (current != NULL) { if( --(current->pkt_remaining) == 0) { /* this loss is too old : removing */ prev->next = current->next; free(current); (rlccb->rx_nblost)--; } else prev = current; current = prev->next; } TRACELVL(5, (mcl_stdout, "<- RLC: UpdateLossList (ok)\n")) return MCL_OK; } void FreeLists(mclcb_t *mclcb) { int i; late_list_t *current_late; lost_list_t *current_lost; rlccb_t *rlccb; TRACELVL(5, (mcl_stdout, "-> RLC: FreeLists\n")) ASSERT(mclcb!=NULL) rlccb = &(mclcb->rlccb); for( i = 0; irx_missing[i].next; while ( current_late != NULL ) { rlccb->rx_missing[i].next = current_late->next; free(current_late); current_late = rlccb->rx_missing[i].next; } rlccb->rx_missing[i].next = NULL; /* redundant, isn't it? */ } current_lost = rlccb->rx_lost.next; while ( current_lost != NULL ) { rlccb->rx_lost.next = current_lost->next; free(current_lost); current_lost = rlccb->rx_lost.next; } rlccb->rx_lost.next = NULL; /* redundant, isn't it? */ rlccb->rx_nblost = 0; rlccb->rx_nblate = 0; rlccb->rx_nblost_since_sp = 0; rlccb->rx_nblate_since_sp = 0; } #endif /* } RLC */