125202Skarels /*
225202Skarels  $Log:	rdp_input.c,v $
325202Skarels  * Revision 2.10  85/06/18  14:37:38  walsh
425202Skarels  * check for version mismatch.
525202Skarels  *
625202Skarels  * Revision 2.9  85/04/08  14:35:11  root
725202Skarels  * *** empty log message ***
825202Skarels  *
925202Skarels  * Revision 2.8  85/02/26  08:26:48  walsh
1025202Skarels  * First pass at using IP source routing information to establish connections
1125202Skarels  * (possibly with hosts not known by the Internet gateways.)  The hooks with
1225202Skarels  * TCP could be better done - particularly dealing with IP addresses in the
1325202Skarels  * header for checksums and tcpdb lookups.
1425202Skarels  *
1525202Skarels  * Revision 2.7  84/11/15  09:55:52  walsh
1625202Skarels  * redid how we deal with compiler padding in the RDP header structure.
1725202Skarels  *
1825202Skarels  * Revision 2.6  84/11/08  16:11:17  walsh
1925202Skarels  * Added code to gather statistics on RDP traffic.  This makes the RDPCB
2025202Skarels  * too big unles you make mbufs 512 bytes large.  RDP_CS should be turned off
2125202Skarels  * unless you do.
2225202Skarels  *
2325202Skarels  * Revision 2.5  84/11/06  14:30:09  walsh
2425202Skarels  * intorduced RDP_HLSHIFT
2525202Skarels  *
2625202Skarels  * Revision 2.4  84/11/05  16:33:07  walsh
2725202Skarels  * fix coding error.
2825202Skarels  *
2925202Skarels  * Revision 2.3  84/11/05  10:51:53  walsh
3025202Skarels  * flush debugging log if new state is RDP_sCLOSED so that packet printer/
3125202Skarels  * system analyst sees final transitions.
3225202Skarels  *
3325202Skarels  * Revision 2.2  84/11/02  15:28:19  walsh
3425202Skarels  * Allow for RDP header fields not on natural boundries.  (Protocol
3525202Skarels  * specifiers say will be part of next version in 6-12 months).
3625202Skarels  * Until then, there goes the speed...  Yucho modifications.
3725202Skarels  *
3825202Skarels  * Revision 2.1  84/11/02  10:12:58  walsh
3925202Skarels  * Fixed to include RCS comments in checked out source.
4025202Skarels  *
4125202Skarels  *
4225202Skarels  * description:
4325202Skarels  * Packet input processing for Reliable Datagram Protocol.
4425202Skarels  *
4525202Skarels  * revision 1.6
4625202Skarels  * date: 84/07/19 10:21:22;  author: walsh;  state: Exp;  lines added/del: 2/1
4725202Skarels  * Organized macros and classified their definitions in rdp_macros.h.
4825202Skarels  *
4925202Skarels  * revision 1.5
5025202Skarels  * date: 84/07/10 09:59:38;  author: walsh;  state: Exp;  lines added/del: 10/10
5125202Skarels  * declared some register variables.
5225202Skarels  *
5325202Skarels  * revision 1.4
5425202Skarels  * date: 84/07/06 14:43:19;  author: wjacobso;  state: Exp;  lines added/del: 2/2
5525202Skarels  * *** empty log message ***
5625202Skarels  *
5725202Skarels  * revision 1.3
5825202Skarels  * date: 84/07/06 13:50:26;  author: wjacobso;  state: Exp;  lines added/del: 6/3
5925202Skarels  * use RDP_ACTION macro instead of rdp_action
6025202Skarels  *
6125202Skarels  * revision 1.2
6225202Skarels  * date: 84/07/06 09:49:20;  author: root;  state: Exp;  lines added/del: 27/45
6325202Skarels  * This version seems to run bug-free.
6425202Skarels  *
6525202Skarels  * revision 1.1
6625202Skarels  * date: 84/06/26 14:17:19;  author: walsh;  state: Exp;
6725202Skarels  * Initial revision
6825202Skarels  */
6925202Skarels 
7025202Skarels 
7125202Skarels #ifdef RDP
7225202Skarels #ifdef	RCSIDENT
7325202Skarels static char rcsident[] = "$Header: rdp_input.c,v 2.10 85/06/18 14:37:38 walsh Exp $";
7425202Skarels #endif
7525202Skarels 
7625202Skarels #include "../h/param.h"
7725202Skarels #include "../h/dir.h"
7825202Skarels #include "../h/user.h"
7925202Skarels #include "../h/kernel.h"
8025202Skarels #include "../h/inode.h"
8125202Skarels #include "../h/mbuf.h"
8225202Skarels #include "../h/socket.h"
8325202Skarels #include "../h/socketvar.h"
8425202Skarels #include "../h/syslog.h"
8525202Skarels 
8625202Skarels #include "../net/if.h"
8725202Skarels #include "../net/route.h"
8825202Skarels 
8925202Skarels #include "../bbnnet/in.h"
9025202Skarels #include "../bbnnet/in_var.h"
9125202Skarels #include "../bbnnet/net.h"
9225202Skarels #include "../bbnnet/in_pcb.h"
9325202Skarels #include "../bbnnet/ip.h"
9425202Skarels #include "../bbnnet/nopcb.h"
9525202Skarels #include "../bbnnet/rdp.h"
9625202Skarels #include "../bbnnet/rdp_macros.h"
9725202Skarels #ifdef	HMP
9825202Skarels #include "../bbnnet/hmp_traps.h"
9925202Skarels #endif
10025202Skarels 
10125202Skarels extern int nosum;
10225202Skarels 
10325202Skarels /*
10425202Skarels  * this is called from ip_input() upon reception of an RDP packet.
10525202Skarels  */
rdp_input(mp)10625202Skarels rdp_input(mp)
10725202Skarels register struct mbuf *mp;
10825202Skarels {
10925202Skarels     register RDPHDR		*pkt;
11025202Skarels     register struct ip	*ip;
11125202Skarels     rdpchecksum pktcksum;
11225202Skarels     rdpchecksum cksum;
11325202Skarels     register int hlen;
11425202Skarels     register struct inpcb *inp;
11525202Skarels 
11625202Skarels     rdpstat.r_total++;
11725202Skarels 
11825202Skarels     /*
11925202Skarels      * see ip_input().  Get access to constant part of RDP header.
12025202Skarels      */
12125202Skarels #define SZ (RDPHDRSZ + sizeof(struct ip))
12225202Skarels     if ((mp->m_off > MMAXOFF) || (mp->m_len < SZ))
12325202Skarels     {
12425202Skarels 	if ((mp = m_pullup(mp, SZ)) == NULL)
12525202Skarels 	{
12625202Skarels 	    rdpstat.r_tooshort ++;
12725202Skarels 	    return;
12825202Skarels 	}
12925202Skarels     }
13025202Skarels #undef SZ
13125202Skarels 
13225202Skarels     ip	= mtod(mp, struct ip *);
13325202Skarels     pkt	= (RDPHDR *) (ip + 1);
13425202Skarels 
13525202Skarels     /* make sure header, incl. option region, does not overflow mbuf */
13625202Skarels 
13725202Skarels     hlen = hdrlen(pkt) + sizeof(struct ip);
13825202Skarels     if (hlen > mp->m_len)
13925202Skarels     {
14025202Skarels 	if ((mp = m_pullup(mp, hlen)) == NULL)
14125202Skarels 	{
14225202Skarels 	    ip_log(ip, "rdp header overflow");
14325202Skarels #ifdef HMPTRAPS
14425202Skarels 	    /* hmp_trap(T_TCP_OVFLO, (caddr_t)0,0); */
14525202Skarels #else
14625202Skarels 	    /* netlog(mp); */
14725202Skarels #endif
14825202Skarels 	    return;
14925202Skarels 	}
15025202Skarels 	ip = mtod(mp, struct ip *);
15125202Skarels 	pkt = (RDPHDR *) (ip + 1);
15225202Skarels     }
15325202Skarels 
15425202Skarels     if (pkt->rh_ver != RDP_VERSION)
15525202Skarels     {
15625202Skarels 	ip_log (ip, "rdp version mismatch");
15725202Skarels 	netlog (mp);
15825202Skarels 	return;
15925202Skarels     }
16025202Skarels 
16125202Skarels     /*
16225202Skarels      * do checksum calculation, drop packet if bad
16325202Skarels      * Checksum must be done on header in net form due to byte ordering
16425202Skarels      * and rotations.
16525202Skarels      */
16625202Skarels 
16725202Skarels     pktcksum = RDP_CKSUM(pkt);
16825202Skarels     RDP_CKSUM(pkt) = 0;
16925202Skarels     cksum = rdp_cksum(mp);
17025202Skarels     if (cksum != pktcksum)
17125202Skarels     {
17225202Skarels 	rdpstat.r_badsum++;
17325202Skarels 	if (! nosum)
17425202Skarels 	{
17525202Skarels 	    inet_cksum_err ("rdp", ip, (u_long) pktcksum, (u_long) cksum);
17625202Skarels 	    netlog(mp);
17725202Skarels 	    return;
17825202Skarels 	}
17925202Skarels     }
18025202Skarels 
18125202Skarels     /* byte swap header */
18225202Skarels 
18325202Skarels     pkt->rh_dlen  = ntohs(pkt->rh_dlen);
18425202Skarels     RDP_SEQNO(pkt) = ntohl(RDP_SEQNO(pkt));
18525202Skarels     RDP_ACKNO(pkt) = ntohl(RDP_ACKNO(pkt));
18625202Skarels 
18725202Skarels     if (ip->ip_len != hdrlen(pkt) + pkt->rh_dlen)
18825202Skarels     {
18925202Skarels 	ip_log(ip, "rdp length error");
190*25208Skarels 	log(LOG_INFO, "%d + %d != %d\n", hdrlen(pkt), pkt->rh_dlen,
19125202Skarels 	    ip->ip_len);
19225202Skarels 	netlog(mp);
19325202Skarels 	return;
19425202Skarels     }
19525202Skarels 
19625202Skarels     inp = in_pcblookup(&rdp, ip->ip_src.s_addr, (u_short)pkt->rh_sport,
19725202Skarels 			     ip->ip_dst.s_addr, (u_short)pkt->rh_dport, TRUE);
19825202Skarels     if (inp == NULL)
19925202Skarels     {
20025202Skarels 	/* nobody wants it */
20125202Skarels 	rdpstat.r_drops ++;
20225202Skarels 	rdp_uncon_rst (pkt);
20325202Skarels     }
20425202Skarels     else
20525202Skarels     {
20625202Skarels 	register rdpstate newstate;
20725202Skarels 	register RDPCB	*rdpcb;
20825202Skarels 
20925202Skarels 	rdpcb = (RDPCB *)inp->inp_ppcb;
21025202Skarels 
21125202Skarels #ifdef RDP_CS
21225202Skarels 	rdpcb->r_rcvd.r_total ++;
21325202Skarels 	if (pkt->rh_flags & (RDP_fNULL|RDP_fRST|RDP_fSYN))
21425202Skarels 	{
21525202Skarels 	    if (pkt->rh_flags & RDP_fNULL)
21625202Skarels 		rdpcb->r_rcvd.r_nullpkts ++;
21725202Skarels 	    if (pkt->rh_flags & RDP_fRST)
21825202Skarels 		rdpcb->r_rcvd.r_rstpkts ++;
21925202Skarels 	    if (pkt->rh_flags & RDP_fSYN)
22025202Skarels 		rdpcb->r_rcvd.r_synpkts ++;
22125202Skarels 	}
22225202Skarels #endif
22325202Skarels 	/* found a protocol control block for the message */
22425202Skarels 	RDP_ACTION(RDP_iNETR, rdpcb, ((int) pkt), newstate);
22525202Skarels     }
22625202Skarels }
22725202Skarels 
22825202Skarels 
22925202Skarels /*
23025202Skarels  * Call a subroutine specifically tailored to deal with this state
23125202Skarels  * transition.
23225202Skarels  */
rdpaction(input,rdpcb,arg)23325202Skarels rdpaction (input, rdpcb, arg)
23425202Skarels register RDPCB	*rdpcb;
23525202Skarels {
23625202Skarels     register rdpstate newstate;
23725202Skarels 
23825202Skarels     RDP_ACTION (input, rdpcb, arg, newstate)
23925202Skarels }
24025202Skarels 
rdp_uncon_rst(pkt)24125202Skarels rdp_uncon_rst (pkt)
24225202Skarels register RDPHDR	*pkt;
24325202Skarels {
24425202Skarels     register struct ip *ip;
24525202Skarels     register struct mbuf *mp;
24625202Skarels     struct in_addr tempinaddr;
24725202Skarels     rdpportnum tempport;
24825202Skarels     long his_seqno;
24925202Skarels     int error;
25025202Skarels 
25125202Skarels     mp = dtom(pkt);
25225202Skarels 
25325202Skarels     /* make sure we don't send a RST in response to an RST */
25425202Skarels 
25525202Skarels     if (pkt->rh_flags & RDP_fRST)
25625202Skarels     {
25725202Skarels 	m_freem(mp);
25825202Skarels 	return;
25925202Skarels     }
26025202Skarels     ip = (struct ip *) (((caddr_t) pkt) - sizeof(struct ip));
26125202Skarels 
26225202Skarels     /* free everything but the header */
26325202Skarels 
26425202Skarels     m_freem(mp->m_next);
26525202Skarels     mp->m_next = NULL;
26625202Skarels     mp->m_len = sizeof(struct ip) + RDPHDRSZ;
26725202Skarels 
26825202Skarels     /* direct the packet back to the originator */
26925202Skarels 
27025202Skarels     tempinaddr = ip->ip_dst;
27125202Skarels     ip->ip_dst = ip->ip_src;
27225202Skarels     ip->ip_src = tempinaddr;
27325202Skarels 
27425202Skarels     tempport = pkt->rh_sport;
27525202Skarels     pkt->rh_sport = pkt->rh_dport;
27625202Skarels     pkt->rh_dport = tempport;
27725202Skarels 
27825202Skarels     /*
27925202Skarels      * and initialize (seqno, ackno, flags) so that it's "in window"
28025202Skarels      * and resets him independent of his state (is acceptable to all
28125202Skarels      * net reception subroutines.)
28225202Skarels      */
28325202Skarels     his_seqno = RDP_SEQNO(pkt);
28425202Skarels     RDP_SEQNO(pkt) = htonl(RDP_ACKNO(pkt) + 1);
28525202Skarels     RDP_ACKNO(pkt) = htonl(his_seqno);
28625202Skarels     if (pkt->rh_flags & RDP_fSYN)
28725202Skarels 	pkt->rh_flags = RDP_fRST|RDP_fACK;
28825202Skarels     else
28925202Skarels 	pkt->rh_flags = RDP_fRST;
29025202Skarels 
29125202Skarels     /* and send it */
29225202Skarels 
29325202Skarels     pkt->rh_hdrlen	= RDPHDRSZ >> RDP_HLSHIFT;
29425202Skarels     pkt->rh_dlen	= 0;
29525202Skarels     RDP_CKSUM(pkt)	= 0;
29625202Skarels 
29725202Skarels     RDP_CKSUM(pkt)	= rdp_cksum(mp);
29825202Skarels 
29925202Skarels     NOPCB_IPSEND (mp, RDPHDRSZ, FALSE, error);
30025202Skarels #ifdef lint
30125202Skarels     error = error;
30225202Skarels #endif
30325202Skarels }
30425202Skarels 
30525202Skarels struct mbuf *rdpdebuf;
30625202Skarels #ifdef RDPDEBUG
30725202Skarels int rdprint;
30825202Skarels #endif
30925202Skarels 
31025202Skarels /*
31125202Skarels  * Write a record in the rdp debugging log
31225202Skarels  */
rdp_debug(rdpcb,arg,input,newstate)31325202Skarels rdp_debug(rdpcb, arg, input, newstate)
31425202Skarels register RDPCB *rdpcb;
31525202Skarels rdpstate newstate;
31625202Skarels {
31725202Skarels     register struct r_debug *dp;
31825202Skarels     register struct mbuf *m;
31925202Skarels 
32025202Skarels #ifdef RDPDEBUG
32125202Skarels     if (rdprint)
32225202Skarels     {
32325202Skarels 	/*
32425202Skarels 	 * Print debugging info directly on the console (use this for
32525202Skarels 	 * intial testing only).
32625202Skarels 	 */
32725202Skarels 	printf("RDP(0x%x) %s X %s", rdpcb, rdpstates[rdpcb->r_state],
32825202Skarels 	    (input < 0 ? "send pkt" : rdpinputs[input]) );
32925202Skarels 
33025202Skarels 	if (input == RDP_iTIMER)
33125202Skarels 	    printf("(%s)", rdptimers[arg]);
33225202Skarels 
33325202Skarels 	printf(" --> %s\n",
33425202Skarels 	    rdpstates[newstate==RDP_sSAME ? rdpcb->r_state : newstate];
33525202Skarels     }
33625202Skarels #endif
33725202Skarels 
33825202Skarels     /*
33925202Skarels      * Get an mbuf to write the debugging record into.  If we don't already
34025202Skarels      * have one, allocate a new one.
34125202Skarels      */
34225202Skarels     if ((m = rdpdebuf) == NULL)
34325202Skarels     {
34425202Skarels 	register struct mbuf *c;
34525202Skarels 
34625202Skarels 	if ((rdpdebuf = m = m_get(M_DONTWAIT, MT_DATA)) == NULL)
34725202Skarels 	    return;
34825202Skarels 	/*
34925202Skarels 	 * If possible, use a cluster so that we need to wake up the
35025202Skarels 	 * raw listener less often and reduce likelihood he misses
35125202Skarels 	 * some information.
35225202Skarels 	 */
35325202Skarels 	MCLGET(c, 1);
35425202Skarels 	if (c)
35525202Skarels 	{
35625202Skarels 	    m->m_off = ((int) c) - ((int) m);
35725202Skarels 	    m->m_act = (struct mbuf *) RCDBLEN;
35825202Skarels 	}
35925202Skarels 	else
36025202Skarels 	m->m_act = (struct mbuf *) RDBLEN;
36125202Skarels 	m->m_len = 0;
36225202Skarels     }
36325202Skarels 
36425202Skarels     dp = (R_DEBUG *) (mtod(m, char *) + m->m_len);
36525202Skarels     /*
36625202Skarels      * Set up the debugging record.
36725202Skarels      */
36825202Skarels     dp->rd_iptime	= iptime();
36925202Skarels     dp->rd_input	= input;
37025202Skarels     dp->rd_newstate	= newstate;
37125202Skarels     dp->rd_rdpcb	= (*rdpcb);	/* structure copy */
37225202Skarels 
37325202Skarels     /*
37425202Skarels      * input == RDP_iNETR           incoming packet
37525202Skarels      *       == -1                  monitor outgoing packet.  Not a true
37625202Skarels      *                              transition CAUSING event, but useful.
37725202Skarels      */
37825202Skarels     if ((input == RDP_iNETR) || (input < 0))
37925202Skarels     {
38025202Skarels 	register struct ip *ip;
38125202Skarels 	register RDPHDR *pkt;
38225202Skarels 
38325202Skarels 	ip = (struct ip *) arg;
38425202Skarels 	pkt = (RDPHDR *) (ip + 1);
38525202Skarels 	dp->rd_iphdr	= (*ip);	/* structure copy */
38625202Skarels 	dp->rd_rdphdr	= (*pkt);	/* structure copy */
38725202Skarels     }
38825202Skarels     else if (input == RDP_iTIMER)
38925202Skarels 	dp->rd_timer	= arg;
39025202Skarels 
39125202Skarels     /*
39225202Skarels      * If the mbuf is full, dispatch it to a raw listener.
39325202Skarels      * Also for transition to closed state so oberver sees all and
39425202Skarels      * can debug stuff more easily.
39525202Skarels      */
39625202Skarels     m->m_len += sizeof(struct r_debug);
39725202Skarels     if ((m->m_len >= ((int) m->m_act)) || (newstate == RDP_sCLOSED))
39825202Skarels     {
39925202Skarels 	m->m_act = 0;
40025202Skarels 	rdpdebuglog(m);
40125202Skarels 	rdpdebuf = NULL;
40225202Skarels     }
40325202Skarels }
40425202Skarels #endif
405