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

📄 spp_usrreq.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
			mask = SF_HI;			goto set_head;		case SO_HEADERS_ON_OUTPUT:			mask = SF_HO;		set_head:			if (cb->s_flags & SF_PI) {				ok = mtod(*value, int *);				if (*ok)					cb->s_flags |= mask;				else					cb->s_flags &= ~mask;			} else error = EINVAL;			break;		case SO_MTU:			cb->s_mtu = *(mtod(*value, u_short *));			break;#ifdef SF_NEWCALL		case SO_NEWCALL:			ok = mtod(*value, int *);			if (*ok) {				cb->s_flags2 |= SF_NEWCALL;				spp_newchecks[5]++;			} else {				cb->s_flags2 &= ~SF_NEWCALL;				spp_newchecks[6]++;			}			break;#endif		case SO_DEFAULT_HEADERS:			{				register struct sphdr *sp						= mtod(*value, struct sphdr *);				cb->s_dt = sp->sp_dt;				cb->s_cc = sp->sp_cc & SP_EM;			}			break;		default:			error = EINVAL;		}		m_freem(*value);		break;	}	release:		return (error);}/*ARGSUSED*/spp_usrreq(so, req, m, nam, controlp)	struct socket *so;	int req;	struct mbuf *m, *nam, *controlp;{	struct nspcb *nsp = sotonspcb(so);	register struct sppcb *cb;	int s = splnet();	int error = 0, ostate;	struct mbuf *mm;	register struct sockbuf *sb;	if (req == PRU_CONTROL)                return (ns_control(so, (int)m, (caddr_t)nam,			(struct ifnet *)controlp));	if (nsp == NULL) {		if (req != PRU_ATTACH) {			error = EINVAL;			goto release;		}	} else		cb = nstosppcb(nsp);	ostate = cb ? cb->s_state : 0;	switch (req) {	case PRU_ATTACH:		if (nsp != NULL) {			error = EISCONN;			break;		}		error = ns_pcballoc(so, &nspcb);		if (error)			break;		if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {			error = soreserve(so, (u_long) 3072, (u_long) 3072);			if (error)				break;		}		nsp = sotonspcb(so);		mm = m_getclr(M_DONTWAIT, MT_PCB);		sb = &so->so_snd;		if (mm == NULL) {			error = ENOBUFS;			break;		}		cb = mtod(mm, struct sppcb *);		mm = m_getclr(M_DONTWAIT, MT_HEADER);		if (mm == NULL) {			(void) m_free(dtom(m));			error = ENOBUFS;			break;		}		cb->s_idp = mtod(mm, struct idp *);		cb->s_state = TCPS_LISTEN;		cb->s_smax = -1;		cb->s_swl1 = -1;		cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;		cb->s_nspcb = nsp;		cb->s_mtu = 576 - sizeof (struct spidp);		cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;		cb->s_ssthresh = cb->s_cwnd;		cb->s_cwmx = sbspace(sb) * CUNIT /				(2 * sizeof (struct spidp));		/* Above is recomputed when connecting to account		   for changed buffering or mtu's */		cb->s_rtt = SPPTV_SRTTBASE;		cb->s_rttvar = SPPTV_SRTTDFLT << 2;		SPPT_RANGESET(cb->s_rxtcur,		    ((SPPTV_SRTTBASE >> 2) + (SPPTV_SRTTDFLT << 2)) >> 1,		    SPPTV_MIN, SPPTV_REXMTMAX);		nsp->nsp_pcb = (caddr_t) cb; 		break;	case PRU_DETACH:		if (nsp == NULL) {			error = ENOTCONN;			break;		}		if (cb->s_state > TCPS_LISTEN)			cb = spp_disconnect(cb);		else			cb = spp_close(cb);		break;	case PRU_BIND:		error = ns_pcbbind(nsp, nam);		break;	case PRU_LISTEN:		if (nsp->nsp_lport == 0)			error = ns_pcbbind(nsp, (struct mbuf *)0);		if (error == 0)			cb->s_state = TCPS_LISTEN;		break;	/*	 * Initiate connection to peer.	 * Enter SYN_SENT state, and mark socket as connecting.	 * Start keep-alive timer, setup prototype header,	 * Send initial system packet requesting connection.	 */	case PRU_CONNECT:		if (nsp->nsp_lport == 0) {			error = ns_pcbbind(nsp, (struct mbuf *)0);			if (error)				break;		}		error = ns_pcbconnect(nsp, nam);		if (error)			break;		soisconnecting(so);		sppstat.spps_connattempt++;		cb->s_state = TCPS_SYN_SENT;		cb->s_did = 0;		spp_template(cb);		cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;		cb->s_force = 1 + SPPTV_KEEP;		/*		 * Other party is required to respond to		 * the port I send from, but he is not		 * required to answer from where I am sending to,		 * so allow wildcarding.		 * original port I am sending to is still saved in		 * cb->s_dport.		 */		nsp->nsp_fport = 0;		error = spp_output(cb, (struct mbuf *) 0);		break;	case PRU_CONNECT2:		error = EOPNOTSUPP;		break;	/*	 * We may decide later to implement connection closing	 * handshaking at the spp level optionally.	 * here is the hook to do it:	 */	case PRU_DISCONNECT:		cb = spp_disconnect(cb);		break;	/*	 * Accept a connection.  Essentially all the work is	 * done at higher levels; just return the address	 * of the peer, storing through addr.	 */	case PRU_ACCEPT: {		struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);		nam->m_len = sizeof (struct sockaddr_ns);		sns->sns_family = AF_NS;		sns->sns_addr = nsp->nsp_faddr;		break;		}	case PRU_SHUTDOWN:		socantsendmore(so);		cb = spp_usrclosed(cb);		if (cb)			error = spp_output(cb, (struct mbuf *) 0);		break;	/*	 * After a receive, possibly send acknowledgment	 * updating allocation.	 */	case PRU_RCVD:		cb->s_flags |= SF_RVD;		(void) spp_output(cb, (struct mbuf *) 0);		cb->s_flags &= ~SF_RVD;		break;	case PRU_ABORT:		(void) spp_drop(cb, ECONNABORTED);		break;	case PRU_SENSE:	case PRU_CONTROL:		m = NULL;		error = EOPNOTSUPP;		break;	case PRU_RCVOOB:		if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||		    (so->so_state & SS_RCVATMARK)) {			m->m_len = 1;			*mtod(m, caddr_t) = cb->s_iobc;			break;		}		error = EINVAL;		break;	case PRU_SENDOOB:		if (sbspace(&so->so_snd) < -512) {			error = ENOBUFS;			break;		}		cb->s_oobflags |= SF_SOOB;		/* fall into */	case PRU_SEND:		if (controlp) {			u_short *p = mtod(controlp, u_short *);			spp_newchecks[2]++;			if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */				cb->s_shdr.sp_dt = *(u_char *)(&p[2]);				spp_newchecks[3]++;			}			m_freem(controlp);		}		controlp = NULL;		error = spp_output(cb, m);		m = NULL;		break;	case PRU_SOCKADDR:		ns_setsockaddr(nsp, nam);		break;	case PRU_PEERADDR:		ns_setpeeraddr(nsp, nam);		break;	case PRU_SLOWTIMO:		cb = spp_timers(cb, (int)nam);		req |= ((int)nam) << 8;		break;	case PRU_FASTTIMO:	case PRU_PROTORCV:	case PRU_PROTOSEND:		error =  EOPNOTSUPP;		break;	default:		panic("sp_usrreq");	}	if (cb && (so->so_options & SO_DEBUG || traceallspps))		spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);release:	if (controlp != NULL)		m_freem(controlp);	if (m != NULL)		m_freem(m);	splx(s);	return (error);}spp_usrreq_sp(so, req, m, nam, controlp)	struct socket *so;	int req;	struct mbuf *m, *nam, *controlp;{	int error = spp_usrreq(so, req, m, nam, controlp);	if (req == PRU_ATTACH && error == 0) {		struct nspcb *nsp = sotonspcb(so);		((struct sppcb *)nsp->nsp_pcb)->s_flags |=					(SF_HI | SF_HO | SF_PI);	}	return (error);}/* * Create template to be used to send spp packets on a connection. * Called after host entry created, fills * in a skeletal spp header (choosing connection id), * minimizing the amount of work necessary when the connection is used. */spp_template(cb)	register struct sppcb *cb;{	register struct nspcb *nsp = cb->s_nspcb;	register struct idp *idp = cb->s_idp;	register struct sockbuf *sb = &(nsp->nsp_socket->so_snd);	idp->idp_pt = NSPROTO_SPP;	idp->idp_sna = nsp->nsp_laddr;	idp->idp_dna = nsp->nsp_faddr;	cb->s_sid = htons(spp_iss);	spp_iss += SPP_ISSINCR/2;	cb->s_alo = 1;	cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu;	cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement					of large packets */	cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spidp));	cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd);		/* But allow for lots of little packets as well */}/* * Close a SPIP control block: *	discard spp control block itself *	discard ns protocol control block *	wake up any sleepers */struct sppcb *spp_close(cb)	register struct sppcb *cb;{	register struct spidp_q *s;	struct nspcb *nsp = cb->s_nspcb;	struct socket *so = nsp->nsp_socket;	register struct mbuf *m;	s = cb->s_q.si_next;	while (s != &(cb->s_q)) {		s = s->si_next;		m = dtom(s->si_prev);		remque(s->si_prev);		m_freem(m);	}	(void) m_free(dtom(cb->s_idp));	(void) m_free(dtom(cb));	nsp->nsp_pcb = 0;	soisdisconnected(so);	ns_pcbdetach(nsp);	sppstat.spps_closed++;	return ((struct sppcb *)0);}/* *	Someday we may do level 3 handshaking *	to close a connection or send a xerox style error. *	For now, just close. */struct sppcb *spp_usrclosed(cb)	register struct sppcb *cb;{	return (spp_close(cb));}struct sppcb *spp_disconnect(cb)	register struct sppcb *cb;{	return (spp_close(cb));}/* * Drop connection, reporting * the specified error. */struct sppcb *spp_drop(cb, errno)	register struct sppcb *cb;	int errno;{	struct socket *so = cb->s_nspcb->nsp_socket;	/*	 * someday, in the xerox world	 * we will generate error protocol packets	 * announcing that the socket has gone away.	 */	if (TCPS_HAVERCVDSYN(cb->s_state)) {		sppstat.spps_drops++;		cb->s_state = TCPS_CLOSED;		/*(void) tcp_output(cb);*/	} else		sppstat.spps_conndrops++;	so->so_error = errno;	return (spp_close(cb));}spp_abort(nsp)	struct nspcb *nsp;{	(void) spp_close((struct sppcb *)nsp->nsp_pcb);}int	spp_backoff[SPP_MAXRXTSHIFT+1] =    { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };/* * Fast timeout routine for processing delayed acks */spp_fasttimo(){	register struct nspcb *nsp;	register struct sppcb *cb;	int s = splnet();	nsp = nspcb.nsp_next;	if (nsp)	for (; nsp != &nspcb; nsp = nsp->nsp_next)		if ((cb = (struct sppcb *)nsp->nsp_pcb) &&		    (cb->s_flags & SF_DELACK)) {			cb->s_flags &= ~SF_DELACK;			cb->s_flags |= SF_ACKNOW;			sppstat.spps_delack++;			(void) spp_output(cb, (struct mbuf *) 0);		}	splx(s);}/* * spp protocol timeout routine called every 500 ms. * Updates the timers in all active pcb's and * causes finite state machine actions if timers expire. */spp_slowtimo(){	register struct nspcb *ip, *ipnxt;	register struct sppcb *cb;	int s = splnet();	register int i;	/*	 * Search through tcb's and update active timers.	 */	ip = nspcb.nsp_next;	if (ip == 0) {		splx(s);		return;	}	while (ip != &nspcb) {		cb = nstosppcb(ip);		ipnxt = ip->nsp_next;		if (cb == 0)			goto tpgone;		for (i = 0; i < SPPT_NTIMERS; i++) {			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {				(void) spp_usrreq(cb->s_nspcb->nsp_socket,				    PRU_SLOWTIMO, (struct mbuf *)0,				    (struct mbuf *)i, (struct mbuf *)0,				    (struct mbuf *)0);				if (ipnxt->nsp_prev != ip)					goto tpgone;			}		}		cb->s_idle++;		if (cb->s_rtt)			cb->s_rtt++;tpgone:		ip = ipnxt;	}	spp_iss += SPP_ISSINCR/PR_SLOWHZ;		/* increment iss */	splx(s);}/* * SPP timer processing. */struct sppcb *spp_timers(cb, timer)	register struct sppcb *cb;	int timer;{	long rexmt;	int win;	cb->s_force = 1 + timer;	switch (timer) {	/*	 * 2 MSL timeout in shutdown went off.  TCP deletes connection	 * control block.	 */	case SPPT_2MSL:		printf("spp: SPPT_2MSL went off for no reason\n");		cb->s_timer[timer] = 0;		break;	/*	 * Retransmission timer went off.  Message has not	 * been acked within retransmit interval.  Back off	 * to a longer retransmit interval and retransmit one packet.	 */	case SPPT_REXMT:		if (++cb->s_rxtshift > SPP_MAXRXTSHIFT) {			cb->s_rxtshift = SPP_MAXRXTSHIFT;			sppstat.spps_timeoutdrop++;			cb = spp_drop(cb, ETIMEDOUT);			break;		}		sppstat.spps_rexmttimeo++;		rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;		rexmt *= spp_backoff[cb->s_rxtshift];		SPPT_RANGESET(cb->s_rxtcur, rexmt, SPPTV_MIN, SPPTV_REXMTMAX);		cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;		/*		 * If we have backed off fairly far, our srtt		 * estimate is probably bogus.  Clobber it		 * so we'll take the next rtt measurement as our srtt;		 * move the current srtt into rttvar to keep the current		 * retransmit times until then.		 */		if (cb->s_rxtshift > SPP_MAXRXTSHIFT / 4 ) {			cb->s_rttvar += (cb->s_srtt >> 2);			cb->s_srtt = 0;		}		cb->s_snxt = cb->s_rack;		/*		 * If timing a packet, stop the timer.		 */		cb->s_rtt = 0;		/*		 * See very long discussion in tcp_timer.c about congestion		 * window and sstrhesh		 */		win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;		if (win < 2)			win = 2;		cb->s_cwnd = CUNIT;		cb->s_ssthresh = win * CUNIT;		(void) spp_output(cb, (struct mbuf *) 0);		break;	/*	 * Persistance timer into zero window.	 * Force a probe to be sent.	 */	case SPPT_PERSIST:		sppstat.spps_persisttimeo++;		spp_setpersist(cb);		(void) spp_output(cb, (struct mbuf *) 0);		break;	/*	 * Keep-alive timer went off; send something	 * or drop connection if idle for too long.	 */	case SPPT_KEEP:		sppstat.spps_keeptimeo++;		if (cb->s_state < TCPS_ESTABLISHED)			goto dropit;		if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {		    	if (cb->s_idle >= SPPTV_MAXIDLE)				goto dropit;			sppstat.spps_keepprobe++;			(void) spp_output(cb, (struct mbuf *) 0);		} else			cb->s_idle = 0;		cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;		break;	dropit:		sppstat.spps_keepdrops++;		cb = spp_drop(cb, ETIMEDOUT);		break;	}	return (cb);}#ifndef lintint SppcbSize = sizeof (struct sppcb);int NspcbSize = sizeof (struct nspcb);#endif /* lint */

⌨️ 快捷键说明

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