1*8407Swnj /*	nsp_input.c	1.3	82/10/09	*/
26826Ssam 
36826Ssam #include "../h/param.h"
46826Ssam #include "../h/systm.h"
56826Ssam #include "../h/mbuf.h"
66826Ssam #include "../h/protosw.h"
76826Ssam #include "../h/socket.h"
86826Ssam #include "../h/socketvar.h"
9*8407Swnj #include "../netdecnet/dn_systm.h"
10*8407Swnj #include "../netdecnet/nsp.h"
11*8407Swnj #include "../netdecnet/nsp_var.h"
12*8407Swnj #include <errno.h>
136826Ssam 
146826Ssam int nspidebug = 1;
156826Ssam #define	printd	if(nspidebug)printf
166826Ssam /*
176826Ssam  * NSP input routine: decode incoming packet and dispatch
186826Ssam  * to appropriate socket.  Called from the software interrupt
196826Ssam  * at splnet.
206826Ssam  *
216826Ssam  * TODO:
226826Ssam  *	count occurances of various error conditions.
236826Ssam  */
246826Ssam 
nspintr()256826Ssam nspintr()
266826Ssam {
276826Ssam 	struct mbuf *m;
286826Ssam 	struct tprh *t;
296826Ssam 	int s, bom, eom;
306826Ssam 	u_short srcnode;
316826Ssam 	char *p;
326826Ssam 	struct nspcb *np;
336826Ssam 
346826Ssam 	/*
356826Ssam 	 * Loop pulling packets off the interrupt queue.
366826Ssam 	 */
376826Ssam next:
386826Ssam 	s = splimp();
396826Ssam 	IF_DEQUEUE(&nspintrq, m);
406826Ssam 	splx(s);
416826Ssam 	printd("nsp_input: m 0x%x", m);
426826Ssam 	if (m == 0)
436826Ssam 		return;
446826Ssam 	t = mtod(m, struct tprh *);
456826Ssam 	srcnode = t->tprh_srcnode;
466826Ssam 	m->m_len -= sizeof (struct tprh);	/* use m_adj??? */
476826Ssam 	m->m_off += sizeof (struct tprh);
486826Ssam 	printd(", srcnode %d, len %d", srcnode, m->m_len);
496826Ssam 	if (m->m_len <= 0) {
506826Ssam 		m_freem(m);
516826Ssam 		goto next;
526826Ssam 	}
536826Ssam 
546826Ssam 	/*
556826Ssam 	 * Switch on the type of the message.
566826Ssam 	 */
576826Ssam 	p = mtod(m, char *);
586826Ssam 	switch (*p) {
596826Ssam 
606826Ssam 	/*
616826Ssam 	 * Got a Data message, possibly with EOM and
626826Ssam 	 * BOM flags set.  Call nsp_chkaddr to do ack
636826Ssam 	 * and flow controll processing, then pass the
646826Ssam 	 * data to the user.
656826Ssam 	 */
666826Ssam 	case NSP_DATA|NSP_EOM|NSP_BOM:
676826Ssam 		eom = bom = 1;
686826Ssam 		goto data;
696826Ssam 
706826Ssam 	case NSP_DATA|NSP_EOM:
716826Ssam 		eom = 1;
726826Ssam 		goto data;
736826Ssam 
746826Ssam 	case NSP_DATA|NSP_BOM:
756826Ssam 		bom = 1;
766826Ssam 
776826Ssam 	case NSP_DATA:
786826Ssam 	data:
796826Ssam 		printd(", DATA (%d,%d)", bom, eom);
806826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_DATA, &segnum);
816826Ssam 		if (np == 0) {
826826Ssam 			m_freem(m);
836826Ssam 			goto next;
846826Ssam 		}
856826Ssam 
866826Ssam 		/*
876826Ssam 		 * Data messages only valid in Run state
886826Ssam 		 */
896826Ssam 		if (np->n_state != NS_RUN) {
906826Ssam 			printf(", !RUN (%d)\n", np->n_state);
916826Ssam 			m_freem(m);
926826Ssam 			goto next;
936826Ssam 		}
946826Ssam 		if (SEQ_GTR(segnum, np->na_xmtdat)) {
956826Ssam 			/* SHOULD DO SEGMENT RECONSTRUCTION HERE */
966826Ssam 			printd(", got data!");
976826Ssam 			sbpappend(m, &np->n_socket->sb_rcv);
986826Ssam 		} else
996826Ssam 			np->n_flags |= NF_DATACK;
1006826Ssam 		break;
1016826Ssam 
1026826Ssam 	/*
1036826Ssam 	 * Got an interrupt message.  Call nsp_chkaddr
1046826Ssam 	 * (as usual).  Save the interrupt data for the
1056826Ssam 	 * user.
1066826Ssam 	 * GENERATE A SIGNAL OF SOME SORT???
1076826Ssam 	 */
1086826Ssam 	case NSP_INTR:
1096826Ssam 		printd(", INTR");
1106826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_INTR, &segnum);
1116826Ssam 		if (np == 0) {
1126826Ssam 			m_freem(m);
1136826Ssam 			goto next;
1146826Ssam 		}
1156826Ssam 
1166826Ssam 		/*
1176826Ssam 		 * If we are in the Connect Confirm state then
1186826Ssam 		 * this Interrupt packet causes the transition
1196826Ssam 		 * to the Run state.  Otherwise we better be in
1206826Ssam 		 * the Run state already.
1216826Ssam 		 */
1226826Ssam 		if (np->n_state == NS_CC)
1236826Ssam 			np->n_state = NS_RUN;
1246826Ssam 		else if (np->n_state != NS_RUN) {
1256826Ssam 			printf(", !RUN %d\n", np->n_state);
1266826Ssam 			m_freem(m);
1276826Ssam 			goto next;
1286826Ssam 		}
1296826Ssam 
1306826Ssam 		/*
1316826Ssam 		 * If this segment is the one after the last
1326826Ssam 		 * other data segment we acked, and there is
1336826Ssam 		 * no waiting interrupt message, then queue
1346826Ssam 		 * this one up.
1356826Ssam 		 */
1366826Ssam 		if (segnum == SEQ_ADD(np->na_xmtoth, 1) &&
1376826Ssam 		    np->nf_locint == NFL_EMPTY) {
1386826Ssam 			if (np->nb_rcv) {
1396826Ssam 				printd(", flush old intr data");
1406826Ssam 				m_freem(np->nb_rcv);
1416826Ssam 			}
1426826Ssam 			if (m->m_len > 16) {
1436826Ssam 				printd(", intr data too long\n");
1446826Ssam 				m_freem(m);
1456826Ssam 				goto next;
1466826Ssam 			}
1476826Ssam 			np->nb_rcv = m;
1486826Ssam 			np->nf_locint = NFL_INTR;
1496826Ssam 			np->na_xmtoth = segnum;		/* really += 1 */
1506826Ssam 			np->n_flags |= NF_OTHACK;
1516826Ssam 		} else if (SEQ_LEQ(segnum, np->na_xmtoth))
1526826Ssam 			np->n_flags |= NF_OTHACK;
1536826Ssam 		break;
1546826Ssam 
1556826Ssam 	/*
1566826Ssam 	 * Got a Link Service message.  Process options
1576826Ssam 	 * to modify flow control values.
1586826Ssam 	 */
1596826Ssam 	case NSP_LS:
1606826Ssam 		printd(", LS");
1616826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_LS, &segnum);
1626826Ssam 		if (np == 0) {
1636826Ssam 			m_freem(m);
1646826Ssam 			goto next;
1656826Ssam 		}
1666826Ssam 
1676826Ssam 		/*
1686826Ssam 		 * If we are in the Connect Confirm state then
1696826Ssam 		 * this Link Service packet causes the transition
1706826Ssam 		 * to the Run state.  Otherwise we better be in
1716826Ssam 		 * the Run state already.
1726826Ssam 		 */
1736826Ssam 		if (np->n_state == NS_CC)
1746826Ssam 			np->n_state = NS_RUN;
1756826Ssam 		else if (np->n_state != NS_RUN) {
1766826Ssam 			printd(", !RUN %d\n", np->n_state);
1776826Ssam 			m_freem(m);
1786826Ssam 			goto next;
1796826Ssam 		}
1806826Ssam 		p = mtod(m, char *);
1816826Ssam 		lsf = *p++;
1826826Ssam 		fcval = *p;
1836826Ssam 		printd(", lsf 0x%x, fcval %d", lsf, fcval);
1846826Ssam 		switch (lsf & NSPLS_FCVALINT) {
1856826Ssam 		case NSPLS_DATREQ:
1866826Ssam 			if (seqnum == SEQ_ADD(np->na_xmtoth, 1)) {
1876826Ssam 				if (np->nf_remdat + fcval >= -128 &&
1886826Ssam 				    np->nf_remdat + fcval <= 127) {
1896826Ssam 					np->nf_remdat += fcval;
1906826Ssam 					np->na_xmtoth = segnum;
1916826Ssam 					np->n_flags |= NF_OTHACK;
1926826Ssam 					switch (lsf & NSPLS_FCMOD) {
1936826Ssam 					case NSPLS_NOCHANGE:
1946826Ssam 						break;
1956826Ssam 					case NSPLS_ON:
1966826Ssam 						np->n_flags &= ~NF_DATOFF;
1976826Ssam 						break;
1986826Ssam 					case NSPLS_OFF:
1996826Ssam 						np->n_flags |= NF_DATOFF;
2006826Ssam 						break;
2016826Ssam 					default:
2026826Ssam 						printd(", bad fcmod");
2036826Ssam 					}
2046826Ssam 				}
2056826Ssam 			} else if (SEQ_LEQ(segnum, np->na_xmtoth))
2066826Ssam 				np->n_flags |= NF_OTHACK;
2076826Ssam 			break;
2086826Ssam 
2096826Ssam 		case NSPLS_INTREQ:
2106826Ssam 			if (seqnum == SEQ_ADD(np->na_xmtoth, 1)) {
2116826Ssam 				if (fcval >= 0 && np->nf_remint+fcval <= 127) {
2126826Ssam 					np->nf_remint += fcval;
2136826Ssam 					np->na_xmtoth = segnum;
2146826Ssam 					np->n_flags |= NF_OTHACK;
2156826Ssam 			} else if (SEQ_LEQ(segnum, np->na_xmtoth))
2166826Ssam 				np->n_flags |= NF_OTHACK;
2176826Ssam 			break;
2186826Ssam 
2196826Ssam 		default:
2206826Ssam 			printd(", bad fcvalint");
2216826Ssam 		}
2226826Ssam 		break;
2236826Ssam 
2246826Ssam 	/*
2256826Ssam 	 * Got an acknowledgement for a Data message.
2266826Ssam 	 * Nsp_chkaddr processes the ack, nothing else
2276826Ssam 	 * to do.
2286826Ssam 	 */
2296826Ssam 	case NSP_DATACK:
2306826Ssam 		printd(", DATACK");
2316826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_DATACK, &segnum);
2326826Ssam 		if (np == 0) {
2336826Ssam 			m_freem(m);
2346826Ssam 			goto next;
2356826Ssam 		}
2366826Ssam 		break;
2376826Ssam 
2386826Ssam 	/*
2396826Ssam 	 * Got an acknowledgement for an Other Data message.
2406826Ssam 	 * Nsp_chkaddr processes the ack, nothing else to do.
2416826Ssam 	 */
2426826Ssam 	case NSP_OTHACK:
2436826Ssam 		printd(", OTHACK");
2446826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_OTHACK, &segnum);
2456826Ssam 		if (np == 0) {
2466826Ssam 			m_freem(m);
2476826Ssam 			goto next;
2486826Ssam 		}
2496826Ssam 		break;
2506826Ssam 
2516826Ssam 	/*
2526826Ssam 	 * Got a Connect Acknowledgement.  Just verify
2536826Ssam 	 * the address and perform the state transition.
2546826Ssam 	 */
2556826Ssam 	case NSP_CONACK:
2566826Ssam 		DOIT
2576826Ssam 		break;
2586826Ssam 
2596826Ssam 	/*
2606826Ssam 	 * Got an unknown message, count it and flush it.
2616826Ssam 	 */
2626826Ssam 	default:
2636826Ssam 		printd(", UNKNOWN!!!");
2646826Ssam 		m_freem(m);
2656826Ssam 		break;
2666826Ssam 	}
2676826Ssam 	printd("\n");
2686826Ssam 	goto next;
2696826Ssam }
270