1 /*
2  $Log:	rdp_input.c,v $
3  * Revision 2.10  85/06/18  14:37:38  walsh
4  * check for version mismatch.
5  *
6  * Revision 2.9  85/04/08  14:35:11  root
7  * *** empty log message ***
8  *
9  * Revision 2.8  85/02/26  08:26:48  walsh
10  * First pass at using IP source routing information to establish connections
11  * (possibly with hosts not known by the Internet gateways.)  The hooks with
12  * TCP could be better done - particularly dealing with IP addresses in the
13  * header for checksums and tcpdb lookups.
14  *
15  * Revision 2.7  84/11/15  09:55:52  walsh
16  * redid how we deal with compiler padding in the RDP header structure.
17  *
18  * Revision 2.6  84/11/08  16:11:17  walsh
19  * Added code to gather statistics on RDP traffic.  This makes the RDPCB
20  * too big unles you make mbufs 512 bytes large.  RDP_CS should be turned off
21  * unless you do.
22  *
23  * Revision 2.5  84/11/06  14:30:09  walsh
24  * intorduced RDP_HLSHIFT
25  *
26  * Revision 2.4  84/11/05  16:33:07  walsh
27  * fix coding error.
28  *
29  * Revision 2.3  84/11/05  10:51:53  walsh
30  * flush debugging log if new state is RDP_sCLOSED so that packet printer/
31  * system analyst sees final transitions.
32  *
33  * Revision 2.2  84/11/02  15:28:19  walsh
34  * Allow for RDP header fields not on natural boundries.  (Protocol
35  * specifiers say will be part of next version in 6-12 months).
36  * Until then, there goes the speed...  Yucho modifications.
37  *
38  * Revision 2.1  84/11/02  10:12:58  walsh
39  * Fixed to include RCS comments in checked out source.
40  *
41  *
42  * description:
43  * Packet input processing for Reliable Datagram Protocol.
44  *
45  * revision 1.6
46  * date: 84/07/19 10:21:22;  author: walsh;  state: Exp;  lines added/del: 2/1
47  * Organized macros and classified their definitions in rdp_macros.h.
48  *
49  * revision 1.5
50  * date: 84/07/10 09:59:38;  author: walsh;  state: Exp;  lines added/del: 10/10
51  * declared some register variables.
52  *
53  * revision 1.4
54  * date: 84/07/06 14:43:19;  author: wjacobso;  state: Exp;  lines added/del: 2/2
55  * *** empty log message ***
56  *
57  * revision 1.3
58  * date: 84/07/06 13:50:26;  author: wjacobso;  state: Exp;  lines added/del: 6/3
59  * use RDP_ACTION macro instead of rdp_action
60  *
61  * revision 1.2
62  * date: 84/07/06 09:49:20;  author: root;  state: Exp;  lines added/del: 27/45
63  * This version seems to run bug-free.
64  *
65  * revision 1.1
66  * date: 84/06/26 14:17:19;  author: walsh;  state: Exp;
67  * Initial revision
68  */
69 
70 
71 #ifdef RDP
72 #ifdef	RCSIDENT
73 static char rcsident[] = "$Header: rdp_input.c,v 2.10 85/06/18 14:37:38 walsh Exp $";
74 #endif
75 
76 #include "../h/param.h"
77 #include "../h/dir.h"
78 #include "../h/user.h"
79 #include "../h/kernel.h"
80 #include "../h/inode.h"
81 #include "../h/mbuf.h"
82 #include "../h/socket.h"
83 #include "../h/socketvar.h"
84 #include "../h/syslog.h"
85 
86 #include "../net/if.h"
87 #include "../net/route.h"
88 
89 #include "../bbnnet/in.h"
90 #include "../bbnnet/in_var.h"
91 #include "../bbnnet/net.h"
92 #include "../bbnnet/in_pcb.h"
93 #include "../bbnnet/ip.h"
94 #include "../bbnnet/nopcb.h"
95 #include "../bbnnet/rdp.h"
96 #include "../bbnnet/rdp_macros.h"
97 #ifdef	HMP
98 #include "../bbnnet/hmp_traps.h"
99 #endif
100 
101 extern int nosum;
102 
103 /*
104  * this is called from ip_input() upon reception of an RDP packet.
105  */
106 rdp_input(mp)
107 register struct mbuf *mp;
108 {
109     register RDPHDR		*pkt;
110     register struct ip	*ip;
111     rdpchecksum pktcksum;
112     rdpchecksum cksum;
113     register int hlen;
114     register struct inpcb *inp;
115 
116     rdpstat.r_total++;
117 
118     /*
119      * see ip_input().  Get access to constant part of RDP header.
120      */
121 #define SZ (RDPHDRSZ + sizeof(struct ip))
122     if ((mp->m_off > MMAXOFF) || (mp->m_len < SZ))
123     {
124 	if ((mp = m_pullup(mp, SZ)) == NULL)
125 	{
126 	    rdpstat.r_tooshort ++;
127 	    return;
128 	}
129     }
130 #undef SZ
131 
132     ip	= mtod(mp, struct ip *);
133     pkt	= (RDPHDR *) (ip + 1);
134 
135     /* make sure header, incl. option region, does not overflow mbuf */
136 
137     hlen = hdrlen(pkt) + sizeof(struct ip);
138     if (hlen > mp->m_len)
139     {
140 	if ((mp = m_pullup(mp, hlen)) == NULL)
141 	{
142 	    ip_log(ip, "rdp header overflow");
143 #ifdef HMPTRAPS
144 	    /* hmp_trap(T_TCP_OVFLO, (caddr_t)0,0); */
145 #else
146 	    /* netlog(mp); */
147 #endif
148 	    return;
149 	}
150 	ip = mtod(mp, struct ip *);
151 	pkt = (RDPHDR *) (ip + 1);
152     }
153 
154     if (pkt->rh_ver != RDP_VERSION)
155     {
156 	ip_log (ip, "rdp version mismatch");
157 	netlog (mp);
158 	return;
159     }
160 
161     /*
162      * do checksum calculation, drop packet if bad
163      * Checksum must be done on header in net form due to byte ordering
164      * and rotations.
165      */
166 
167     pktcksum = RDP_CKSUM(pkt);
168     RDP_CKSUM(pkt) = 0;
169     cksum = rdp_cksum(mp);
170     if (cksum != pktcksum)
171     {
172 	rdpstat.r_badsum++;
173 	if (! nosum)
174 	{
175 	    inet_cksum_err ("rdp", ip, (u_long) pktcksum, (u_long) cksum);
176 	    netlog(mp);
177 	    return;
178 	}
179     }
180 
181     /* byte swap header */
182 
183     pkt->rh_dlen  = ntohs(pkt->rh_dlen);
184     RDP_SEQNO(pkt) = ntohl(RDP_SEQNO(pkt));
185     RDP_ACKNO(pkt) = ntohl(RDP_ACKNO(pkt));
186 
187     if (ip->ip_len != hdrlen(pkt) + pkt->rh_dlen)
188     {
189 	ip_log(ip, "rdp length error");
190 	log(LOG_INFO, "%d + %d != %d\n", hdrlen(pkt), pkt->rh_dlen,
191 	    ip->ip_len);
192 	netlog(mp);
193 	return;
194     }
195 
196     inp = in_pcblookup(&rdp, ip->ip_src.s_addr, (u_short)pkt->rh_sport,
197 			     ip->ip_dst.s_addr, (u_short)pkt->rh_dport, TRUE);
198     if (inp == NULL)
199     {
200 	/* nobody wants it */
201 	rdpstat.r_drops ++;
202 	rdp_uncon_rst (pkt);
203     }
204     else
205     {
206 	register rdpstate newstate;
207 	register RDPCB	*rdpcb;
208 
209 	rdpcb = (RDPCB *)inp->inp_ppcb;
210 
211 #ifdef RDP_CS
212 	rdpcb->r_rcvd.r_total ++;
213 	if (pkt->rh_flags & (RDP_fNULL|RDP_fRST|RDP_fSYN))
214 	{
215 	    if (pkt->rh_flags & RDP_fNULL)
216 		rdpcb->r_rcvd.r_nullpkts ++;
217 	    if (pkt->rh_flags & RDP_fRST)
218 		rdpcb->r_rcvd.r_rstpkts ++;
219 	    if (pkt->rh_flags & RDP_fSYN)
220 		rdpcb->r_rcvd.r_synpkts ++;
221 	}
222 #endif
223 	/* found a protocol control block for the message */
224 	RDP_ACTION(RDP_iNETR, rdpcb, ((int) pkt), newstate);
225     }
226 }
227 
228 
229 /*
230  * Call a subroutine specifically tailored to deal with this state
231  * transition.
232  */
233 rdpaction (input, rdpcb, arg)
234 register RDPCB	*rdpcb;
235 {
236     register rdpstate newstate;
237 
238     RDP_ACTION (input, rdpcb, arg, newstate)
239 }
240 
241 rdp_uncon_rst (pkt)
242 register RDPHDR	*pkt;
243 {
244     register struct ip *ip;
245     register struct mbuf *mp;
246     struct in_addr tempinaddr;
247     rdpportnum tempport;
248     long his_seqno;
249     int error;
250 
251     mp = dtom(pkt);
252 
253     /* make sure we don't send a RST in response to an RST */
254 
255     if (pkt->rh_flags & RDP_fRST)
256     {
257 	m_freem(mp);
258 	return;
259     }
260     ip = (struct ip *) (((caddr_t) pkt) - sizeof(struct ip));
261 
262     /* free everything but the header */
263 
264     m_freem(mp->m_next);
265     mp->m_next = NULL;
266     mp->m_len = sizeof(struct ip) + RDPHDRSZ;
267 
268     /* direct the packet back to the originator */
269 
270     tempinaddr = ip->ip_dst;
271     ip->ip_dst = ip->ip_src;
272     ip->ip_src = tempinaddr;
273 
274     tempport = pkt->rh_sport;
275     pkt->rh_sport = pkt->rh_dport;
276     pkt->rh_dport = tempport;
277 
278     /*
279      * and initialize (seqno, ackno, flags) so that it's "in window"
280      * and resets him independent of his state (is acceptable to all
281      * net reception subroutines.)
282      */
283     his_seqno = RDP_SEQNO(pkt);
284     RDP_SEQNO(pkt) = htonl(RDP_ACKNO(pkt) + 1);
285     RDP_ACKNO(pkt) = htonl(his_seqno);
286     if (pkt->rh_flags & RDP_fSYN)
287 	pkt->rh_flags = RDP_fRST|RDP_fACK;
288     else
289 	pkt->rh_flags = RDP_fRST;
290 
291     /* and send it */
292 
293     pkt->rh_hdrlen	= RDPHDRSZ >> RDP_HLSHIFT;
294     pkt->rh_dlen	= 0;
295     RDP_CKSUM(pkt)	= 0;
296 
297     RDP_CKSUM(pkt)	= rdp_cksum(mp);
298 
299     NOPCB_IPSEND (mp, RDPHDRSZ, FALSE, error);
300 #ifdef lint
301     error = error;
302 #endif
303 }
304 
305 struct mbuf *rdpdebuf;
306 #ifdef RDPDEBUG
307 int rdprint;
308 #endif
309 
310 /*
311  * Write a record in the rdp debugging log
312  */
313 rdp_debug(rdpcb, arg, input, newstate)
314 register RDPCB *rdpcb;
315 rdpstate newstate;
316 {
317     register struct r_debug *dp;
318     register struct mbuf *m;
319 
320 #ifdef RDPDEBUG
321     if (rdprint)
322     {
323 	/*
324 	 * Print debugging info directly on the console (use this for
325 	 * intial testing only).
326 	 */
327 	printf("RDP(0x%x) %s X %s", rdpcb, rdpstates[rdpcb->r_state],
328 	    (input < 0 ? "send pkt" : rdpinputs[input]) );
329 
330 	if (input == RDP_iTIMER)
331 	    printf("(%s)", rdptimers[arg]);
332 
333 	printf(" --> %s\n",
334 	    rdpstates[newstate==RDP_sSAME ? rdpcb->r_state : newstate];
335     }
336 #endif
337 
338     /*
339      * Get an mbuf to write the debugging record into.  If we don't already
340      * have one, allocate a new one.
341      */
342     if ((m = rdpdebuf) == NULL)
343     {
344 	register struct mbuf *c;
345 
346 	if ((rdpdebuf = m = m_get(M_DONTWAIT, MT_DATA)) == NULL)
347 	    return;
348 	/*
349 	 * If possible, use a cluster so that we need to wake up the
350 	 * raw listener less often and reduce likelihood he misses
351 	 * some information.
352 	 */
353 	MCLGET(c, 1);
354 	if (c)
355 	{
356 	    m->m_off = ((int) c) - ((int) m);
357 	    m->m_act = (struct mbuf *) RCDBLEN;
358 	}
359 	else
360 	m->m_act = (struct mbuf *) RDBLEN;
361 	m->m_len = 0;
362     }
363 
364     dp = (R_DEBUG *) (mtod(m, char *) + m->m_len);
365     /*
366      * Set up the debugging record.
367      */
368     dp->rd_iptime	= iptime();
369     dp->rd_input	= input;
370     dp->rd_newstate	= newstate;
371     dp->rd_rdpcb	= (*rdpcb);	/* structure copy */
372 
373     /*
374      * input == RDP_iNETR           incoming packet
375      *       == -1                  monitor outgoing packet.  Not a true
376      *                              transition CAUSING event, but useful.
377      */
378     if ((input == RDP_iNETR) || (input < 0))
379     {
380 	register struct ip *ip;
381 	register RDPHDR *pkt;
382 
383 	ip = (struct ip *) arg;
384 	pkt = (RDPHDR *) (ip + 1);
385 	dp->rd_iphdr	= (*ip);	/* structure copy */
386 	dp->rd_rdphdr	= (*pkt);	/* structure copy */
387     }
388     else if (input == RDP_iTIMER)
389 	dp->rd_timer	= arg;
390 
391     /*
392      * If the mbuf is full, dispatch it to a raw listener.
393      * Also for transition to closed state so oberver sees all and
394      * can debug stuff more easily.
395      */
396     m->m_len += sizeof(struct r_debug);
397     if ((m->m_len >= ((int) m->m_act)) || (newstate == RDP_sCLOSED))
398     {
399 	m->m_act = 0;
400 	rdpdebuglog(m);
401 	rdpdebuf = NULL;
402     }
403 }
404 #endif
405