home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************/
- /* Copyright(c) 1987, 1992 by BBN Systems and Technologies, */
- /* A Division of Bolt Beranek and Newman Inc. */
- /* */
- /* RDP implementation for 4.2/4.3bsd by Craig Partridge */
- /* */
- /* Permission to use, copy, modify, distribute, and sell this software */
- /* and its documentation for any purpose is hereby granted without fee, */
- /* provided that the above copyright notice and this permission appear */
- /* in all copies and in supporting documentation, and that the name of */
- /* Bolt Beranek and Newman Inc. not be used in advertising or */
- /* publicity pertaining to distribution of the software without */
- /* specific, written prior permission. BBN makes no representations */
- /* about the suitability of this software for any purposes. It is */
- /* provided "AS IS" without express or implied warranties. */
- /**************************************************************************/
-
- #include "../h/param.h"
- #include "../h/dir.h"
- #include "../h/user.h"
- #include "../h/mbuf.h"
- #include "../h/protosw.h"
- #include "../h/socket.h"
- #include "../h/socketvar.h"
- #include "../h/errno.h"
-
- #include "../net/if.h"
- #include "../net/route.h"
-
- #include "../netinet/in.h"
- #include "../netinet/in_pcb.h"
- #include "../netinet/in_systm.h"
- #include "../netinet/ip.h"
- #include "../netinet/ip_var.h"
- #include "../netinet/ip_icmp.h"
-
- #include "../netinet/rdp.h"
- #include "../netinet/rdp_var.h"
- #include "../netinet/rdp_ip.h"
- #include "../netinet/rdp_conf.h"
-
- extern struct inpcb rdb;
- extern u_long rdpserial;
- extern u_short rdp_mtu;
- extern short rdp_start[];
-
- /**************************************************************************/
- /* called on PRU_ATTACH */
- /**************************************************************************/
-
- rdp_attach(so)
- struct socket *so;
- {
- int error=0;
- register struct inpcb *inp;
- register struct rdpcb *rp;
- register struct rdpque *rq;
- register struct mbuf *m;
-
- if ((error = soreserve(so,2048,(int)(R_RCVMAX*rdp_mtu*6)))!=0)
- goto quit;
-
- if ((error = in_pcballoc(so,&rdb)) != 0)
- goto quit;
-
- inp = sotoinpcb(so);
-
- /* now grab our pcb -- actually, are we willing to wait? */
- if ((m = m_getclr(M_WAIT,MT_PCB)) == 0)
- {
- error = ENOBUFS;
- goto quit;
- }
-
- rp = mtod(m,struct rdpcb *);
-
- /* now grab queues */
- if ((m = m_getclr(M_WAIT,MT_PCB)) == 0)
- {
- (void) m_free(dtom(rp));
- error = ENOBUFS;
- goto quit;
- }
-
- rq = mtod(m,struct rdpque *);
-
- rp->rp_rq = rq;
- rp->rp_state = R_CLOSED;
-
- inp->inp_ppcb = (caddr_t) rp;
- error = 0;
-
- quit:
- return(error);
- }
-
- /**************************************************************************/
- /* called on PRU_DETACH */
- /**************************************************************************/
-
- rdp_detach(so,inp)
- struct socket *so;
- struct inpcb *inp;
- {
- struct rdpcb *rp = (struct rdpcb *)inp->inp_ppcb;
- register int error = 0;
-
- switch (rp->rp_state)
- {
- case R_OPEN:
- /* I don't know why we are here */
- panic("rdp_detach: open");
- break;
-
- /* user closed in middle of attempt to connect */
- case R_SYN_SENT:
- case R_SYN_RCVD:
- /* hope we send */
- /* WRONG SEQ #?? */
- (void) rdp_rst(inp,0,(u_long)0,(u_long)0,1);
- rp->rp_state = R_CLOSED;
- /* fall thru */
-
- case R_LISTEN:
- case R_CLOSED:
- /* we can just detach in these states */
- (void) m_free(dtom(rp->rp_rq));
- (void) m_free(dtom(rp));
- inp->inp_ppcb = 0;
- so->so_snd.sb_cc = 0;
- soisdisconnected(so);
- in_pcbdetach(inp);
- break;
-
- case R_DRAIN:
- case R_CLOSE_WAIT:
- /* leave pcb in place -- clean up later.. */
- break;
- }
-
- return(error);
- }
-
- /**************************************************************************/
- /* called on PRU_CONNECT */
- /**************************************************************************/
-
- rdp_connect(inp,addr)
- struct inpcb *inp;
- struct mbuf *addr;
- {
- register struct rdpcb *rp = (struct rdpcb *)inp->inp_ppcb;
- register struct rdpque *rq = rp->rp_rq;
- int error;
-
- if (error = in_pcbconnect(inp,addr))
- return(error);
-
- rp->rp_sndhsa = rp->rp_sndnxt = rdpserial++;
- rp->rp_snduna = rp->rp_sndnxt;
-
- /* sndnxt == sndiss */
- if ((error = rdp_syn(inp,0,rp->rp_sndnxt,(u_long)0)) == 0)
- {
- soisconnecting(inp->inp_socket);
- rp->rp_state = R_SYN_SENT;
- rq->rq_sndtimer[0] = 0;
- rq->rq_retries[0] = 0;
- }
-
- return(error);
- }
-
- /**************************************************************************/
- /* called on PRU_DISCONNECT */
- /**************************************************************************/
-
- rdp_disconnect(inp)
- struct inpcb *inp;
- {
- register struct rdpcb *rp = (struct rdpcb *)inp->inp_ppcb;
- register struct rdpque *rq = rp->rp_rq;
- register struct socket *so = inp->inp_socket;
- int error = 0;
-
- switch (rp->rp_state)
- {
- case R_OPEN:
- /* did we read everything? */
- if (rdp_rclr(rp))
- {
- /* no, so clear send queue and get upset */
- (void) rdp_sclr(rp);
- error = ECONNABORTED;
- }
- else if (seq_lt(rp->rp_snduna,rp->rp_sndnxt))
- {
- /* we need to drain */
- rp->rp_state = R_DRAIN;
- rp->rp_timer = 0;
- soisdisconnecting(so);
- break;
- }
-
- /* no need to drain -- just close */
-
- soisdisconnected(so);
- rp->rp_state = R_CLOSE_WAIT;
- rp->rp_timer = RT_CLOTIME + (R_MAXTRIES * rp->rp_estrtt);
- rq->rq_retries[0] = 0;
- rq->rq_sndtimer[0] = 0;
- (void) rdp_rst(inp,0,rp->rp_sndnxt,(u_long)0,1);
- break;
-
- case R_SYN_RCVD:
- case R_SYN_SENT:
- (void) rdp_rst(inp,0,rp->rp_sndnxt,(u_long)0,1);
- rp->rp_state = R_CLOSED;
- rp->rp_timer = 0;
- soisdisconnected(so);
- (void) rdp_detach(so,inp);
- break;
-
- /* should not get here */
- case R_CLOSE_WAIT:
- case R_CLOSED:
- case R_LISTEN:
- case R_DRAIN:
- panic("rdp_disconnect");
- }
-
- return(error);
- }
-
- /**************************************************************************/
- /* CTLINPUT SUPPORT ROUTINES */
- /**************************************************************************/
-
- /**************************************************************************/
- /* fatal error on connection */
- /* this simply tears apart a connection because we believe the connection */
- /* is dead -- if you are doing a close from the user, use rdp_disconnect */
- /**************************************************************************/
-
- rdp_fatal(inp)
- struct inpcb *inp;
- {
- struct rdpcb *rp = (struct rdpcb *)inp->inp_ppcb;
- struct socket *so = inp->inp_socket;
-
- if (rp == 0)
- panic("rdp_fatal");
-
- soisdisconnected(so);
-
- switch (rp->rp_state)
- {
- case R_LISTEN:
- /* what??? */
- so->so_error = 0;
- return;
-
- case R_OPEN:
- case R_DRAIN:
- /* clear our queues */
- (void) rdp_clrq(rp);
- break;
-
- case R_CLOSED:
- /* maybe we were opening... */
- case R_CLOSE_WAIT:
- case R_SYN_SENT:
- case R_SYN_RCVD:
- break;
- }
-
- rp->rp_state = R_CLOSED;
- rp->rp_timer = 0;
-
- (void) rdp_detach(so,inp);
- }
-
-
- /**************************************************************************/
- /* source quench received */
- /**************************************************************************/
-
- rdp_quench(inp)
- struct inpcb *inp;
- {
- register struct rdpcb *rp = (struct rdpcb *)inp->inp_ppcb;
- register struct socket *so = inp->inp_socket;
-
- /* shrink our window size by ~30% */
- if ((rp->rp_maxinflt = ((rp->rp_inflt * 7)/10)) < 1)
- rp->rp_maxinflt = 1;
-
- /* block packets from socket layer */
- if (rp->rp_maxinflt <= rp->rp_inflt)
- so->so_snd.sb_cc = so->so_snd.sb_hiwat;
-
- /* wait until the current window clears out before opening window */
- rp->rp_qwait = rp->rp_inflt + 1;
- }
-
- /**************************************************************************/
- /* TIMERS */
- /**************************************************************************/
-
- /**************************************************************************/
- /* compute new round trip time, see rfc 889 for details */
- /* */
- /* profiling shows this is called often enough (and in few enough places) */
- /* that it might make sense to make it a macro. */
- /**************************************************************************/
-
- #define PRECISION 8
-
- rdp_newrtt(rttptr,sample)
- struct rdp_rtt *rttptr;
- short sample;
- {
- register u_long newrtt, srtt;
-
- newrtt = (sample * RT_G) << PRECISION;
- srtt = (rttptr->rp_rtt << PRECISION) + rttptr->rp_rttfrac;
-
- if (srtt > newrtt)
- srtt = ((srtt * 15) + newrtt) >> 4;
- else
- srtt = ((srtt * 3) + newrtt) >> 2;
-
- if (srtt < ((RT_RTMIN * RT_G) << PRECISION))
- srtt = (RT_RTMIN * RT_G) << PRECISION;
- else if (srtt > (RT_RTMAX << PRECISION))
- srtt = RT_RTMAX << PRECISION;
-
- rttptr->rp_rttfrac = srtt & 0xff;
- rttptr->rp_rtt = srtt >> PRECISION;
- }
-
- /**************************************************************************/
- /* QUEUE CLEANUP */
- /**************************************************************************/
-
- /**************************************************************************/
- /* clear the packet queues -- return 0 if no packets needed to be freed */
- /**************************************************************************/
-
- rdp_clrq(rp)
- struct rdpcb *rp;
- {
- if (rp==0)
- return(0);
-
- return(rdp_sclr(rp) + rdp_rclr(rp));
- }
-
- /**************************************************************************/
- /* just clear the send queue */
- /* use of pointers instead of indexes should speed this up, but not done */
- /* enough that I care.. */
- /**************************************************************************/
-
- rdp_sclr(rp)
- register struct rdpcb *rp;
- {
- register int i, count;
- register struct rdpque *rq = rp->rp_rq;
- int save;
-
- /* deal with the send queue */
-
- save = count = rp->rp_sndnxt - rp->rp_snduna;
- i = rq->rq_sndbase;
-
- for(; count > 0; count--)
- {
- rq->rq_sndtimer[i] = 0;
- if (rq->rq_sndq[i] != 0)
- (void) m_freem(rq->rq_sndq[i]);
- rq->rq_sndq[i] = 0;
-
- if (++i == R_RCVWIN)
- i = 0;
- }
-
- return(save);
- }
-
- /**************************************************************************/
- /* just clear the inbound queue */
- /**************************************************************************/
-
- rdp_rclr(rp)
- struct rdpcb *rp;
- {
- register int i, count;
- register struct rdpque *rq = rp->rp_rq;
- extern struct mbuf rdp_mark;
- int save;
-
- /* the inbound side -- look for unread packets */
-
- save = count = rp->rp_rcvhi - rp->rp_rcvcur;
- i = rq->rq_rcvbase;
-
- for(; count > 0; count--)
- {
- if (rq->rq_rcvq[i] != 0)
- {
- if (rq->rq_rcvq[i] != &rdp_mark)
- (void) m_freem(rq->rq_rcvq[i]);
-
- rq->rq_rcvq[i] = 0;
- }
-
- if (++i == R_RCVWIN)
- i = 0;
- }
-
- return(save);
- }
-