⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spp_usrreq.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1984, 1985, 1986, 1987, 1993 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)spp_usrreq.c	8.1 (Berkeley) 6/10/93 */#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/protosw.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/errno.h>#include <net/if.h>#include <net/route.h>#include <netinet/tcp_fsm.h>#include <netns/ns.h>#include <netns/ns_pcb.h>#include <netns/idp.h>#include <netns/idp_var.h>#include <netns/ns_error.h>#include <netns/sp.h>#include <netns/spidp.h>#include <netns/spp_timer.h>#include <netns/spp_var.h>#include <netns/spp_debug.h>/* * SP protocol implementation. */spp_init(){	spp_iss = 1; /* WRONG !! should fish it out of TODR */}struct spidp spp_savesi;int traceallspps = 0;extern int sppconsdebug;int spp_hardnosed;int spp_use_delack = 0;u_short spp_newchecks[50];/*ARGSUSED*/spp_input(m, nsp)	register struct mbuf *m;	register struct nspcb *nsp;{	register struct sppcb *cb;	register struct spidp *si = mtod(m, struct spidp *);	register struct socket *so;	short ostate;	int dropsocket = 0;	sppstat.spps_rcvtotal++;	if (nsp == 0) {		panic("No nspcb in spp_input\n");		return;	}	cb = nstosppcb(nsp);	if (cb == 0) goto bad;	if (m->m_len < sizeof(*si)) {		if ((m = m_pullup(m, sizeof(*si))) == 0) {			sppstat.spps_rcvshort++;			return;		}		si = mtod(m, struct spidp *);	}	si->si_seq = ntohs(si->si_seq);	si->si_ack = ntohs(si->si_ack);	si->si_alo = ntohs(si->si_alo);	so = nsp->nsp_socket;	if (so->so_options & SO_DEBUG || traceallspps) {		ostate = cb->s_state;		spp_savesi = *si;	}	if (so->so_options & SO_ACCEPTCONN) {		struct sppcb *ocb = cb;		so = sonewconn(so, 0);		if (so == 0) {			goto drop;		}		/*		 * This is ugly, but ....		 *		 * Mark socket as temporary until we're		 * committed to keeping it.  The code at		 * ``drop'' and ``dropwithreset'' check the		 * flag dropsocket to see if the temporary		 * socket created here should be discarded.		 * We mark the socket as discardable until		 * we're committed to it below in TCPS_LISTEN.		 */		dropsocket++;		nsp = (struct nspcb *)so->so_pcb;		nsp->nsp_laddr = si->si_dna;		cb = nstosppcb(nsp);		cb->s_mtu = ocb->s_mtu;		/* preserve sockopts */		cb->s_flags = ocb->s_flags;	/* preserve sockopts */		cb->s_flags2 = ocb->s_flags2;	/* preserve sockopts */		cb->s_state = TCPS_LISTEN;	}	/*	 * Packet received on connection.	 * reset idle time and keep-alive timer;	 */	cb->s_idle = 0;	cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;	switch (cb->s_state) {	case TCPS_LISTEN:{		struct mbuf *am;		register struct sockaddr_ns *sns;		struct ns_addr laddr;		/*		 * If somebody here was carying on a conversation		 * and went away, and his pen pal thinks he can		 * still talk, we get the misdirected packet.		 */		if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {			spp_istat.gonawy++;			goto dropwithreset;		}		am = m_get(M_DONTWAIT, MT_SONAME);		if (am == NULL)			goto drop;		am->m_len = sizeof (struct sockaddr_ns);		sns = mtod(am, struct sockaddr_ns *);		sns->sns_len = sizeof(*sns);		sns->sns_family = AF_NS;		sns->sns_addr = si->si_sna;		laddr = nsp->nsp_laddr;		if (ns_nullhost(laddr))			nsp->nsp_laddr = si->si_dna;		if (ns_pcbconnect(nsp, am)) {			nsp->nsp_laddr = laddr;			(void) m_free(am);			spp_istat.noconn++;			goto drop;		}		(void) m_free(am);		spp_template(cb);		dropsocket = 0;		/* committed to socket */		cb->s_did = si->si_sid;		cb->s_rack = si->si_ack;		cb->s_ralo = si->si_alo;#define THREEWAYSHAKE#ifdef THREEWAYSHAKE		cb->s_state = TCPS_SYN_RECEIVED;		cb->s_force = 1 + SPPT_KEEP;		sppstat.spps_accepts++;		cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;		}		break;	/*	 * This state means that we have heard a response	 * to our acceptance of their connection	 * It is probably logically unnecessary in this	 * implementation.	 */	 case TCPS_SYN_RECEIVED: {		if (si->si_did!=cb->s_sid) {			spp_istat.wrncon++;			goto drop;		}#endif		nsp->nsp_fport =  si->si_sport;		cb->s_timer[SPPT_REXMT] = 0;		cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;		soisconnected(so);		cb->s_state = TCPS_ESTABLISHED;		sppstat.spps_accepts++;		}		break;	/*	 * This state means that we have gotten a response	 * to our attempt to establish a connection.	 * We fill in the data from the other side,	 * telling us which port to respond to, instead of the well-	 * known one we might have sent to in the first place.	 * We also require that this is a response to our	 * connection id.	 */	case TCPS_SYN_SENT:		if (si->si_did!=cb->s_sid) {			spp_istat.notme++;			goto drop;		}		sppstat.spps_connects++;		cb->s_did = si->si_sid;		cb->s_rack = si->si_ack;		cb->s_ralo = si->si_alo;		cb->s_dport = nsp->nsp_fport =  si->si_sport;		cb->s_timer[SPPT_REXMT] = 0;		cb->s_flags |= SF_ACKNOW;		soisconnected(so);		cb->s_state = TCPS_ESTABLISHED;		/* Use roundtrip time of connection request for initial rtt */		if (cb->s_rtt) {			cb->s_srtt = cb->s_rtt << 3;			cb->s_rttvar = cb->s_rtt << 1;			SPPT_RANGESET(cb->s_rxtcur,			    ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,			    SPPTV_MIN, SPPTV_REXMTMAX);			    cb->s_rtt = 0;		}	}	if (so->so_options & SO_DEBUG || traceallspps)		spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0);	m->m_len -= sizeof (struct idp);	m->m_pkthdr.len -= sizeof (struct idp);	m->m_data += sizeof (struct idp);	if (spp_reass(cb, si)) {		(void) m_freem(m);	}	if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT)))		(void) spp_output(cb, (struct mbuf *)0);	cb->s_flags &= ~(SF_WIN|SF_RXT);	return;dropwithreset:	if (dropsocket)		(void) soabort(so);	si->si_seq = ntohs(si->si_seq);	si->si_ack = ntohs(si->si_ack);	si->si_alo = ntohs(si->si_alo);	ns_error(dtom(si), NS_ERR_NOSOCK, 0);	if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);	return;drop:bad:	if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG ||            traceallspps)		spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);	m_freem(m);}int spprexmtthresh = 3;/* * This is structurally similar to the tcp reassembly routine * but its function is somewhat different:  It merely queues * packets up, and suppresses duplicates. */spp_reass(cb, si)register struct sppcb *cb;register struct spidp *si;{	register struct spidp_q *q;	register struct mbuf *m;	register struct socket *so = cb->s_nspcb->nsp_socket;	char packetp = cb->s_flags & SF_HI;	int incr;	char wakeup = 0;	if (si == SI(0))		goto present;	/*	 * Update our news from them.	 */	if (si->si_cc & SP_SA)		cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_ACKNOW);	if (SSEQ_GT(si->si_alo, cb->s_ralo))		cb->s_flags |= SF_WIN;	if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {		if ((si->si_cc & SP_SP) && cb->s_rack != (cb->s_smax + 1)) {			sppstat.spps_rcvdupack++;			/*			 * If this is a completely duplicate ack			 * and other conditions hold, we assume			 * a packet has been dropped and retransmit			 * it exactly as in tcp_input().			 */			if (si->si_ack != cb->s_rack ||			    si->si_alo != cb->s_ralo)				cb->s_dupacks = 0;			else if (++cb->s_dupacks == spprexmtthresh) {				u_short onxt = cb->s_snxt;				int cwnd = cb->s_cwnd;				cb->s_snxt = si->si_ack;				cb->s_cwnd = CUNIT;				cb->s_force = 1 + SPPT_REXMT;				(void) spp_output(cb, (struct mbuf *)0);				cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;				cb->s_rtt = 0;				if (cwnd >= 4 * CUNIT)					cb->s_cwnd = cwnd / 2;				if (SSEQ_GT(onxt, cb->s_snxt))					cb->s_snxt = onxt;				return (1);			}		} else			cb->s_dupacks = 0;		goto update_window;	}	cb->s_dupacks = 0;	/*	 * If our correspondent acknowledges data we haven't sent	 * TCP would drop the packet after acking.  We'll be a little	 * more permissive	 */	if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {		sppstat.spps_rcvacktoomuch++;		si->si_ack = cb->s_smax + 1;	}	sppstat.spps_rcvackpack++;	/*	 * If transmit timer is running and timed sequence	 * number was acked, update smoothed round trip time.	 * See discussion of algorithm in tcp_input.c	 */	if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {		sppstat.spps_rttupdated++;		if (cb->s_srtt != 0) {			register short delta;			delta = cb->s_rtt - (cb->s_srtt >> 3);			if ((cb->s_srtt += delta) <= 0)				cb->s_srtt = 1;			if (delta < 0)				delta = -delta;			delta -= (cb->s_rttvar >> 2);			if ((cb->s_rttvar += delta) <= 0)				cb->s_rttvar = 1;		} else {			/*			 * No rtt measurement yet			 */			cb->s_srtt = cb->s_rtt << 3;			cb->s_rttvar = cb->s_rtt << 1;		}		cb->s_rtt = 0;		cb->s_rxtshift = 0;		SPPT_RANGESET(cb->s_rxtcur,			((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,			SPPTV_MIN, SPPTV_REXMTMAX);	}	/*	 * If all outstanding data is acked, stop retransmit	 * timer and remember to restart (more output or persist).	 * If there is more data to be acked, restart retransmit	 * timer, using current (possibly backed-off) value;	 */	if (si->si_ack == cb->s_smax + 1) {		cb->s_timer[SPPT_REXMT] = 0;		cb->s_flags |= SF_RXT;	} else if (cb->s_timer[SPPT_PERSIST] == 0)		cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;	/*	 * When new data is acked, open the congestion window.	 * If the window gives us less than ssthresh packets	 * in flight, open exponentially (maxseg at a time).	 * Otherwise open linearly (maxseg^2 / cwnd at a time).	 */	incr = CUNIT;	if (cb->s_cwnd > cb->s_ssthresh)		incr = max(incr * incr / cb->s_cwnd, 1);	cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);	/*	 * Trim Acked data from output queue.	 */	while ((m = so->so_snd.sb_mb) != NULL) {		if (SSEQ_LT((mtod(m, struct spidp *))->si_seq, si->si_ack))			sbdroprecord(&so->so_snd);		else			break;	}	sowwakeup(so);	cb->s_rack = si->si_ack;update_window:	if (SSEQ_LT(cb->s_snxt, cb->s_rack))		cb->s_snxt = cb->s_rack;	if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq &&	    (SSEQ_LT(cb->s_swl2, si->si_ack) ||	     cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) {		/* keep track of pure window updates */		if ((si->si_cc & SP_SP) && cb->s_swl2 == si->si_ack		    && SSEQ_LT(cb->s_ralo, si->si_alo)) {			sppstat.spps_rcvwinupd++;			sppstat.spps_rcvdupack--;		}		cb->s_ralo = si->si_alo;		cb->s_swl1 = si->si_seq;		cb->s_swl2 = si->si_ack;		cb->s_swnd = (1 + si->si_alo - si->si_ack);		if (cb->s_swnd > cb->s_smxw)			cb->s_smxw = cb->s_swnd;		cb->s_flags |= SF_WIN;	}	/*	 * If this packet number is higher than that which	 * we have allocated refuse it, unless urgent	 */	if (SSEQ_GT(si->si_seq, cb->s_alo)) {		if (si->si_cc & SP_SP) {			sppstat.spps_rcvwinprobe++;			return (1);		} else			sppstat.spps_rcvpackafterwin++;		if (si->si_cc & SP_OB) {			if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) {				ns_error(dtom(si), NS_ERR_FULLUP, 0);				return (0);			} /* else queue this packet; */		} else {			/*register struct socket *so = cb->s_nspcb->nsp_socket;			if (so->so_state && SS_NOFDREF) {				ns_error(dtom(si), NS_ERR_NOSOCK, 0);				(void)spp_close(cb);			} else				       would crash system*/			spp_istat.notyet++;			ns_error(dtom(si), NS_ERR_FULLUP, 0);			return (0);		}	}	/*	 * If this is a system packet, we don't need to	 * queue it up, and won't update acknowledge #	 */	if (si->si_cc & SP_SP) {		return (1);	}	/*	 * We have already seen this packet, so drop.	 */	if (SSEQ_LT(si->si_seq, cb->s_ack)) {		spp_istat.bdreas++;		sppstat.spps_rcvduppack++;		if (si->si_seq == cb->s_ack - 1)			spp_istat.lstdup++;		return (1);	}	/*	 * Loop through all packets queued up to insert in	 * appropriate sequence.	 */	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {		if (si->si_seq == SI(q)->si_seq) {			sppstat.spps_rcvduppack++;			return (1);		}		if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) {			sppstat.spps_rcvoopack++;			break;		}	}	insque(si, q->si_prev);	/*	 * If this packet is urgent, inform process	 */	if (si->si_cc & SP_OB) {		cb->s_iobc = ((char *)si)[1 + sizeof(*si)];		sohasoutofband(so);		cb->s_oobflags |= SF_IOOB;	}present:#define SPINC sizeof(struct sphdr)	/*	 * Loop through all packets queued up to update acknowledge	 * number, and present all acknowledged data to user;	 * If in packet interface mode, show packet headers.	 */	for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {		  if (SI(q)->si_seq == cb->s_ack) {			cb->s_ack++;			m = dtom(q);			if (SI(q)->si_cc & SP_OB) {				cb->s_oobflags &= ~SF_IOOB;				if (so->so_rcv.sb_cc)					so->so_oobmark = so->so_rcv.sb_cc;				else					so->so_state |= SS_RCVATMARK;			}			q = q->si_prev;			remque(q->si_next);			wakeup = 1;			sppstat.spps_rcvpack++;#ifdef SF_NEWCALL			if (cb->s_flags2 & SF_NEWCALL) {				struct sphdr *sp = mtod(m, struct sphdr *);				u_char dt = sp->sp_dt;				spp_newchecks[4]++;				if (dt != cb->s_rhdr.sp_dt) {					struct mbuf *mm =					   m_getclr(M_DONTWAIT, MT_CONTROL);					spp_newchecks[0]++;					if (mm != NULL) {						u_short *s =							mtod(mm, u_short *);						cb->s_rhdr.sp_dt = dt;						mm->m_len = 5; /*XXX*/						s[0] = 5;						s[1] = 1;						*(u_char *)(&s[2]) = dt;						sbappend(&so->so_rcv, mm);					}				}				if (sp->sp_cc & SP_OB) {					MCHTYPE(m, MT_OOBDATA);					spp_newchecks[1]++;					so->so_oobmark = 0;					so->so_state &= ~SS_RCVATMARK;				}				if (packetp == 0) {					m->m_data += SPINC;					m->m_len -= SPINC;					m->m_pkthdr.len -= SPINC;				}				if ((sp->sp_cc & SP_EM) || packetp) {					sbappendrecord(&so->so_rcv, m);					spp_newchecks[9]++;				} else					sbappend(&so->so_rcv, m);			} else#endif			if (packetp) {				sbappendrecord(&so->so_rcv, m);			} else {				cb->s_rhdr = *mtod(m, struct sphdr *);				m->m_data += SPINC;				m->m_len -= SPINC;				m->m_pkthdr.len -= SPINC;				sbappend(&so->so_rcv, m);			}		  } else			break;	}	if (wakeup) sorwakeup(so);	return (0);}spp_ctlinput(cmd, arg)	int cmd;	caddr_t arg;{	struct ns_addr *na;	extern u_char nsctlerrmap[];	extern spp_abort(), spp_quench();	extern struct nspcb *idp_drop();	struct ns_errp *errp;	struct nspcb *nsp;	struct sockaddr_ns *sns;	int type;	if (cmd < 0 || cmd > PRC_NCMDS)		return;	type = NS_ERR_UNREACH_HOST;	switch (cmd) {	case PRC_ROUTEDEAD:		return;	case PRC_IFDOWN:	case PRC_HOSTDEAD:	case PRC_HOSTUNREACH:		sns = (struct sockaddr_ns *)arg;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -