|
|
1.1 ! root 1: /* ! 2: * C H R C V ! 3: * ! 4: * Chaosnet line discipline - handle a received packet. ! 5: * Chrcv() is called by the service routine for the RD queue. ! 6: * ! 7: * ! 8: * (c) Copyright 1984 Nirvonics, Inc. ! 9: * ! 10: * Written by Kurt Gollhardt ! 11: * Last update Fri Nov 16 11:16:20 1984 ! 12: * ! 13: * This software is the property of Nirvonics, Inc. ! 14: * All rights reserved. ! 15: * ! 16: */ ! 17: ! 18: #include "ch.h" ! 19: #if NCH > 0 ! 20: #include "../h/param.h" ! 21: #include "../h/systm.h" ! 22: #include "../h/stream.h" ! 23: #include "../h/conf.h" ! 24: #include "../chaosld/types.h" ! 25: #include "../chaosld/constants.h" ! 26: #include "../chaosld/globals.h" ! 27: ! 28: #define send_los(pkt,str) sendlos(pkt,str,sizeof(str)-1) ! 29: ! 30: #define STS_AGE hz/4 /* Minimum pkt age for re-xmission on STS */ ! 31: ! 32: ! 33: chrcv(q) ! 34: struct queue *q; ! 35: { ! 36: register struct packet *pkt; ! 37: register struct connection *conn; ! 38: register struct sts_data *sts; ! 39: register unsigned index; ! 40: ! 41: debug(DPKT,printf("Chrcv: ")); ! 42: if ((pkt = get_packet(q, 0)) == NOPKT) ! 43: return; ! 44: pkt->next = NOPKT; ! 45: ! 46: ch_busy++; ! 47: if (pkt->pk_op == MNTOP) ! 48: free_packet(pkt); ! 49: else if (pkt->pk_op == RFCOP) ! 50: rcvrfc(pkt); ! 51: else if (pkt->pk_op == BRDOP) ! 52: rcvbrd(pkt); ! 53: /* ! 54: * Check for various flavors of bad indices ! 55: */ ! 56: else if ((index = pkt->pk_didx.ci_tidx) >= NCH || ! 57: (conn = Chconn[index]) == NOCONN || ! 58: pkt->pk_didx.ci_idx != conn->cn_lidx.ci_idx) { ! 59: debug(DPKT|DABNOR,printf("Packet with bad index: %x, op:0%o\n", ! 60: pkt->pk_didx, pkt->pk_op)); ! 61: send_los(pkt, "Connection doesn't exist"); ! 62: /* ! 63: * Handle responses to our RFC ! 64: */ ! 65: } else if (conn->cn_state == CSRFCSENT) ! 66: switch(pkt->pk_op) { ! 67: case OPNOP: ! 68: debug(DCONN,printf("Conn #%x: OPEN received\n", conn->cn_lidx)); ! 69: /* ! 70: * Mark the connection as open, saving his index ! 71: */ ! 72: conn->cn_state = CSOPEN; ! 73: conn->cn_fidx = pkt->pk_sidx; ! 74: conn->cn_time = Chclock; ! 75: /* ! 76: * Indicate we have received AND "read" the OPEN ! 77: * Read his window size, indicate that he has ! 78: * received and acked the RFC, and acknowledge the OPN ! 79: */ ! 80: conn->cn_rread = conn->cn_rlast = pkt->pk_pkn; ! 81: flatten(pkt); ! 82: sts = (struct sts_data *)pkt->data->rptr; ! 83: conn->cn_twsize = sts->sts_rwsize; ! 84: receipt(conn, pkt->pk_ackn, pkt->pk_ackn); ! 85: /* ! 86: * Send him back an STS to get things going. ! 87: */ ! 88: setsts(conn, pkt); ! 89: reflect(pkt); ! 90: chd_newstate(conn); ! 91: break; ! 92: case CLSOP: ! 93: case ANSOP: ! 94: case FWDOP: ! 95: debug(DCONN,printf("Conn #%x: CLOSE/ANS received for RFC\n", conn->cn_lidx)); ! 96: close_conn(conn, CSCLOSED, pkt); ! 97: break; ! 98: default: ! 99: debug(DPKT|DABNOR, ! 100: printf("bad packet type for conn #%x in CSRFCSENT: %d\n", ! 101: conn->cn_lidx, pkt->pk_op)); ! 102: send_los(pkt, "Bad packet type reponse to RFC"); ! 103: } ! 104: /* ! 105: * Process a packet for an open connection ! 106: */ ! 107: else if (conn->cn_state == CSOPEN) { ! 108: conn->cn_time = Chclock; ! 109: if (ISDATA(pkt)) ! 110: rcvdata(conn, pkt); ! 111: else switch (pkt->pk_op) { ! 112: case OPNOP: ! 113: /* ! 114: * Ignore duplicate opens. ! 115: */ ! 116: debug(DPKT|DABNOR,printf("Duplicate open received\n")); ! 117: free_packet(pkt); ! 118: break; ! 119: case SNSOP: ! 120: debug(DPKT,prpkt(pkt, "SNS")); ! 121: receipt(conn, pkt->pk_ackn, pkt->pk_ackn); ! 122: setsts(conn, pkt); ! 123: reflect(pkt); ! 124: break; ! 125: case EOFOP: ! 126: rcvdata(conn, pkt); ! 127: break; ! 128: case LOSOP: ! 129: case CLSOP: ! 130: debug(DCONN, printf("Close rcvd on %x\n", conn->cn_lidx)); ! 131: close_conn(conn, pkt->pk_op == CLSOP ? CSCLOSED : CSLOST, ! 132: pkt); ! 133: break; ! 134: /* ! 135: * Uncontrolled data - queue it at the head of the rlist ! 136: */ ! 137: case UNCOP: ! 138: receipt(conn, pkt->pk_ackn, pkt->pk_ackn); ! 139: ch_input(conn, pkt); /* Send packet to pseudo-device */ ! 140: break; ! 141: case STSOP: ! 142: flatten(pkt); ! 143: sts = (struct sts_data *)pkt->data->rptr; ! 144: if (sts->sts_rwsize > conn->cn_twsize) ! 145: chd_newout(conn); ! 146: conn->cn_twsize = sts->sts_rwsize; ! 147: receipt(conn, pkt->pk_ackn, sts->sts_receipt); ! 148: free_packet(pkt); ! 149: chretran(conn, STS_AGE); /* Re-xmit all but very recent pkts */ ! 150: break; ! 151: default: ! 152: debug(DPKT|DABNOR, printf("bad opcode:%d\n", pkt->pk_op)); ! 153: send_los(pkt, "Bad opcode"); ! 154: /* should we do close_conn here? */ ! 155: } ! 156: /* ! 157: * Connection is neither waiting for an OPEN nor OPEN. ! 158: */ ! 159: } else { ! 160: debug(DPKT|DABNOR,printf("Packet for conn #%x (not open) state=%d, op:%d\n", conn->cn_lidx, conn->cn_state, pkt->pk_op)); ! 161: send_los(pkt, "Connection is closed"); ! 162: } ! 163: ! 164: --ch_busy; ! 165: } ! 166: ! 167: /* ! 168: * Process a received data packet - or an EOF packet which is mostly treated ! 169: * the same. ! 170: */ ! 171: rcvdata(conn, pkt) ! 172: register struct connection *conn; ! 173: register struct packet *pkt; ! 174: { ! 175: register struct packet *npkt; ! 176: ! 177: debug(DPKT,(prpkt(pkt,"DATA"),printf("\n")) ); ! 178: if (cmp_gt(pkt->pk_pkn, conn->cn_rread + conn->cn_rwsize)) { ! 179: debug(DPKT|DABNOR,printf("Discarding data out of window\n")); ! 180: free_packet(pkt); ! 181: return; ! 182: } ! 183: receipt(conn, pkt->pk_ackn, pkt->pk_ackn); ! 184: if (cmp_le(pkt->pk_pkn, conn->cn_rlast)) { ! 185: debug(DPKT,printf("Duplicate data packet\n")); ! 186: setsts(conn, pkt); ! 187: reflect(pkt); ! 188: return; ! 189: } ! 190: ! 191: /* ! 192: * Link the out of order list onto the new packet in case ! 193: * it fills the gap between in-order and out-of-order lists ! 194: * and to make it easy to grab all now-in-order packets from the ! 195: * out-of-order list. ! 196: */ ! 197: pkt->next = conn->cn_routorder; ! 198: /* ! 199: * Now transfer all in-order packets to the pseudo-device ! 200: */ ! 201: for (npkt = pkt; npkt != NOPKT && ! 202: npkt->pk_pkn == (unsigned short)(conn->cn_rlast + 1); ! 203: npkt = npkt->next) { ! 204: conn->cn_rlast++; ! 205: ch_input(conn, npkt); ! 206: } ! 207: /* ! 208: * If we received any in-order pkts, check if spontaneous STS is needed ! 209: */ ! 210: if (pkt != npkt) { ! 211: debug(DPKT,printf("new ordered data packet\n")); ! 212: conn->cn_routorder = npkt; ! 213: } else { ! 214: /* ! 215: * Here we have received an out of order packet which must be ! 216: * inserted into the out-of-order queue, in packet number order. ! 217: */ ! 218: for (npkt = pkt; (npkt = npkt->next) != NOPKT && ! 219: cmp_gt(pkt->pk_pkn, npkt->pk_pkn); ) ! 220: pkt->next = npkt; /* save the last pkt here */ ! 221: ! 222: if (npkt != NOPKT && pkt->pk_pkn == npkt->pk_pkn) { ! 223: debug(DPKT|DABNOR, ! 224: printf("Duplicate out of order packet\n")); ! 225: pkt->next = NOPKT; ! 226: setsts(conn, pkt); ! 227: reflect(pkt); ! 228: } else { ! 229: if (npkt == conn->cn_routorder) ! 230: conn->cn_routorder = pkt; ! 231: else ! 232: pkt->next->next = pkt; ! 233: pkt->next = npkt; ! 234: debug(DPKT|DABNOR, ! 235: printf("New out of order packet\n")); ! 236: } ! 237: } ! 238: } ! 239: ! 240: /* ! 241: * Process receipts and acknowledgements using recnum as the receipt. ! 242: */ ! 243: receipt(conn, acknum, recnum) ! 244: register struct connection *conn; ! 245: unsigned short acknum, recnum; ! 246: { ! 247: register struct packet *pkt, *pktl; ! 248: ! 249: ch_busy++; ! 250: /* ! 251: * Process a receipt, freeing packets that we now know have been ! 252: * received. ! 253: */ ! 254: if (cmp_gt(recnum, conn->cn_trecvd)) { ! 255: for (pktl = conn->cn_thead; ! 256: pktl != NOPKT && cmp_le(pktl->pk_pkn, recnum); ! 257: pktl = pkt) { ! 258: pkt = pktl->next; ! 259: free_packet(pktl); ! 260: } ! 261: if ((conn->cn_thead = pktl) == NOPKT) ! 262: conn->cn_ttail = NOPKT; ! 263: conn->cn_trecvd = recnum; ! 264: } ! 265: /* ! 266: * If the acknowledgement is new, update our idea of the ! 267: * latest acknowledged packet, and wakeup output that might be blocked ! 268: * on a full transmit window. ! 269: */ ! 270: if (cmp_gt(acknum, conn->cn_tacked)) ! 271: if (cmp_gt(acknum, conn->cn_tlast)) { ! 272: debug(DABNOR, (printf("Invalid acknowledgment(%d,%d)\n", ! 273: acknum, conn->cn_tlast))); ! 274: } else { ! 275: conn->cn_tacked = acknum; ! 276: chd_newout(conn); ! 277: } ! 278: --ch_busy; ! 279: } ! 280: ! 281: ! 282: #ifdef BRDBRIDGE ! 283: ! 284: int Chbrdbridge = 1; ! 285: #define MAXBRD 8 ! 286: ! 287: #endif BRDBRIDGE ! 288: ! 289: /* ! 290: * Process a received BRD ! 291: * The trickiness is that we must modify the bit map completely before ! 292: * sending it to anyone - thus we must remember all those to send it to. ! 293: */ ! 294: ! 295: rcvbrd(pkt) ! 296: register struct packet *pkt; ! 297: { ! 298: int bitlen = pkt->pk_ackn; ! 299: ! 300: /* Here pk_ackn is # bytes in subnet bitmap */ ! 301: if ((pkt->pk_len <= bitlen) || (bitlen >= CHNSUBNET/8)) { ! 302: free_packet(pkt); ! 303: return; ! 304: } ! 305: if (flatten(pkt)) ! 306: return; ! 307: ! 308: #ifdef BRDBRIDGE ! 309: if (Chbrdbridge) { ! 310: register struct chroute *r; ! 311: register int mask, i; ! 312: struct packet *npkt; ! 313: chaddr addrs[MAXBRD], *adp; ! 314: ! 315: bitp = pkt->data->rptr; ! 316: for (i = 0, r = Chroutetab; r < bitlen; i++) ! 317: for (mask = 1; mask & 0377; mask <<= 1, r++) ! 318: if (r->rt_type == CHDIRECT && r->rt_cost < HIGH_COST && ! 319: *bitp & mask && adp < &addrs[MAXBRD]) { ! 320: *bitp &= ~mask; ! 321: *adp++ = r->rt_path.ifp->my_addr; ! 322: } ! 323: while (adp > addrs) { ! 324: if ((npkt = new_packet()) == NOPKT) ! 325: return; ! 326: npkt->ph = pkt->ph; ! 327: append_packet(npkt, pkt->data->rptr, pkt->pk_len); ! 328: npkt->pk_daddr = *--adp; ! 329: npkt->pk_daddr.ch_host = 0; ! 330: npkt->pk_pkn = 1; ! 331: sendctl(npkt); ! 332: } ! 333: } ! 334: #endif BRDBRIDGE ! 335: ! 336: pkt->pk_lenword = pkt->pk_len - bitlen; ! 337: pkt->data->rptr += bitlen; ! 338: pkt->pk_ackn = 0; ! 339: rcvrfc(pkt); ! 340: } ! 341: ! 342: /* ! 343: * Process a received RFC ! 344: */ ! 345: rcvrfc(pkt) ! 346: register struct packet *pkt; ! 347: { ! 348: register struct connection *conn, **conptr; ! 349: register struct service *svp; ! 350: extern struct service Chservice[]; ! 351: struct packet **opkt, *pktl; ! 352: ! 353: debug(DPKT,prpkt(pkt,"RFC/BRD")); ! 354: /* ! 355: * Check if this is a duplicate RFC, and if so throw it away, ! 356: * and retransmit the OPEN. ! 357: */ ! 358: for (conptr = &Chconn[0]; conptr < &Chconn[NCH];) ! 359: if ((conn = *conptr++) != NOCONN && ! 360: conn->cn_fidx.ci_idx == pkt->pk_sidx.ci_idx && ! 361: conn->cn_faddr.ch_addr == pkt->pk_saddr.ch_addr) { ! 362: if (conn->cn_state == CSOPEN) { ! 363: debug(DPKT|DABNOR, ! 364: printf("Rcvrfc: Retransmitting open chan #%x\n", ! 365: (*conptr)->cn_lidx.ci_idx)); ! 366: chretran(conn, 0); ! 367: } else { ! 368: debug(DPKT|DABNOR, ! 369: printf("Rcvrfc: Duplicate RFC: %x\n", ! 370: conn->cn_lidx.ci_idx)); ! 371: } ! 372: free_packet(pkt); ! 373: return; ! 374: } ! 375: ! 376: if (flatten(pkt)) { ! 377: free_packet(pkt); ! 378: return; ! 379: } ! 380: ! 381: /* ! 382: * Scan the listen list for a listener and if one is found ! 383: * open the connection and remove the listen packet from the ! 384: * listen list. ! 385: */ ! 386: for (opkt = &Chlsnlist; (pktl = *opkt) != NOPKT; opkt = &pktl->next) ! 387: if(concmp(pkt, pktl->data->rptr, (int)pktl->pk_len)) { ! 388: conn = Chconn[pktl->pk_sidx.ci_tidx]; ! 389: *opkt = pktl->next; ! 390: free_packet(pktl); ! 391: lsnmatch(pkt, conn); ! 392: chd_newstate(conn); ! 393: return; ! 394: } ! 395: /* ! 396: * Check for built-in services. ! 397: */ ! 398: for (svp = Chservice; svp->name != 0; ++svp) ! 399: if (concmp(pkt, svp->name, svp->len)) { ! 400: (*svp->func)(pkt); ! 401: return; ! 402: } ! 403: /* ! 404: * There was no listener, so queue the RFC on the unmatched RFC list ! 405: * again checking for duplicates. ! 406: */ ! 407: if ((pktl = Chrfclist) == NOPKT) ! 408: Chrfclist = Chrfctail = pkt; ! 409: else { ! 410: do { ! 411: if(pktl->pk_sidx.ci_idx == pkt->pk_sidx.ci_idx && ! 412: pktl->pk_saddr.ch_addr == pkt->pk_saddr.ch_addr) { ! 413: debug(DPKT/*|DABNOR*/,printf("Rcvrfc: Discarding duplicate Rfc on Chrfclist\n")); ! 414: free_packet(pkt); ! 415: return; ! 416: } ! 417: } while ((pktl = pktl->next) != NOPKT); ! 418: Chrfctail->next = pkt; ! 419: Chrfctail = pkt; ! 420: } ! 421: debug(DCONN,printf("Rcvrfc: Queued Rfc on Chrfclist\n")); ! 422: /* ! 423: * A new unmatched RFC has been received. Send a copy of it up to the ! 424: * unmatched RFC server. ! 425: */ ! 426: copy_pkdata(ChaosQ, pkt); ! 427: } ! 428: ! 429: /* ! 430: * An RFC has matched a listener, either by an RFC coming and finding a match ! 431: * on the listener list, or by a listen being done and matching an RFC on the ! 432: * unmatched RFC list. So we change the state of the connection to CSRFCRCVD ! 433: */ ! 434: lsnmatch(rfcpkt, conn) ! 435: register struct packet *rfcpkt; ! 436: register struct connection *conn; ! 437: { ! 438: debug(DCONN,printf("Conn #%x: LISTEN matched \n", conn->cn_lidx)); ! 439: /* ! 440: * Initialize the conection ! 441: */ ! 442: conn->cn_time = Chclock; ! 443: conn->cn_state = CSRFCRCVD; ! 444: if (conn->cn_rwsize == 0) ! 445: conn->cn_rwsize = CHDRWSIZE; ! 446: conn->cn_faddr = rfcpkt->pk_saddr; ! 447: conn->cn_fidx = rfcpkt->pk_sidx; ! 448: ! 449: /* ! 450: * Indicate to the other end that we have received and "read" ! 451: * the RFC so that the open will truly acknowledge it. ! 452: */ ! 453: conn->cn_rlast = conn->cn_rread = rfcpkt->pk_pkn; ! 454: /* ! 455: * Queue up the RFC for the user to read if he wants it. ! 456: */ ! 457: chdrint(conn, rfcpkt); ! 458: } ! 459: ! 460: /* ! 461: * Remove a listener from the listener list, due to the listener bailing out. ! 462: * Called from top level at high priority ! 463: */ ! 464: rmlisten(conn) ! 465: register struct connection *conn; ! 466: { ! 467: register struct packet *opkt, *pkt; ! 468: ! 469: opkt = NOPKT; ! 470: for (pkt = Chlsnlist; pkt != NOPKT; opkt = pkt, pkt = pkt->next) ! 471: if (pkt->pk_sidx.ci_tidx == conn->cn_lidx.ci_tidx) { ! 472: if(opkt == NOPKT) ! 473: Chlsnlist = pkt->next; ! 474: else ! 475: opkt->next = pkt->next; ! 476: free_packet(pkt); ! 477: break; ! 478: } ! 479: } ! 480: ! 481: /* ! 482: * Compare the RFC contact name with the listener name. ! 483: */ ! 484: concmp(rfcpkt, lsnstr, lsnlen) ! 485: struct packet *rfcpkt; ! 486: register char *lsnstr; ! 487: register int lsnlen; ! 488: { ! 489: register char *rfcstr = (char *)rfcpkt->data->rptr; ! 490: register int rfclen; ! 491: ! 492: debug(DPKT,{printf("Rcvrfc: Comparing "); ! 493: print_str(rfcpkt->pk_len, rfcstr); ! 494: printf(" and "); ! 495: print_str(lsnlen, lsnstr); ! 496: printf("\n");}); ! 497: for (rfclen = rfcpkt->pk_len; rfclen; rfclen--, lsnlen--) ! 498: if (lsnlen <= 0) ! 499: return ((*rfcstr == ' ') ? 1 : 0); ! 500: else if (*rfcstr++ != *lsnstr++) ! 501: return(0); ! 502: return (lsnlen == 0); ! 503: } ! 504: ! 505: ! 506: ch_input(conn, pkt) ! 507: struct connection *conn; ! 508: struct packet *pkt; ! 509: { ! 510: int pkn, op, controlled; ! 511: ! 512: pkn = pkt->pk_pkn; ! 513: op = pkt->pk_op; ! 514: controlled = CONTROLLED(pkt); ! 515: ! 516: chdrint(conn, pkt); ! 517: ! 518: if (controlled) { ! 519: conn->cn_rread = pkn; ! 520: if (op == EOFOP) ! 521: sendsts(conn); ! 522: } ! 523: } ! 524: ! 525: ! 526: #ifdef DEBUG ! 527: prpkt(pkt, str) ! 528: register struct packet *pkt; ! 529: char *str; ! 530: { ! 531: printf("op=%s(%o) len=%d fc=%d\ndhost=%o didx=%x\nshost=%o sidx=%x\npkn=%d ackn=%d\n", ! 532: str, pkt->pk_op, pkt->pk_len, pkt->pk_fc, pkt->pk_daddr.ch_addr, ! 533: pkt->pk_didx.ci_idx, pkt->pk_saddr.ch_addr, pkt->pk_sidx.ci_idx, ! 534: (unsigned)pkt->pk_pkn, (unsigned)pkt->pk_ackn); ! 535: } ! 536: ! 537: print_str(len, s) ! 538: register int len; ! 539: register char *s; ! 540: { ! 541: while (len-- > 0 && *s != '\0') ! 542: printf("%c", *s++); ! 543: } ! 544: #endif DEBUG ! 545: ! 546: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.