|
|
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.