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