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

📄 spp_usrreq.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (sns->sns_family != AF_NS)			return;		na = &sns->sns_addr;		break;	default:		errp = (struct ns_errp *)arg;		na = &errp->ns_err_idp.idp_dna;		type = errp->ns_err_num;		type = ntohs((u_short)type);	}	switch (type) {	case NS_ERR_UNREACH_HOST:		ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0);		break;	case NS_ERR_TOO_BIG:	case NS_ERR_NOSOCK:		nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port,			NS_WILDCARD);		if (nsp) {			if(nsp->nsp_pcb)				(void) spp_drop((struct sppcb *)nsp->nsp_pcb,						(int)nsctlerrmap[cmd]);			else				(void) idp_drop(nsp, (int)nsctlerrmap[cmd]);		}		break;	case NS_ERR_FULLUP:		ns_pcbnotify(na, 0, spp_quench, (long) 0);	}}/* * When a source quench is received, close congestion window * to one packet.  We will gradually open it again as we proceed. */spp_quench(nsp)	struct nspcb *nsp;{	struct sppcb *cb = nstosppcb(nsp);	if (cb)		cb->s_cwnd = CUNIT;}#ifdef notdefintspp_fixmtu(nsp)register struct nspcb *nsp;{	register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb);	register struct mbuf *m;	register struct spidp *si;	struct ns_errp *ep;	struct sockbuf *sb;	int badseq, len;	struct mbuf *firstbad, *m0;	if (cb) {		/* 		 * The notification that we have sent		 * too much is bad news -- we will		 * have to go through queued up so far		 * splitting ones which are too big and		 * reassigning sequence numbers and checksums.		 * we should then retransmit all packets from		 * one above the offending packet to the last one		 * we had sent (or our allocation)		 * then the offending one so that the any queued		 * data at our destination will be discarded.		 */		 ep = (struct ns_errp *)nsp->nsp_notify_param;		 sb = &nsp->nsp_socket->so_snd;		 cb->s_mtu = ep->ns_err_param;		 badseq = SI(&ep->ns_err_idp)->si_seq;		 for (m = sb->sb_mb; m; m = m->m_act) {			si = mtod(m, struct spidp *);			if (si->si_seq == badseq)				break;		 }		 if (m == 0) return;		 firstbad = m;		 /*for (;;) {*/			/* calculate length */			for (m0 = m, len = 0; m ; m = m->m_next)				len += m->m_len;			if (len > cb->s_mtu) {			}		/* FINISH THIS		} */	}}#endifspp_output(cb, m0)	register struct sppcb *cb;	struct mbuf *m0;{	struct socket *so = cb->s_nspcb->nsp_socket;	register struct mbuf *m;	register struct spidp *si = (struct spidp *) 0;	register struct sockbuf *sb = &so->so_snd;	int len = 0, win, rcv_win;	short span, off, recordp = 0;	u_short alo;	int error = 0, sendalot;#ifdef notdef	int idle;#endif	struct mbuf *mprev;	extern int idpcksum;	if (m0) {		int mtu = cb->s_mtu;		int datalen;		/*		 * Make sure that packet isn't too big.		 */		for (m = m0; m ; m = m->m_next) {			mprev = m;			len += m->m_len;			if (m->m_flags & M_EOR)				recordp = 1;		}		datalen = (cb->s_flags & SF_HO) ?				len - sizeof (struct sphdr) : len;		if (datalen > mtu) {			if (cb->s_flags & SF_PI) {				m_freem(m0);				return (EMSGSIZE);			} else {				int oldEM = cb->s_cc & SP_EM;				cb->s_cc &= ~SP_EM;				while (len > mtu) {					/*					 * Here we are only being called					 * from usrreq(), so it is OK to					 * block.					 */					m = m_copym(m0, 0, mtu, M_WAIT);					if (cb->s_flags & SF_NEWCALL) {					    struct mbuf *mm = m;					    spp_newchecks[7]++;					    while (mm) {						mm->m_flags &= ~M_EOR;						mm = mm->m_next;					    }					}					error = spp_output(cb, m);					if (error) {						cb->s_cc |= oldEM;						m_freem(m0);						return(error);					}					m_adj(m0, mtu);					len -= mtu;				}				cb->s_cc |= oldEM;			}		}		/*		 * Force length even, by adding a "garbage byte" if		 * necessary.		 */		if (len & 1) {			m = mprev;			if (M_TRAILINGSPACE(m) >= 1)				m->m_len++;			else {				struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);				if (m1 == 0) {					m_freem(m0);					return (ENOBUFS);				}				m1->m_len = 1;				*(mtod(m1, u_char *)) = 0;				m->m_next = m1;			}		}		m = m_gethdr(M_DONTWAIT, MT_HEADER);		if (m == 0) {			m_freem(m0);			return (ENOBUFS);		}		/*		 * Fill in mbuf with extended SP header		 * and addresses and length put into network format.		 */		MH_ALIGN(m, sizeof (struct spidp));		m->m_len = sizeof (struct spidp);		m->m_next = m0;		si = mtod(m, struct spidp *);		si->si_i = *cb->s_idp;		si->si_s = cb->s_shdr;		if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {			register struct sphdr *sh;			if (m0->m_len < sizeof (*sh)) {				if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {					(void) m_free(m);					m_freem(m0);					return (EINVAL);				}				m->m_next = m0;			}			sh = mtod(m0, struct sphdr *);			si->si_dt = sh->sp_dt;			si->si_cc |= sh->sp_cc & SP_EM;			m0->m_len -= sizeof (*sh);			m0->m_data += sizeof (*sh);			len -= sizeof (*sh);		}		len += sizeof(*si);		if ((cb->s_flags2 & SF_NEWCALL) && recordp) {			si->si_cc  |= SP_EM;			spp_newchecks[8]++;		}		if (cb->s_oobflags & SF_SOOB) {			/*			 * Per jqj@cornell:			 * make sure OB packets convey exactly 1 byte.			 * If the packet is 1 byte or larger, we			 * have already guaranted there to be at least			 * one garbage byte for the checksum, and			 * extra bytes shouldn't hurt!			 */			if (len > sizeof(*si)) {				si->si_cc |= SP_OB;				len = (1 + sizeof(*si));			}		}		si->si_len = htons((u_short)len);		m->m_pkthdr.len = ((len - 1) | 1) + 1;		/*		 * queue stuff up for output		 */		sbappendrecord(sb, m);		cb->s_seq++;	}#ifdef notdef	idle = (cb->s_smax == (cb->s_rack - 1));#endifagain:	sendalot = 0;	off = cb->s_snxt - cb->s_rack;	win = min(cb->s_swnd, (cb->s_cwnd/CUNIT));	/*	 * If in persist timeout with window of 0, send a probe.	 * Otherwise, if window is small but nonzero	 * and timer expired, send what we can and go into	 * transmit state.	 */	if (cb->s_force == 1 + SPPT_PERSIST) {		if (win != 0) {			cb->s_timer[SPPT_PERSIST] = 0;			cb->s_rxtshift = 0;		}	}	span = cb->s_seq - cb->s_rack;	len = min(span, win) - off;	if (len < 0) {		/*		 * Window shrank after we went into it.		 * If window shrank to 0, cancel pending		 * restransmission and pull s_snxt back		 * to (closed) window.  We will enter persist		 * state below.  If the widndow didn't close completely,		 * just wait for an ACK.		 */		len = 0;		if (win == 0) {			cb->s_timer[SPPT_REXMT] = 0;			cb->s_snxt = cb->s_rack;		}	}	if (len > 1)		sendalot = 1;	rcv_win = sbspace(&so->so_rcv);	/*	 * Send if we owe peer an ACK.	 */	if (cb->s_oobflags & SF_SOOB) {		/*		 * must transmit this out of band packet		 */		cb->s_oobflags &= ~ SF_SOOB;		sendalot = 1;		sppstat.spps_sndurg++;		goto found;	}	if (cb->s_flags & SF_ACKNOW)		goto send;	if (cb->s_state < TCPS_ESTABLISHED)		goto send;	/*	 * Silly window can't happen in spp.	 * Code from tcp deleted.	 */	if (len)		goto send;	/*	 * Compare available window to amount of window	 * known to peer (as advertised window less	 * next expected input.)  If the difference is at least two	 * packets or at least 35% of the mximum possible window,	 * then want to send a window update to peer.	 */	if (rcv_win > 0) {		u_short delta =  1 + cb->s_alo - cb->s_ack;		int adv = rcv_win - (delta * cb->s_mtu);				if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) ||		    (100 * adv / so->so_rcv.sb_hiwat >= 35)) {			sppstat.spps_sndwinup++;			cb->s_flags |= SF_ACKNOW;			goto send;		}	}	/*	 * Many comments from tcp_output.c are appropriate here	 * including . . .	 * If send window is too small, there is data to transmit, and no	 * retransmit or persist is pending, then go to persist state.	 * If nothing happens soon, send when timer expires:	 * if window is nonzero, transmit what we can,	 * otherwise send a probe.	 */	if (so->so_snd.sb_cc && cb->s_timer[SPPT_REXMT] == 0 &&		cb->s_timer[SPPT_PERSIST] == 0) {			cb->s_rxtshift = 0;			spp_setpersist(cb);	}	/*	 * No reason to send a packet, just return.	 */	cb->s_outx = 1;	return (0);send:	/*	 * Find requested packet.	 */	si = 0;	if (len > 0) {		cb->s_want = cb->s_snxt;		for (m = sb->sb_mb; m; m = m->m_act) {			si = mtod(m, struct spidp *);			if (SSEQ_LEQ(cb->s_snxt, si->si_seq))				break;		}	found:		if (si) {			if (si->si_seq == cb->s_snxt)					cb->s_snxt++;				else					sppstat.spps_sndvoid++, si = 0;		}	}	/*	 * update window	 */	if (rcv_win < 0)		rcv_win = 0;	alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu));	if (SSEQ_LT(alo, cb->s_alo)) 		alo = cb->s_alo;	if (si) {		/*		 * must make a copy of this packet for		 * idp_output to monkey with		 */		m = m_copy(dtom(si), 0, (int)M_COPYALL);		if (m == NULL) {			return (ENOBUFS);		}		si = mtod(m, struct spidp *);		if (SSEQ_LT(si->si_seq, cb->s_smax))			sppstat.spps_sndrexmitpack++;		else			sppstat.spps_sndpack++;	} else if (cb->s_force || cb->s_flags & SF_ACKNOW) {		/*		 * Must send an acknowledgement or a probe		 */		if (cb->s_force)			sppstat.spps_sndprobe++;		if (cb->s_flags & SF_ACKNOW)			sppstat.spps_sndacks++;		m = m_gethdr(M_DONTWAIT, MT_HEADER);		if (m == 0)			return (ENOBUFS);		/*		 * Fill in mbuf with extended SP header		 * and addresses and length put into network format.		 */		MH_ALIGN(m, sizeof (struct spidp));		m->m_len = sizeof (*si);		m->m_pkthdr.len = sizeof (*si);		si = mtod(m, struct spidp *);		si->si_i = *cb->s_idp;		si->si_s = cb->s_shdr;		si->si_seq = cb->s_smax + 1;		si->si_len = htons(sizeof (*si));		si->si_cc |= SP_SP;	} else {		cb->s_outx = 3;		if (so->so_options & SO_DEBUG || traceallspps)			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);		return (0);	}	/*	 * Stuff checksum and output datagram.	 */	if ((si->si_cc & SP_SP) == 0) {		if (cb->s_force != (1 + SPPT_PERSIST) ||		    cb->s_timer[SPPT_PERSIST] == 0) {			/*			 * If this is a new packet and we are not currently 			 * timing anything, time this one.			 */			if (SSEQ_LT(cb->s_smax, si->si_seq)) {				cb->s_smax = si->si_seq;				if (cb->s_rtt == 0) {					sppstat.spps_segstimed++;					cb->s_rtseq = si->si_seq;					cb->s_rtt = 1;				}			}			/*			 * Set rexmt timer if not currently set,			 * Initial value for retransmit timer is smoothed			 * round-trip time + 2 * round-trip time variance.			 * Initialize shift counter which is used for backoff			 * of retransmit time.			 */			if (cb->s_timer[SPPT_REXMT] == 0 &&			    cb->s_snxt != cb->s_rack) {				cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;				if (cb->s_timer[SPPT_PERSIST]) {					cb->s_timer[SPPT_PERSIST] = 0;					cb->s_rxtshift = 0;				}			}		} else if (SSEQ_LT(cb->s_smax, si->si_seq)) {			cb->s_smax = si->si_seq;		}	} else if (cb->s_state < TCPS_ESTABLISHED) {		if (cb->s_rtt == 0)			cb->s_rtt = 1; /* Time initial handshake */		if (cb->s_timer[SPPT_REXMT] == 0)			cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;	}	{		/*		 * Do not request acks when we ack their data packets or		 * when we do a gratuitous window update.		 */		if (((si->si_cc & SP_SP) == 0) || cb->s_force)				si->si_cc |= SP_SA;		si->si_seq = htons(si->si_seq);		si->si_alo = htons(alo);		si->si_ack = htons(cb->s_ack);		if (idpcksum) {			si->si_sum = 0;			len = ntohs(si->si_len);			if (len & 1)				len++;			si->si_sum = ns_cksum(m, len);		} else			si->si_sum = 0xffff;		cb->s_outx = 4;		if (so->so_options & SO_DEBUG || traceallspps)			spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);		if (so->so_options & SO_DONTROUTE)			error = ns_output(m, (struct route *)0, NS_ROUTETOIF);		else			error = ns_output(m, &cb->s_nspcb->nsp_route, 0);	}	if (error) {		return (error);	}	sppstat.spps_sndtotal++;	/*	 * Data sent (as far as we can tell).	 * If this advertises a larger window than any other segment,	 * then remember the size of the advertized window.	 * Any pending ACK has now been sent.	 */	cb->s_force = 0;	cb->s_flags &= ~(SF_ACKNOW|SF_DELACK);	if (SSEQ_GT(alo, cb->s_alo))		cb->s_alo = alo;	if (sendalot)		goto again;	cb->s_outx = 5;	return (0);}int spp_do_persist_panics = 0;spp_setpersist(cb)	register struct sppcb *cb;{	register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;	extern int spp_backoff[];	if (cb->s_timer[SPPT_REXMT] && spp_do_persist_panics)		panic("spp_output REXMT");	/*	 * Start/restart persistance timer.	 */	SPPT_RANGESET(cb->s_timer[SPPT_PERSIST],	    t*spp_backoff[cb->s_rxtshift],	    SPPTV_PERSMIN, SPPTV_PERSMAX);	if (cb->s_rxtshift < SPP_MAXRXTSHIFT)		cb->s_rxtshift++;}/*ARGSUSED*/spp_ctloutput(req, so, level, name, value)	int req;	struct socket *so;	int name;	struct mbuf **value;{	register struct mbuf *m;	struct nspcb *nsp = sotonspcb(so);	register struct sppcb *cb;	int mask, error = 0;	if (level != NSPROTO_SPP) {		/* This will have to be changed when we do more general		   stacking of protocols */		return (idp_ctloutput(req, so, level, name, value));	}	if (nsp == NULL) {		error = EINVAL;		goto release;	} else		cb = nstosppcb(nsp);	switch (req) {	case PRCO_GETOPT:		if (value == NULL)			return (EINVAL);		m = m_get(M_DONTWAIT, MT_DATA);		if (m == NULL)			return (ENOBUFS);		switch (name) {		case SO_HEADERS_ON_INPUT:			mask = SF_HI;			goto get_flags;		case SO_HEADERS_ON_OUTPUT:			mask = SF_HO;		get_flags:			m->m_len = sizeof(short);			*mtod(m, short *) = cb->s_flags & mask;			break;		case SO_MTU:			m->m_len = sizeof(u_short);			*mtod(m, short *) = cb->s_mtu;			break;		case SO_LAST_HEADER:			m->m_len = sizeof(struct sphdr);			*mtod(m, struct sphdr *) = cb->s_rhdr;			break;		case SO_DEFAULT_HEADERS:			m->m_len = sizeof(struct spidp);			*mtod(m, struct sphdr *) = cb->s_shdr;			break;		default:			error = EINVAL;		}		*value = m;		break;	case PRCO_SETOPT:		if (value == 0 || *value == 0) {			error = EINVAL;			break;		}		switch (name) {			int *ok;		case SO_HEADERS_ON_INPUT:

⌨️ 快捷键说明

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