from BBN
[unix-history] / usr / src / sys / deprecated / bbnnet / rdp_input.c
/*
$Log: rdp_input.c,v $
* Revision 2.10 85/06/18 14:37:38 walsh
* check for version mismatch.
*
* Revision 2.9 85/04/08 14:35:11 root
* *** empty log message ***
*
* Revision 2.8 85/02/26 08:26:48 walsh
* First pass at using IP source routing information to establish connections
* (possibly with hosts not known by the Internet gateways.) The hooks with
* TCP could be better done - particularly dealing with IP addresses in the
* header for checksums and tcpdb lookups.
*
* Revision 2.7 84/11/15 09:55:52 walsh
* redid how we deal with compiler padding in the RDP header structure.
*
* Revision 2.6 84/11/08 16:11:17 walsh
* Added code to gather statistics on RDP traffic. This makes the RDPCB
* too big unles you make mbufs 512 bytes large. RDP_CS should be turned off
* unless you do.
*
* Revision 2.5 84/11/06 14:30:09 walsh
* intorduced RDP_HLSHIFT
*
* Revision 2.4 84/11/05 16:33:07 walsh
* fix coding error.
*
* Revision 2.3 84/11/05 10:51:53 walsh
* flush debugging log if new state is RDP_sCLOSED so that packet printer/
* system analyst sees final transitions.
*
* Revision 2.2 84/11/02 15:28:19 walsh
* Allow for RDP header fields not on natural boundries. (Protocol
* specifiers say will be part of next version in 6-12 months).
* Until then, there goes the speed... Yucho modifications.
*
* Revision 2.1 84/11/02 10:12:58 walsh
* Fixed to include RCS comments in checked out source.
*
*
* description:
* Packet input processing for Reliable Datagram Protocol.
*
* revision 1.6
* date: 84/07/19 10:21:22; author: walsh; state: Exp; lines added/del: 2/1
* Organized macros and classified their definitions in rdp_macros.h.
*
* revision 1.5
* date: 84/07/10 09:59:38; author: walsh; state: Exp; lines added/del: 10/10
* declared some register variables.
*
* revision 1.4
* date: 84/07/06 14:43:19; author: wjacobso; state: Exp; lines added/del: 2/2
* *** empty log message ***
*
* revision 1.3
* date: 84/07/06 13:50:26; author: wjacobso; state: Exp; lines added/del: 6/3
* use RDP_ACTION macro instead of rdp_action
*
* revision 1.2
* date: 84/07/06 09:49:20; author: root; state: Exp; lines added/del: 27/45
* This version seems to run bug-free.
*
* revision 1.1
* date: 84/06/26 14:17:19; author: walsh; state: Exp;
* Initial revision
*/
#ifdef RDP
#ifdef RCSIDENT
static char rcsident[] = "$Header: rdp_input.c,v 2.10 85/06/18 14:37:38 walsh Exp $";
#endif
#include "../h/param.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/kernel.h"
#include "../h/inode.h"
#include "../h/mbuf.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/syslog.h"
#include "../net/if.h"
#include "../net/route.h"
#include "../bbnnet/in.h"
#include "../bbnnet/in_var.h"
#include "../bbnnet/net.h"
#include "../bbnnet/in_pcb.h"
#include "../bbnnet/ip.h"
#include "../bbnnet/nopcb.h"
#include "../bbnnet/rdp.h"
#include "../bbnnet/rdp_macros.h"
#ifdef HMP
#include "../bbnnet/hmp_traps.h"
#endif
extern int nosum;
/*
* this is called from ip_input() upon reception of an RDP packet.
*/
rdp_input(mp)
register struct mbuf *mp;
{
register RDPHDR *pkt;
register struct ip *ip;
rdpchecksum pktcksum;
rdpchecksum cksum;
register int hlen;
register struct inpcb *inp;
rdpstat.r_total++;
/*
* see ip_input(). Get access to constant part of RDP header.
*/
#define SZ (RDPHDRSZ + sizeof(struct ip))
if ((mp->m_off > MMAXOFF) || (mp->m_len < SZ))
{
if ((mp = m_pullup(mp, SZ)) == NULL)
{
rdpstat.r_tooshort ++;
return;
}
}
#undef SZ
ip = mtod(mp, struct ip *);
pkt = (RDPHDR *) (ip + 1);
/* make sure header, incl. option region, does not overflow mbuf */
hlen = hdrlen(pkt) + sizeof(struct ip);
if (hlen > mp->m_len)
{
if ((mp = m_pullup(mp, hlen)) == NULL)
{
ip_log(ip, "rdp header overflow");
#ifdef HMPTRAPS
/* hmp_trap(T_TCP_OVFLO, (caddr_t)0,0); */
#else
/* netlog(mp); */
#endif
return;
}
ip = mtod(mp, struct ip *);
pkt = (RDPHDR *) (ip + 1);
}
if (pkt->rh_ver != RDP_VERSION)
{
ip_log (ip, "rdp version mismatch");
netlog (mp);
return;
}
/*
* do checksum calculation, drop packet if bad
* Checksum must be done on header in net form due to byte ordering
* and rotations.
*/
pktcksum = RDP_CKSUM(pkt);
RDP_CKSUM(pkt) = 0;
cksum = rdp_cksum(mp);
if (cksum != pktcksum)
{
rdpstat.r_badsum++;
if (! nosum)
{
inet_cksum_err ("rdp", ip, (u_long) pktcksum, (u_long) cksum);
netlog(mp);
return;
}
}
/* byte swap header */
pkt->rh_dlen = ntohs(pkt->rh_dlen);
RDP_SEQNO(pkt) = ntohl(RDP_SEQNO(pkt));
RDP_ACKNO(pkt) = ntohl(RDP_ACKNO(pkt));
if (ip->ip_len != hdrlen(pkt) + pkt->rh_dlen)
{
ip_log(ip, "rdp length error");
log(KERN_RECOV, "%d + %d != %d\n", hdrlen(pkt), pkt->rh_dlen,
ip->ip_len);
netlog(mp);
return;
}
inp = in_pcblookup(&rdp, ip->ip_src.s_addr, (u_short)pkt->rh_sport,
ip->ip_dst.s_addr, (u_short)pkt->rh_dport, TRUE);
if (inp == NULL)
{
/* nobody wants it */
rdpstat.r_drops ++;
rdp_uncon_rst (pkt);
}
else
{
register rdpstate newstate;
register RDPCB *rdpcb;
rdpcb = (RDPCB *)inp->inp_ppcb;
#ifdef RDP_CS
rdpcb->r_rcvd.r_total ++;
if (pkt->rh_flags & (RDP_fNULL|RDP_fRST|RDP_fSYN))
{
if (pkt->rh_flags & RDP_fNULL)
rdpcb->r_rcvd.r_nullpkts ++;
if (pkt->rh_flags & RDP_fRST)
rdpcb->r_rcvd.r_rstpkts ++;
if (pkt->rh_flags & RDP_fSYN)
rdpcb->r_rcvd.r_synpkts ++;
}
#endif
/* found a protocol control block for the message */
RDP_ACTION(RDP_iNETR, rdpcb, ((int) pkt), newstate);
}
}
/*
* Call a subroutine specifically tailored to deal with this state
* transition.
*/
rdpaction (input, rdpcb, arg)
register RDPCB *rdpcb;
{
register rdpstate newstate;
RDP_ACTION (input, rdpcb, arg, newstate)
}
rdp_uncon_rst (pkt)
register RDPHDR *pkt;
{
register struct ip *ip;
register struct mbuf *mp;
struct in_addr tempinaddr;
rdpportnum tempport;
long his_seqno;
int error;
mp = dtom(pkt);
/* make sure we don't send a RST in response to an RST */
if (pkt->rh_flags & RDP_fRST)
{
m_freem(mp);
return;
}
ip = (struct ip *) (((caddr_t) pkt) - sizeof(struct ip));
/* free everything but the header */
m_freem(mp->m_next);
mp->m_next = NULL;
mp->m_len = sizeof(struct ip) + RDPHDRSZ;
/* direct the packet back to the originator */
tempinaddr = ip->ip_dst;
ip->ip_dst = ip->ip_src;
ip->ip_src = tempinaddr;
tempport = pkt->rh_sport;
pkt->rh_sport = pkt->rh_dport;
pkt->rh_dport = tempport;
/*
* and initialize (seqno, ackno, flags) so that it's "in window"
* and resets him independent of his state (is acceptable to all
* net reception subroutines.)
*/
his_seqno = RDP_SEQNO(pkt);
RDP_SEQNO(pkt) = htonl(RDP_ACKNO(pkt) + 1);
RDP_ACKNO(pkt) = htonl(his_seqno);
if (pkt->rh_flags & RDP_fSYN)
pkt->rh_flags = RDP_fRST|RDP_fACK;
else
pkt->rh_flags = RDP_fRST;
/* and send it */
pkt->rh_hdrlen = RDPHDRSZ >> RDP_HLSHIFT;
pkt->rh_dlen = 0;
RDP_CKSUM(pkt) = 0;
RDP_CKSUM(pkt) = rdp_cksum(mp);
NOPCB_IPSEND (mp, RDPHDRSZ, FALSE, error);
#ifdef lint
error = error;
#endif
}
struct mbuf *rdpdebuf;
#ifdef RDPDEBUG
int rdprint;
#endif
/*
* Write a record in the rdp debugging log
*/
rdp_debug(rdpcb, arg, input, newstate)
register RDPCB *rdpcb;
rdpstate newstate;
{
register struct r_debug *dp;
register struct mbuf *m;
#ifdef RDPDEBUG
if (rdprint)
{
/*
* Print debugging info directly on the console (use this for
* intial testing only).
*/
printf("RDP(0x%x) %s X %s", rdpcb, rdpstates[rdpcb->r_state],
(input < 0 ? "send pkt" : rdpinputs[input]) );
if (input == RDP_iTIMER)
printf("(%s)", rdptimers[arg]);
printf(" --> %s\n",
rdpstates[newstate==RDP_sSAME ? rdpcb->r_state : newstate];
}
#endif
/*
* Get an mbuf to write the debugging record into. If we don't already
* have one, allocate a new one.
*/
if ((m = rdpdebuf) == NULL)
{
register struct mbuf *c;
if ((rdpdebuf = m = m_get(M_DONTWAIT, MT_DATA)) == NULL)
return;
/*
* If possible, use a cluster so that we need to wake up the
* raw listener less often and reduce likelihood he misses
* some information.
*/
MCLGET(c, 1);
if (c)
{
m->m_off = ((int) c) - ((int) m);
m->m_act = (struct mbuf *) RCDBLEN;
}
else
m->m_act = (struct mbuf *) RDBLEN;
m->m_len = 0;
}
dp = (R_DEBUG *) (mtod(m, char *) + m->m_len);
/*
* Set up the debugging record.
*/
dp->rd_iptime = iptime();
dp->rd_input = input;
dp->rd_newstate = newstate;
dp->rd_rdpcb = (*rdpcb); /* structure copy */
/*
* input == RDP_iNETR incoming packet
* == -1 monitor outgoing packet. Not a true
* transition CAUSING event, but useful.
*/
if ((input == RDP_iNETR) || (input < 0))
{
register struct ip *ip;
register RDPHDR *pkt;
ip = (struct ip *) arg;
pkt = (RDPHDR *) (ip + 1);
dp->rd_iphdr = (*ip); /* structure copy */
dp->rd_rdphdr = (*pkt); /* structure copy */
}
else if (input == RDP_iTIMER)
dp->rd_timer = arg;
/*
* If the mbuf is full, dispatch it to a raw listener.
* Also for transition to closed state so oberver sees all and
* can debug stuff more easily.
*/
m->m_len += sizeof(struct r_debug);
if ((m->m_len >= ((int) m->m_act)) || (newstate == RDP_sCLOSED))
{
m->m_act = 0;
rdpdebuglog(m);
rdpdebuf = NULL;
}
}
#endif