1*6826Ssam 
2*6826Ssam #include "../h/param.h"
3*6826Ssam #include "../h/systm.h"
4*6826Ssam #include "../h/mbuf.h"
5*6826Ssam #include "../h/protosw.h"
6*6826Ssam #include "../h/socket.h"
7*6826Ssam #include "../h/socketvar.h"
8*6826Ssam #include "../net/dn_systm.h"
9*6826Ssam #include "../net/nsp.h"
10*6826Ssam #include "../net/nsp_var.h"
11*6826Ssam #include "../errno.h"
12*6826Ssam 
13*6826Ssam int nspidebug = 1;
14*6826Ssam #define	printd	if(nspidebug)printf
15*6826Ssam /*
16*6826Ssam  * NSP input routine: decode incoming packet and dispatch
17*6826Ssam  * to appropriate socket.  Called from the software interrupt
18*6826Ssam  * at splnet.
19*6826Ssam  *
20*6826Ssam  * TODO:
21*6826Ssam  *	count occurances of various error conditions.
22*6826Ssam  */
23*6826Ssam 
24*6826Ssam nspintr()
25*6826Ssam {
26*6826Ssam 	struct mbuf *m;
27*6826Ssam 	struct tprh *t;
28*6826Ssam 	int s, bom, eom;
29*6826Ssam 	u_short srcnode;
30*6826Ssam 	char *p;
31*6826Ssam 	struct nspcb *np;
32*6826Ssam 
33*6826Ssam 	/*
34*6826Ssam 	 * Loop pulling packets off the interrupt queue.
35*6826Ssam 	 */
36*6826Ssam next:
37*6826Ssam 	s = splimp();
38*6826Ssam 	IF_DEQUEUE(&nspintrq, m);
39*6826Ssam 	splx(s);
40*6826Ssam 	printd("nsp_input: m 0x%x", m);
41*6826Ssam 	if (m == 0)
42*6826Ssam 		return;
43*6826Ssam 	t = mtod(m, struct tprh *);
44*6826Ssam 	srcnode = t->tprh_srcnode;
45*6826Ssam 	m->m_len -= sizeof (struct tprh);	/* use m_adj??? */
46*6826Ssam 	m->m_off += sizeof (struct tprh);
47*6826Ssam 	printd(", srcnode %d, len %d", srcnode, m->m_len);
48*6826Ssam 	if (m->m_len <= 0) {
49*6826Ssam 		m_freem(m);
50*6826Ssam 		goto next;
51*6826Ssam 	}
52*6826Ssam 
53*6826Ssam 	/*
54*6826Ssam 	 * Switch on the type of the message.
55*6826Ssam 	 */
56*6826Ssam 	p = mtod(m, char *);
57*6826Ssam 	switch (*p) {
58*6826Ssam 
59*6826Ssam 	/*
60*6826Ssam 	 * Got a Data message, possibly with EOM and
61*6826Ssam 	 * BOM flags set.  Call nsp_chkaddr to do ack
62*6826Ssam 	 * and flow controll processing, then pass the
63*6826Ssam 	 * data to the user.
64*6826Ssam 	 */
65*6826Ssam 	case NSP_DATA|NSP_EOM|NSP_BOM:
66*6826Ssam 		eom = bom = 1;
67*6826Ssam 		goto data;
68*6826Ssam 
69*6826Ssam 	case NSP_DATA|NSP_EOM:
70*6826Ssam 		eom = 1;
71*6826Ssam 		goto data;
72*6826Ssam 
73*6826Ssam 	case NSP_DATA|NSP_BOM:
74*6826Ssam 		bom = 1;
75*6826Ssam 
76*6826Ssam 	case NSP_DATA:
77*6826Ssam 	data:
78*6826Ssam 		printd(", DATA (%d,%d)", bom, eom);
79*6826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_DATA, &segnum);
80*6826Ssam 		if (np == 0) {
81*6826Ssam 			m_freem(m);
82*6826Ssam 			goto next;
83*6826Ssam 		}
84*6826Ssam 
85*6826Ssam 		/*
86*6826Ssam 		 * Data messages only valid in Run state
87*6826Ssam 		 */
88*6826Ssam 		if (np->n_state != NS_RUN) {
89*6826Ssam 			printf(", !RUN (%d)\n", np->n_state);
90*6826Ssam 			m_freem(m);
91*6826Ssam 			goto next;
92*6826Ssam 		}
93*6826Ssam 		if (SEQ_GTR(segnum, np->na_xmtdat)) {
94*6826Ssam 			/* SHOULD DO SEGMENT RECONSTRUCTION HERE */
95*6826Ssam 			printd(", got data!");
96*6826Ssam 			sbpappend(m, &np->n_socket->sb_rcv);
97*6826Ssam 		} else
98*6826Ssam 			np->n_flags |= NF_DATACK;
99*6826Ssam 		break;
100*6826Ssam 
101*6826Ssam 	/*
102*6826Ssam 	 * Got an interrupt message.  Call nsp_chkaddr
103*6826Ssam 	 * (as usual).  Save the interrupt data for the
104*6826Ssam 	 * user.
105*6826Ssam 	 * GENERATE A SIGNAL OF SOME SORT???
106*6826Ssam 	 */
107*6826Ssam 	case NSP_INTR:
108*6826Ssam 		printd(", INTR");
109*6826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_INTR, &segnum);
110*6826Ssam 		if (np == 0) {
111*6826Ssam 			m_freem(m);
112*6826Ssam 			goto next;
113*6826Ssam 		}
114*6826Ssam 
115*6826Ssam 		/*
116*6826Ssam 		 * If we are in the Connect Confirm state then
117*6826Ssam 		 * this Interrupt packet causes the transition
118*6826Ssam 		 * to the Run state.  Otherwise we better be in
119*6826Ssam 		 * the Run state already.
120*6826Ssam 		 */
121*6826Ssam 		if (np->n_state == NS_CC)
122*6826Ssam 			np->n_state = NS_RUN;
123*6826Ssam 		else if (np->n_state != NS_RUN) {
124*6826Ssam 			printf(", !RUN %d\n", np->n_state);
125*6826Ssam 			m_freem(m);
126*6826Ssam 			goto next;
127*6826Ssam 		}
128*6826Ssam 
129*6826Ssam 		/*
130*6826Ssam 		 * If this segment is the one after the last
131*6826Ssam 		 * other data segment we acked, and there is
132*6826Ssam 		 * no waiting interrupt message, then queue
133*6826Ssam 		 * this one up.
134*6826Ssam 		 */
135*6826Ssam 		if (segnum == SEQ_ADD(np->na_xmtoth, 1) &&
136*6826Ssam 		    np->nf_locint == NFL_EMPTY) {
137*6826Ssam 			if (np->nb_rcv) {
138*6826Ssam 				printd(", flush old intr data");
139*6826Ssam 				m_freem(np->nb_rcv);
140*6826Ssam 			}
141*6826Ssam 			if (m->m_len > 16) {
142*6826Ssam 				printd(", intr data too long\n");
143*6826Ssam 				m_freem(m);
144*6826Ssam 				goto next;
145*6826Ssam 			}
146*6826Ssam 			np->nb_rcv = m;
147*6826Ssam 			np->nf_locint = NFL_INTR;
148*6826Ssam 			np->na_xmtoth = segnum;		/* really += 1 */
149*6826Ssam 			np->n_flags |= NF_OTHACK;
150*6826Ssam 		} else if (SEQ_LEQ(segnum, np->na_xmtoth))
151*6826Ssam 			np->n_flags |= NF_OTHACK;
152*6826Ssam 		break;
153*6826Ssam 
154*6826Ssam 	/*
155*6826Ssam 	 * Got a Link Service message.  Process options
156*6826Ssam 	 * to modify flow control values.
157*6826Ssam 	 */
158*6826Ssam 	case NSP_LS:
159*6826Ssam 		printd(", LS");
160*6826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_LS, &segnum);
161*6826Ssam 		if (np == 0) {
162*6826Ssam 			m_freem(m);
163*6826Ssam 			goto next;
164*6826Ssam 		}
165*6826Ssam 
166*6826Ssam 		/*
167*6826Ssam 		 * If we are in the Connect Confirm state then
168*6826Ssam 		 * this Link Service packet causes the transition
169*6826Ssam 		 * to the Run state.  Otherwise we better be in
170*6826Ssam 		 * the Run state already.
171*6826Ssam 		 */
172*6826Ssam 		if (np->n_state == NS_CC)
173*6826Ssam 			np->n_state = NS_RUN;
174*6826Ssam 		else if (np->n_state != NS_RUN) {
175*6826Ssam 			printd(", !RUN %d\n", np->n_state);
176*6826Ssam 			m_freem(m);
177*6826Ssam 			goto next;
178*6826Ssam 		}
179*6826Ssam 		p = mtod(m, char *);
180*6826Ssam 		lsf = *p++;
181*6826Ssam 		fcval = *p;
182*6826Ssam 		printd(", lsf 0x%x, fcval %d", lsf, fcval);
183*6826Ssam 		switch (lsf & NSPLS_FCVALINT) {
184*6826Ssam 		case NSPLS_DATREQ:
185*6826Ssam 			if (seqnum == SEQ_ADD(np->na_xmtoth, 1)) {
186*6826Ssam 				if (np->nf_remdat + fcval >= -128 &&
187*6826Ssam 				    np->nf_remdat + fcval <= 127) {
188*6826Ssam 					np->nf_remdat += fcval;
189*6826Ssam 					np->na_xmtoth = segnum;
190*6826Ssam 					np->n_flags |= NF_OTHACK;
191*6826Ssam 					switch (lsf & NSPLS_FCMOD) {
192*6826Ssam 					case NSPLS_NOCHANGE:
193*6826Ssam 						break;
194*6826Ssam 					case NSPLS_ON:
195*6826Ssam 						np->n_flags &= ~NF_DATOFF;
196*6826Ssam 						break;
197*6826Ssam 					case NSPLS_OFF:
198*6826Ssam 						np->n_flags |= NF_DATOFF;
199*6826Ssam 						break;
200*6826Ssam 					default:
201*6826Ssam 						printd(", bad fcmod");
202*6826Ssam 					}
203*6826Ssam 				}
204*6826Ssam 			} else if (SEQ_LEQ(segnum, np->na_xmtoth))
205*6826Ssam 				np->n_flags |= NF_OTHACK;
206*6826Ssam 			break;
207*6826Ssam 
208*6826Ssam 		case NSPLS_INTREQ:
209*6826Ssam 			if (seqnum == SEQ_ADD(np->na_xmtoth, 1)) {
210*6826Ssam 				if (fcval >= 0 && np->nf_remint+fcval <= 127) {
211*6826Ssam 					np->nf_remint += fcval;
212*6826Ssam 					np->na_xmtoth = segnum;
213*6826Ssam 					np->n_flags |= NF_OTHACK;
214*6826Ssam 			} else if (SEQ_LEQ(segnum, np->na_xmtoth))
215*6826Ssam 				np->n_flags |= NF_OTHACK;
216*6826Ssam 			break;
217*6826Ssam 
218*6826Ssam 		default:
219*6826Ssam 			printd(", bad fcvalint");
220*6826Ssam 		}
221*6826Ssam 		break;
222*6826Ssam 
223*6826Ssam 	/*
224*6826Ssam 	 * Got an acknowledgement for a Data message.
225*6826Ssam 	 * Nsp_chkaddr processes the ack, nothing else
226*6826Ssam 	 * to do.
227*6826Ssam 	 */
228*6826Ssam 	case NSP_DATACK:
229*6826Ssam 		printd(", DATACK");
230*6826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_DATACK, &segnum);
231*6826Ssam 		if (np == 0) {
232*6826Ssam 			m_freem(m);
233*6826Ssam 			goto next;
234*6826Ssam 		}
235*6826Ssam 		break;
236*6826Ssam 
237*6826Ssam 	/*
238*6826Ssam 	 * Got an acknowledgement for an Other Data message.
239*6826Ssam 	 * Nsp_chkaddr processes the ack, nothing else to do.
240*6826Ssam 	 */
241*6826Ssam 	case NSP_OTHACK:
242*6826Ssam 		printd(", OTHACK");
243*6826Ssam 		np = nsp_chkaddr(m, srcnode, NSP_OTHACK, &segnum);
244*6826Ssam 		if (np == 0) {
245*6826Ssam 			m_freem(m);
246*6826Ssam 			goto next;
247*6826Ssam 		}
248*6826Ssam 		break;
249*6826Ssam 
250*6826Ssam 	/*
251*6826Ssam 	 * Got a Connect Acknowledgement.  Just verify
252*6826Ssam 	 * the address and perform the state transition.
253*6826Ssam 	 */
254*6826Ssam 	case NSP_CONACK:
255*6826Ssam 		DOIT
256*6826Ssam 		break;
257*6826Ssam 
258*6826Ssam 	/*
259*6826Ssam 	 * Got an unknown message, count it and flush it.
260*6826Ssam 	 */
261*6826Ssam 	default:
262*6826Ssam 		printd(", UNKNOWN!!!");
263*6826Ssam 		m_freem(m);
264*6826Ssam 		break;
265*6826Ssam 	}
266*6826Ssam 	printd("\n");
267*6826Ssam 	goto next;
268*6826Ssam }
269