|
|
1.1 ! root 1: #include "../chunix/chsys.h" ! 2: #include "../chunix/chconf.h" ! 3: #include "../chaos/chaos.h" ! 4: ! 5: /* ! 6: * Send a STS packet on this connection ! 7: * if allocation fails it is not sent ! 8: */ ! 9: sendsts(conn) ! 10: register struct connection *conn; ! 11: { ! 12: register struct packet *pkt; ! 13: ! 14: if ((pkt = pkalloc(sizeof(struct sts_data), 1)) != NOPKT) { ! 15: setpkt(conn, pkt); ! 16: makests(conn, pkt); ! 17: sendctl(pkt); ! 18: } ! 19: } ! 20: ! 21: /* ! 22: * Send a SNS packet on this connection ! 23: * if allocation failed nothing is sent ! 24: */ ! 25: sendsns(conn) ! 26: register struct connection *conn; ! 27: { ! 28: register struct packet *pkt; ! 29: ! 30: if ((pkt = pkalloc(0, 1)) != NOPKT) { ! 31: setpkt(conn, pkt); ! 32: pkt->pk_op = SNSOP; ! 33: pkt->pk_lenword = 0; ! 34: pkt->pk_ackn = conn->cn_racked = conn->cn_rread; ! 35: sendctl(pkt); ! 36: } ! 37: } ! 38: ! 39: /* ! 40: * Send an open in response to a RFC ! 41: * return NOPKT is allocation fails else, open packet ! 42: */ ! 43: sendopn(conn) ! 44: register struct connection *conn; ! 45: { ! 46: register struct packet *pkt; ! 47: ! 48: if ((pkt = pkalloc(sizeof(struct sts_data), 1)) != NOPKT) { ! 49: conn->cn_rsts = conn->cn_rwsize >> 1; ! 50: conn->cn_tlast = 0; ! 51: pkt->pk_op = OPNOP; ! 52: pkt->pk_len = sizeof(struct sts_data); ! 53: pkt->pk_receipt = conn->cn_rlast; ! 54: pkt->pk_rwsize = conn->cn_rwsize; ! 55: debug(DCONN,printf("Conn #%x: open sent\n",conn->cn_lidx)); ! 56: (void)ch_write(conn, pkt); ! 57: } ! 58: } ! 59: ! 60: ! 61: /* ! 62: * Following are functions and macros that deal with tranmitters directly ! 63: * ! 64: * Macro XMITHEAD (pkt, xcvr) queues pkt on xcvr for transmission, putting ! 65: * it at the head of the queue for "quick" action. The transmitter is ! 66: * started if no packet is currently being transmitted. ! 67: * It is assumed that the pkt is a single one and not a list. ! 68: * Macro XMITTAIL is similar except that is queues the packet at the tail ! 69: * of the transmit list, treats the pkt argument as a list, and puts a time ! 70: * stamp in each packet in the list. ! 71: * Note that XMITTAIL modifies the variable pkt. ! 72: */ ! 73: #define XMITHEAD(pkt, axcvr) \ ! 74: { register struct chxcvr *xcvr = axcvr; \ ! 75: pkt->pk_next = xcvr->xc_list; \ ! 76: xcvr->xc_list = pkt; \ ! 77: if (xcvr->xc_tail == NOPKT) { \ ! 78: xcvr->xc_tail = pkt; \ ! 79: if (xcvr->xc_tpkt == NOPKT) \ ! 80: (*xcvr->xc_start)(xcvr); \ ! 81: } \ ! 82: } ! 83: /* ! 84: * Sendctl - send a control packet that will not be acknowledged and ! 85: * will not be retransmitted (this actual packet). Put the ! 86: * given packet at the head of the transmit queue so it is transmitted ! 87: * "quickly", i.e. before data packets queued at the tail of the queue. ! 88: * If anything is wrong (no path, bad subnet) we just throw it ! 89: * away. Remember, pk_next is assumed to be == NOPKT. ! 90: */ ! 91: sendctl(pkt) ! 92: register struct packet *pkt; ! 93: { ! 94: register struct chroute *r; ! 95: ! 96: debug(DSEND, (printf("Sending: %d ", pkt->pk_op), prpkt(pkt, "ctl"), printf("\n"))); ! 97: if (pkt->pk_dsubnet >= CHNSUBNET || ! 98: (r = &Chroutetab[pkt->pk_dsubnet])->rt_type == CHNOPATH) ! 99: ch_free((char *)pkt); ! 100: else if (pkt->pk_daddr == Chmyaddr) ! 101: sendtome(pkt); ! 102: else { ! 103: if (r->rt_type == CHFIXED || r->rt_type == CHBRIDGE) { ! 104: pkt->pk_xdest = r->rt_addr; ! 105: r = &Chroutetab[r->rt_subnet]; ! 106: } else ! 107: pkt->pk_xdest = pkt->pk_daddr; ! 108: XMITHEAD(pkt, r->rt_xcvr); ! 109: } ! 110: } ! 111: /* ! 112: * Senddata - send a list of controlled packets, all assumed to be to the ! 113: * same destination. Queue them on the end of the appropriate transmit ! 114: * queue. ! 115: * Similar to sendctl, but stuffs time, handles a list, and puts pkts ! 116: * at the end of the queue instead of at the beginning, and fakes ! 117: * transmission if it can't really send the packets (as opposed to ! 118: * throwing the packets away) ! 119: */ ! 120: senddata(pkt) ! 121: register struct packet *pkt; ! 122: { ! 123: register struct chroute *r; ! 124: ! 125: debug(DSEND, (printf("Sending: %d ", pkt->pk_op), prpkt(pkt, "data"), printf("\n"))); ! 126: if (pkt->pk_dsubnet >= CHNSUBNET || ! 127: (r = &Chroutetab[pkt->pk_dsubnet])->rt_type == CHNOPATH) { ! 128: struct packet *npkt; ! 129: ! 130: do { ! 131: npkt = pkt->pk_next; ! 132: pkt->pk_next = NOPKT; ! 133: xmitdone(pkt); ! 134: } while ((pkt = npkt) != NOPKT); ! 135: } else if (pkt->pk_daddr == Chmyaddr) ! 136: sendtome(pkt); ! 137: else { ! 138: register struct chxcvr *xcvr; ! 139: register unsigned short dest; ! 140: ! 141: if (r->rt_type == CHFIXED || r->rt_type == CHBRIDGE) { ! 142: dest = r->rt_addr; ! 143: r = &Chroutetab[r->rt_subnet]; ! 144: } else ! 145: dest = pkt->pk_daddr; ! 146: xcvr = r->rt_xcvr; ! 147: if (xcvr->xc_list == NOPKT) ! 148: xcvr->xc_list = pkt; ! 149: else ! 150: xcvr->xc_tail->pk_next = pkt; ! 151: for (;;) { ! 152: pkt->pk_time = Chclock; ! 153: pkt->pk_xdest = dest; ! 154: if (pkt->pk_next == NOPKT) ! 155: break; ! 156: pkt = pkt->pk_next; ! 157: } ! 158: xcvr->xc_tail = pkt; ! 159: if (xcvr->xc_tpkt == NOPKT) ! 160: (*xcvr->xc_start)(xcvr); ! 161: } ! 162: } ! 163: /* ! 164: * Send the given RUT packet out on the given tranceiver, which has the given ! 165: * cost. If the "copy" flag is true, make a copy of the packet. ! 166: * Note that if copy is not set, the packet data gets modified. ! 167: */ ! 168: sendrut(pkt, axcvr, cost, copy) ! 169: register struct packet *pkt; ! 170: register struct chxcvr *axcvr; ! 171: unsigned short cost; ! 172: int copy; ! 173: { ! 174: register struct rut_data *rd; ! 175: struct rut_data *rdend; ! 176: ! 177: if (copy) { ! 178: struct packet *npkt; ! 179: ! 180: if ((npkt = pkalloc((int)pkt->pk_len, 1)) == NOPKT) ! 181: return; ! 182: movepkt(pkt, npkt); ! 183: pkt = npkt; ! 184: } ! 185: rdend = (struct rut_data *)(pkt->pk_cdata + pkt->pk_len); ! 186: for (rd = pkt->pk_rutdata; rd < rdend; rd++) ! 187: rd->pk_cost += cost; ! 188: pkt->pk_saddr = axcvr->xc_addr; ! 189: pkt->pk_xdest = 0; ! 190: XMITHEAD(pkt, axcvr); ! 191: } ! 192: /* ! 193: * Send the (list of) packet(s) to myself - NOTE THIS CAN BE RECURSIVE! ! 194: */ ! 195: sendtome(pkt) ! 196: register struct packet *pkt; ! 197: { ! 198: register struct packet *rpkt, *npkt; ! 199: static struct chxcvr fakexcvr; ! 200: ! 201: /* ! 202: * Static structure is used to economize on stack space. ! 203: * We are careful to use it very locally so that recursion still ! 204: * works. Cleaner solutions don't recurse very well. ! 205: * Basically for each packet in the list, prepare it for ! 206: * transmission by executing xmitnext, ! 207: * complete the transmission by calling xmitdone, ! 208: * then receive the packet on the other side, possibly ! 209: * causing this routine to recurse (after we're done with the ! 210: * static structure until next time around the loop) ! 211: * When this routine is called with a list of data packets, things ! 212: * can get pretty weird. ! 213: */ ! 214: while (pkt != NOPKT) { ! 215: /* ! 216: * Make the transmit list consist of one packet to send. ! 217: * Save the rest of the list in npkt. ! 218: */ ! 219: npkt = pkt->pk_next; ! 220: pkt->pk_next = NOPKT; ! 221: fakexcvr.xc_tpkt = NOPKT; ! 222: fakexcvr.xc_list = fakexcvr.xc_tail = pkt; ! 223: /* ! 224: * The xmitnext just dequeues pkt and sets ackn. ! 225: * It will free the packet if its not worth sending. ! 226: */ ! 227: (void)xmitnext(&fakexcvr); ! 228: if (fakexcvr.xc_tpkt) { ! 229: /* ! 230: * So it really should be sent. ! 231: * First make a copy for the receiving side in rpkt. ! 232: */ ! 233: if ((rpkt = pkalloc((int)pkt->pk_len, 1)) != NOPKT) ! 234: movepkt(pkt, rpkt); ! 235: /* ! 236: * This xmitdone just completes transmission. ! 237: * Now pkt is out of our hands. ! 238: */ ! 239: xmitdone(pkt); ! 240: /* ! 241: * So transmission is complete. Now receive it. ! 242: */ ! 243: if (rpkt != NOPKT) ! 244: rcvpkt(rpkt); ! 245: } ! 246: pkt = npkt; ! 247: } ! 248: } ! 249: /* ! 250: * Indicate that actual transmission of the current packet has been completed. ! 251: * Called by the device dependent interrupt routine when transmission ! 252: * of a packet has finished. ! 253: */ ! 254: xmitdone(pkt) ! 255: register struct packet *pkt; ! 256: { ! 257: register struct connection *conn; ! 258: register struct packet *npkt; ! 259: ! 260: if (pkt->pk_saddr == Chmyaddr && CONTPKT(pkt) && ! 261: pkt->pk_stindex < CHNCONNS && ! 262: (conn = Chconntab[pkt->pk_stindex]) != NOCONN && ! 263: pkt->pk_sidx == conn->cn_lidx && ! 264: (conn->cn_state == CSOPEN || conn->cn_state == CSRFCSENT) && ! 265: cmp_gt(pkt->pk_pkn, conn->cn_trecvd)) { ! 266: pkt->pk_time = Chclock; ! 267: if ((npkt = conn->cn_thead) == NOPKT || ! 268: cmp_lt(pkt->pk_pkn, npkt->pk_pkn)) { ! 269: pkt->pk_next = npkt; ! 270: conn->cn_thead = pkt; ! 271: } else { ! 272: for( ; npkt->pk_next != NOPKT; npkt = npkt->pk_next) ! 273: if(cmp_lt(pkt->pk_pkn, npkt->pk_next->pk_pkn)) ! 274: break; ! 275: pkt->pk_next = npkt->pk_next; ! 276: npkt->pk_next = pkt; ! 277: } ! 278: if(pkt->pk_next == NOPKT) ! 279: conn->cn_ttail = pkt; ! 280: } else ! 281: ch_free((char *)pkt); ! 282: } ! 283: /* ! 284: * Return the next packet on which to begin transmission (if none, NOPKT). ! 285: */ ! 286: struct packet * ! 287: xmitnext(xcvr) ! 288: register struct chxcvr *xcvr; ! 289: { ! 290: register struct packet *pkt; ! 291: register struct connection *conn; ! 292: ! 293: while ((pkt = xcvr->xc_tpkt = xcvr->xc_list) != NOPKT) { ! 294: if ((xcvr->xc_list = pkt->pk_next) == NOPKT) ! 295: xcvr->xc_tail = NOPKT; ! 296: if (pkt->pk_saddr == Chmyaddr && CONTPKT(pkt)) ! 297: if (pkt->pk_stindex < CHNCONNS && ! 298: (conn = Chconntab[pkt->pk_stindex]) != NOCONN && ! 299: pkt->pk_sidx == conn->cn_lidx && ! 300: (conn->cn_state == CSOPEN || conn->cn_state == CSRFCSENT) && ! 301: cmp_gt(pkt->pk_pkn, conn->cn_trecvd)) ! 302: pkt->pk_ackn = conn->cn_racked = conn->cn_rread; ! 303: else { ! 304: debug(DPKT, ! 305: printf("invalid pkt to send: #%x\n", ! 306: conn->cn_lidx)); ! 307: ch_free((char *)pkt); ! 308: continue; ! 309: } ! 310: xcvr->xc_ttime = Chclock; ! 311: break; ! 312: } ! 313: return (pkt); ! 314: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.