|
|
1.1 ! root 1: #include "../chunix/chsys.h" ! 2: #include "../chunix/chconf.h" ! 3: #include "../chaos/chaos.h" ! 4: ! 5: /* ! 6: * Clock level processing. ! 7: * ch_clock should be called each clock tick (HZ per second) ! 8: * at a priority equal to or higher that LOCK. ! 9: * ! 10: * Terminology: ! 11: * Packet aging: Retransmitting packets that are not acked within ! 12: * AGERATE ticks ! 13: * ! 14: * Probe: The sending of a SNS packet if not all of the packets ! 15: * we have sent have been acknowledged ! 16: * ! 17: * Responding: Send a SNS every so often to see if the guy is still ! 18: * alive (after NRESPONDS we declare him dead) ! 19: * ! 20: * RFC aging: The retransmission of RFC packets ! 21: * ! 22: * Route aging: Increase the cost of transmitting over gateways so we ! 23: * will use another gateway if the current gateway goes ! 24: * down. ! 25: * Route broadcast: If we are connected to more than one subnet, broad ! 26: * cast our bridge status every BRIDGERATE seconds. ! 27: * ! 28: * Interface hung: Checking periodically for dead interfaces (or dead ! 29: * "other end"'s of point-to-point links). ! 30: * ! 31: * These rates might want to vary with the cost of getting to the host. ! 32: * They also might want to reside in the chconf.h file if they are not a real ! 33: * network standard. ! 34: * ! 35: * Since these rates are dependent on a run-time variable ! 36: * (This is a good idea if you think about it long enough), ! 37: * We might want to initialize specific variables at run-time to ! 38: * avoid recalculation if the profile of chclock is disturbing. ! 39: */ ! 40: #define MINRATE ORATE /* Minimum of following rates */ ! 41: #define HANGRATE (Chhz>>1) /* How often to check for hung ! 42: interfaces */ ! 43: #define AGERATE (Chhz) /* Re-xmit pkt if not rcptd in time */ ! 44: #define PROBERATE (Chhz<<3) /* Send SNS to get STS for receipts or ! 45: to make sure the conn. is alive */ ! 46: #define ORATE (Chhz>>1) /* Xmit current (stream) output packet ! 47: if not touched in this time */ ! 48: #define TESTRATE (Chhz*45) /* Respond testing rate */ ! 49: #define ROUTERATE (Chhz<<2) /* Route aging rate */ ! 50: #define BRIDGERATE (Chhz*15) /* Routing broadcast rate */ ! 51: #define NRESPONDS 3 /* Test this many times before timing ! 52: out the connection */ ! 53: #define UPTIME (NRESPONDS*TESTRATE) /* Nothing in this time and ! 54: the connection is flushed */ ! 55: #define RFCRATE (Chhz*5) /* Retransmit RFC's this often */ ! 56: #define RFCTIME (RFCRATE*CHRFCTRYS) /* Try CHRFCTRYS times to RFC */ ! 57: ! 58: chtime Chclock; ! 59: ! 60: ch_clock() ! 61: { ! 62: register struct connection *conn; ! 63: register struct connection **connptr; ! 64: register struct packet *pkt; ! 65: chtime inactive; ! 66: int probing; /* are we probing this time ? */ ! 67: static chtime nextclk = 1; /* next time to do anything */ ! 68: static chtime nextprobe = 1; /* next time to probe */ ! 69: static chtime nexthang = 1; /* next time to chxtime() */ ! 70: static chtime nextroute = 1; /* next time to age routing */ ! 71: static chtime nextbridge = 1; /* next time to send routing */ ! 72: ! 73: if (nextclk != ++Chclock) ! 74: return; ! 75: nextclk += MINRATE; ! 76: if (cmp_gt(Chclock, nextprobe)) { ! 77: probing = 1; ! 78: nextprobe += PROBERATE; ! 79: } else ! 80: probing = 0; ! 81: if (cmp_gt(Chclock, nexthang)) { ! 82: chxtime(); ! 83: nexthang += HANGRATE; ! 84: } ! 85: if (cmp_gt(Chclock, nextroute)) { ! 86: chroutage(); ! 87: nextroute += ROUTERATE; ! 88: } ! 89: if (cmp_gt(Chclock, nextbridge)) { ! 90: chbridge(); ! 91: nextbridge += BRIDGERATE; ! 92: } ! 93: debug(DNOCLK,return); ! 94: for (connptr = &Chconntab[0]; connptr < &Chconntab[CHNCONNS]; connptr++) ! 95: if ((conn = *connptr) == NOCONN) ! 96: continue; ! 97: else if (conn->cn_state == CSOPEN) { ! 98: #ifdef CHSTRCODE ! 99: /* ! 100: * Timeout the current output stream packet. ! 101: * The timeout value should vary per connection. ! 102: * (shades of x.29!!) ! 103: */ ! 104: if ((pkt = conn->cn_toutput) != NOPKT && ! 105: cmp_gt(Chclock, pkt->pk_time + ORATE) && ! 106: !chtfull(conn)) { ! 107: conn->cn_toutput = NOPKT; ! 108: /* ! 109: * We don't care if the packet will ! 110: * be lost since either the connection ! 111: * is no longer open anyway, or an ! 112: * ANSOP was sent in the wrong state. ! 113: */ ! 114: (void)ch_write(conn, pkt); ! 115: } ! 116: #endif ! 117: if (conn->cn_thead != NOPKT) ! 118: clkretran(conn); ! 119: if (probing) { ! 120: inactive = Chclock - conn->cn_active; ! 121: if (inactive >= UPTIME) ! 122: chdead(conn); ! 123: else if (conn->cn_tacked != conn->cn_tlast && ! 124: inactive >= PROBERATE || ! 125: inactive >= TESTRATE) { ! 126: debug(DCONN, ! 127: printf("Conn #%x: Probe: %D\n", ! 128: conn->cn_lidx, ! 129: inactive)); ! 130: sendsns(conn); ! 131: } ! 132: } ! 133: } else if (conn->cn_state == CSRFCSENT) { ! 134: /* ! 135: * The RFC packet, if it has finished being sent out ! 136: * will be at cn_thead. If it is still in the process ! 137: * of being sent it will not be there yet. ! 138: */ ! 139: pkt = conn->cn_thead; ! 140: inactive = Chclock - conn->cn_active; ! 141: if (inactive >= RFCTIME) { ! 142: debug(DCONN|DABNOR, printf("Conn #%x: RFC Timeout\n",conn->cn_lidx)); ! 143: clsconn(conn, CSCLOSED, NOPKT); ! 144: } else if (pkt != NOPKT && ! 145: cmp_gt(Chclock, pkt->pk_time + RFCRATE)) { ! 146: debug(DCONN|DABNOR,printf("Conn #%x: RFC Retransmit\n",conn->cn_lidx)); ! 147: conn->cn_ttail = conn->cn_thead = NOPKT; ! 148: senddata(pkt); ! 149: } ! 150: } ! 151: } ! 152: ! 153: clkretran(conn) ! 154: struct connection *conn; ! 155: { ! 156: register struct packet *pkt, **opkt; ! 157: register struct packet *lastpkt; ! 158: struct packet *firstpkt = NOPKT; ! 159: ! 160: for (opkt = &conn->cn_thead; pkt = *opkt;) ! 161: if (cmp_gt(Chclock, pkt->pk_time + AGERATE)) { ! 162: if (firstpkt == NOPKT) ! 163: firstpkt = pkt; ! 164: else ! 165: lastpkt->pk_next = pkt; ! 166: lastpkt = pkt; ! 167: *opkt = pkt->pk_next; ! 168: pkt->pk_next = NOPKT; ! 169: } else ! 170: opkt = &pkt->pk_next; ! 171: if (firstpkt != NOPKT) { ! 172: debug(DCONN|DABNOR, ! 173: printf("Conn #%x: Rexmit (op:%d, pkn:%d)\n", ! 174: conn->cn_lidx, firstpkt->pk_op, ! 175: firstpkt->pk_pkn)); ! 176: senddata(firstpkt); ! 177: } ! 178: } ! 179: /* ! 180: * The connection has been inactive too long, close it. ! 181: */ ! 182: chdead(conn) ! 183: register struct connection *conn; ! 184: { ! 185: static char tomsg[] = "Foreign host not responding"; ! 186: register struct packet *pkt; ! 187: ! 188: debug(DCONN|DABNOR,printf("Conn #%x: Timeout\n", conn->cn_lidx)); ! 189: if ((pkt = pkalloc(sizeof(tomsg), 1)) != NOPKT) { ! 190: pkt = pktstr(pkt, tomsg, sizeof(tomsg)); ! 191: pkt->pk_op = LOSOP; ! 192: } ! 193: clsconn(conn, CSINCT, pkt); ! 194: } ! 195: /* ! 196: * Increase the cost of accessing a subnet via a gateway ! 197: */ ! 198: chroutage() ! 199: { ! 200: register struct chroute *r; ! 201: ! 202: for (r = Chroutetab; r < &Chroutetab[CHNSUBNET]; r++) ! 203: if ((r->rt_type == CHBRIDGE || r->rt_type == CHDIRECT) && ! 204: r->rt_cost < CHHCOST) ! 205: r->rt_cost++; ! 206: } ! 207: /* ! 208: * Send routing packets on all directly connected subnets, unless we are on ! 209: * only one. ! 210: */ ! 211: chbridge() ! 212: { ! 213: register struct chroute *r; ! 214: register struct packet *pkt; ! 215: register struct rut_data *rd; ! 216: register int ndirect; ! 217: register int n; ! 218: ! 219: /* ! 220: * Count the number of subnets to which we are directly connected. ! 221: * If not more than one, then we are not a bridge and shouldn't ! 222: * send out routing packets at all. ! 223: * While we're at it, count the number of subnets we know we ! 224: * have any access to. This number determines the size of the ! 225: * routine packet we need to send, if any. ! 226: */ ! 227: n = ndirect = 0; ! 228: for (r = Chroutetab; r <= &Chroutetab[CHNSUBNET]; r++) ! 229: switch(r->rt_type) { ! 230: case CHDIRECT: ! 231: ndirect++; ! 232: default: ! 233: n++; ! 234: break; ! 235: case CHNOPATH: ! 236: ; ! 237: } ! 238: if (ndirect <= 1 || ! 239: (pkt = pkalloc(n * sizeof(struct rut_data), 1)) == NOPKT) ! 240: return; ! 241: /* ! 242: * Build the routing packet to send out on each directly connected ! 243: * subnet. It is complete except for the cost of the directly ! 244: * connected subnet we are sending it out on. This cost must be ! 245: * added to each entry in the packet each time it is sent. ! 246: */ ! 247: pkt->pk_len = n * sizeof(struct rut_data); ! 248: pkt->pk_op = RUTOP; ! 249: pkt->pk_type = pkt->pk_daddr = pkt->pk_sidx = pkt->pk_didx = 0; ! 250: pkt->pk_next = NOPKT; ! 251: rd = pkt->pk_rutdata; ! 252: for (n = 0, r = Chroutetab; r < &Chroutetab[CHNSUBNET]; r++, n++) ! 253: if (r->rt_type != CHNOPATH) { ! 254: rd->pk_subnet = n; ! 255: rd->pk_cost = r->rt_cost; ! 256: rd++; ! 257: } ! 258: /* ! 259: * Now send out this packet on each directly connected subnet. ! 260: * ndirect becomes zero on last such subnet. ! 261: */ ! 262: for (r = Chroutetab; r < &Chroutetab[CHNSUBNET]; r++) ! 263: if (r->rt_type == CHDIRECT) ! 264: sendrut(pkt, r->rt_xcvr, r->rt_cost, --ndirect); ! 265: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.