/* LAPB (AX.25) timer recovery routines * Copyright 1991 Phil Karn, KA9Q */ /* Mods by G1EMM */ #include "global.h" #include "mbuf.h" #include "ax25.h" #include "timer.h" #include "lapb.h" static void tx_enq __ARGS((struct ax25_cb *axp)); int lapbtimertype = 0; /* default to binary exponential */ /* Called whenever timer T1 expires */ void recover(p) void *p; { register struct ax25_cb *axp = (struct ax25_cb *)p; axp->flags.retrans = 1; axp->retries++; switch(lapbtimertype){ case 2: /* original backoff mode*/ set_timer(&axp->t1,axp->srt * 2); break; case 1: /* linear backoff mode */ if((1L << axp->retries) < Blimit) set_timer(&axp->t1,dur_timer(&axp->t1) + axp->srt); break; case 0: /* exponential backoff mode */ if((1L << axp->retries) < Blimit) set_timer(&axp->t1,dur_timer(&axp->t1)*2); break; } switch(axp->state){ case LAPB_SETUP: if(axp->n2 != 0 && axp->retries > axp->n2){ nr_derate(axp); free_q(&axp->txq); axp->reason = LB_TIMEOUT; lapbstate(axp,LAPB_DISCONNECTED); } else { sendctl(axp,LAPB_COMMAND,SABM|PF); start_timer(&axp->t1); } break; case LAPB_DISCPENDING: if(axp->n2 != 0 && axp->retries > axp->n2){ nr_derate(axp); axp->reason = LB_TIMEOUT; lapbstate(axp,LAPB_DISCONNECTED); } else { sendctl(axp,LAPB_COMMAND,DISC|PF); start_timer(&axp->t1); } break; case LAPB_CONNECTED: case LAPB_RECOVERY: if(axp->n2 != 0 && axp->retries > axp->n2){ /* Give up */ nr_derate(axp); sendctl(axp,LAPB_RESPONSE,DM|PF); free_q(&axp->txq); axp->reason = LB_TIMEOUT; lapbstate(axp,LAPB_DISCONNECTED); } else { /* Transmit poll */ tx_enq(axp); lapbstate(axp,LAPB_RECOVERY); } break; } } /* Send a poll (S-frame command with the poll bit set) */ void pollthem(p) void *p; { register struct ax25_cb *axp; axp = (struct ax25_cb *)p; if(axp->proto == V1) return; /* Not supported in the old protocol */ switch(axp->state){ case LAPB_CONNECTED: axp->retries = 0; tx_enq(axp); lapbstate(axp,LAPB_RECOVERY); break; } } /* Called whenever timer T4 (link rudundancy timer) expires */ void redundant(p) void *p; { register struct ax25_cb *axp; axp = (struct ax25_cb *)p; switch(axp->state){ case LAPB_CONNECTED: case LAPB_RECOVERY: axp->retries = 0; sendctl(axp,LAPB_COMMAND,DISC|PF); start_timer(&axp->t1); free_q(&axp->txq); lapbstate(axp,LAPB_DISCPENDING); break; } } /* Transmit query */ static void tx_enq(axp) register struct ax25_cb *axp; { char ctl; struct mbuf *bp; /* I believe that retransmitting the oldest unacked * I-frame tends to give better performance than polling, * as long as the frame isn't too "large", because * chances are that the I frame got lost anyway. * This is an option in LAPB, but not in the official AX.25. */ if(axp->txq != NULLBUF && (len_p(axp->txq) < axp->pthresh || axp->proto == V1)){ /* Retransmit oldest unacked I-frame */ dup_p(&bp,axp->txq,0,len_p(axp->txq)); ctl = PF | I | ((axp->vs - axp->unack) & MMASK) << 1 | axp->vr << 5; sendframe(axp,LAPB_COMMAND,ctl,bp); } else { ctl = len_p(axp->rxq) >= axp->window ? RNR|PF : RR|PF; sendctl(axp,LAPB_COMMAND,ctl); } axp->response = 0; stop_timer(&axp->t3); start_timer(&axp->t1); }