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