157028Ssklower /*
257028Ssklower * Copyright (C) Dirk Husemann, Computer Science Department IV,
357028Ssklower * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
4*63216Sbostic * Copyright (c) 1992, 1993
5*63216Sbostic * The Regents of the University of California. All rights reserved.
657028Ssklower *
757028Ssklower * This code is derived from software contributed to Berkeley by
857028Ssklower * Dirk Husemann and the Computer Science Department (IV) of
957028Ssklower * the University of Erlangen-Nuremberg, Germany.
1057028Ssklower *
1157028Ssklower * %sccs.include.redist.c%
1257028Ssklower *
13*63216Sbostic * @(#)llc_timer.c 8.1 (Berkeley) 06/10/93
1457028Ssklower */
1557028Ssklower
1657028Ssklower #include <sys/param.h>
1757028Ssklower #include <sys/systm.h>
1857028Ssklower #include <sys/mbuf.h>
1957028Ssklower #include <sys/domain.h>
2057028Ssklower #include <sys/socket.h>
2157028Ssklower #include <sys/protosw.h>
2257028Ssklower #include <sys/errno.h>
2357028Ssklower #include <sys/time.h>
2457028Ssklower #include <sys/kernel.h>
2557028Ssklower
2657028Ssklower #include <net/if.h>
2757028Ssklower #include <net/if_dl.h>
2857028Ssklower #include <net/if_llc.h>
2957028Ssklower
3057028Ssklower #include <netccitt/dll.h>
3157028Ssklower #include <netccitt/llc_var.h>
3257028Ssklower
3357028Ssklower
3457028Ssklower /*
3557028Ssklower * Various timer values. They can be adjusted
3657028Ssklower * by patching the binary with adb if necessary.
3757028Ssklower */
3857028Ssklower /* ISO 8802-2 timers */
3957028Ssklower int llc_n2 = LLC_N2_VALUE;
4057028Ssklower int llc_ACK_timer = LLC_ACK_TIMER;
4157028Ssklower int llc_P_timer = LLC_P_TIMER;
4257028Ssklower int llc_BUSY_timer = LLC_BUSY_TIMER;
4357028Ssklower int llc_REJ_timer = LLC_REJ_TIMER;
4457028Ssklower /* Implementation specific timers */
4557028Ssklower int llc_AGE_timer = LLC_AGE_TIMER;
4657028Ssklower int llc_DACTION_timer = LLC_DACTION_TIMER;
4757028Ssklower
4857028Ssklower /*
4957028Ssklower * The timer routine. We are called every 500ms by the kernel.
5057028Ssklower * Handle the various virtual timers.
5157028Ssklower */
5257028Ssklower
5357028Ssklower void
llc_timer()5457028Ssklower llc_timer()
5557028Ssklower {
5657028Ssklower register struct llc_linkcb *linkp;
5757028Ssklower register struct llc_linkcb *nlinkp;
5857028Ssklower register int timer;
5957028Ssklower register int action;
6057028Ssklower register int s = splimp();
6157028Ssklower
6257028Ssklower /*
6357028Ssklower * All links are accessible over the doubly linked list llccb_q
6457028Ssklower */
6557028Ssklower if (!LQEMPTY) {
6657028Ssklower /*
6757028Ssklower * A for-loop is not that great an idea as the linkp
6857028Ssklower * might get deleted if the age timer has expired ...
6957028Ssklower */
7057028Ssklower linkp = LQFIRST;
7157028Ssklower while (LQVALID(linkp)) {
7257028Ssklower nlinkp = LQNEXT(linkp);
7357028Ssklower /*
7457028Ssklower * Check implementation specific timers first
7557028Ssklower */
7657028Ssklower /* The delayed action/acknowledge idle timer */
7757028Ssklower switch (LLC_TIMERXPIRED(linkp, DACTION)) {
7857028Ssklower case LLC_TIMER_RUNNING:
7957028Ssklower LLC_AGETIMER(linkp, DACTION);
8057028Ssklower break;
8157028Ssklower case LLC_TIMER_EXPIRED: {
8257028Ssklower register int cmdrsp;
8357028Ssklower register int pollfinal;
8457028Ssklower
8557028Ssklower switch (LLC_GETFLAG(linkp, DACTION)) {
8657028Ssklower case LLC_DACKCMD:
8757028Ssklower cmdrsp = LLC_CMD, pollfinal = 0;
8857028Ssklower break;
8957028Ssklower case LLC_DACKCMDPOLL:
9057028Ssklower cmdrsp = LLC_CMD, pollfinal = 1;
9157028Ssklower break;
9257028Ssklower case LLC_DACKRSP:
9357028Ssklower cmdrsp = LLC_RSP, pollfinal = 0;
9457028Ssklower break;
9557028Ssklower case LLC_DACKRSPFINAL:
9657028Ssklower cmdrsp = LLC_RSP, pollfinal = 1;
9757028Ssklower break;
9857028Ssklower }
9957028Ssklower llc_send(linkp, LLCFT_RR, cmdrsp, pollfinal);
10057028Ssklower LLC_STOPTIMER(linkp, DACTION);
10157028Ssklower break;
10257028Ssklower }
10357028Ssklower }
10457028Ssklower /* The link idle timer */
10557028Ssklower switch (LLC_TIMERXPIRED(linkp, AGE)) {
10657028Ssklower case LLC_TIMER_RUNNING:
10757028Ssklower LLC_AGETIMER(linkp, AGE);
10857028Ssklower break;
10957028Ssklower case LLC_TIMER_EXPIRED:
11057028Ssklower /*
11157028Ssklower * Only crunch the link when really no
11257028Ssklower * timers are running any more.
11357028Ssklower */
11457028Ssklower if (llc_anytimersup(linkp) == 0) {
11557028Ssklower llc_dellink(linkp);
11657028Ssklower LLC_STOPTIMER(linkp, AGE);
11757028Ssklower goto gone;
11857028Ssklower } else {
11957028Ssklower LLC_STARTTIMER(linkp, AGE);
12057028Ssklower }
12157028Ssklower break;
12257028Ssklower }
12357028Ssklower /*
12457028Ssklower * Now, check all the ISO 8802-2 timers
12557028Ssklower */
12657028Ssklower FOR_ALL_LLC_TIMERS(timer) {
12757028Ssklower action = 0;
12857028Ssklower if ((linkp->llcl_timerflags & (1<<timer)) &&
12957028Ssklower (linkp->llcl_timers[timer] == 0)) {
13057028Ssklower switch (timer) {
13157028Ssklower case LLC_ACK_SHIFT:
13257028Ssklower action = LLC_ACK_TIMER_EXPIRED;
13357028Ssklower break;
13457028Ssklower case LLC_P_SHIFT:
13557028Ssklower action = LLC_P_TIMER_EXPIRED;
13657028Ssklower break;
13757028Ssklower case LLC_BUSY_SHIFT:
13857028Ssklower action = LLC_BUSY_TIMER_EXPIRED;
13957028Ssklower break;
14057028Ssklower case LLC_REJ_SHIFT:
14157028Ssklower action = LLC_REJ_TIMER_EXPIRED;
14257028Ssklower break;
14357028Ssklower }
14457028Ssklower linkp->llcl_timerflags &= ~(1<<timer);
14557028Ssklower (void)llc_statehandler(linkp, (struct llc *)0, action, 0, 1);
14657028Ssklower } else if (linkp->llcl_timers[timer] > 0)
14757028Ssklower linkp->llcl_timers[timer]--;
14857028Ssklower }
14957028Ssklower
15057028Ssklower gone: linkp = nlinkp;
15157028Ssklower }
15257028Ssklower }
15357028Ssklower splx (s);
15457028Ssklower }
155