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

📄 tcp_usrreq.c

📁 嵌入式操作系统ECOS的网络开发包
💻 C
📖 第 1 页 / 共 2 页
字号:
	/*
	 * Abort the TCP.
	 */
	case PRU_ABORT:
		tp = tcp_drop(tp, ECONNABORTED);
		break;

	case PRU_SENSE:
#ifndef __ECOS
		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
#endif
		(void) splx(s);
		return (0);

	case PRU_RCVOOB:
		if ((so->so_oobmark == 0 &&
		    (so->so_state & SS_RCVATMARK) == 0) ||
		    so->so_options & SO_OOBINLINE ||
		    tp->t_oobflags & TCPOOB_HADDATA) {
			error = EINVAL;
			break;
		}
		if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
			error = EWOULDBLOCK;
			break;
		}
		m->m_len = 1;
		*mtod(m, caddr_t) = tp->t_iobc;
		if (((long)nam & MSG_PEEK) == 0)
			tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
		break;

	case PRU_SENDOOB:
		if (sbspace(&so->so_snd) < -512) {
			m_freem(m);
			error = ENOBUFS;
			break;
		}
		/*
		 * According to RFC961 (Assigned Protocols),
		 * the urgent pointer points to the last octet
		 * of urgent data.  We continue, however,
		 * to consider it to indicate the first octet
		 * of data past the urgent section.
		 * Otherwise, snd_up should be one lower.
		 */
		sbappend(&so->so_snd, m);
		tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
		tp->t_force = 1;
		error = tcp_output(tp);
		tp->t_force = 0;
		break;

	case PRU_SOCKADDR:
#ifdef INET6
		if (inp->inp_flags & INP_IPV6)
			in6_setsockaddr(inp, nam);
		else
#endif
			in_setsockaddr(inp, nam);
		break;

	case PRU_PEERADDR:
#ifdef INET6
		if (inp->inp_flags & INP_IPV6)
			in6_setpeeraddr(inp, nam);
		else
#endif
			in_setpeeraddr(inp, nam);
		break;

	/*
	 * TCP slow timer went off; going through this
	 * routine for tracing's sake.
	 */
	case PRU_SLOWTIMO:
		tp = tcp_timers(tp, (long)nam);
		req |= (long)nam << 8;		/* for debug's sake */
		break;

	default:
		panic("tcp_usrreq");
	}
#ifdef TCPDEBUG
	if (tp && (so->so_options & SO_DEBUG))
		tcp_trace(TA_USER, ostate, tp, (caddr_t)0, req, 0);
#endif /* TCPDEBUG */
	splx(s);
	return (error);
}

int
tcp_ctloutput(op, so, level, optname, mp)
	int op;
	struct socket *so;
	int level, optname;
	struct mbuf **mp;
{
	int error = 0, s;
	struct inpcb *inp;
	register struct tcpcb *tp;
	register struct mbuf *m;
	register int i;

	s = splsoftnet();
	inp = sotoinpcb(so);
	if (inp == NULL) {
		splx(s);
		if (op == PRCO_SETOPT && *mp)
			(void) m_free(*mp);
		return (ECONNRESET);
	}
#ifdef INET6
	tp = intotcpcb(inp);
#endif /* INET6 */
	if (level != IPPROTO_TCP) {
#ifdef INET6
		/*
		 * Not sure if this is the best approach.
		 * It seems to be, but we don't set tp->pf until the connection
		 * is established, which may lead to confusion in the case of
		 * AF_INET6 sockets which get SET/GET options for IPv4.
		 */
		if (tp->pf == PF_INET6)
			error = ip6_ctloutput(op, so, level, optname, mp);
		else
#endif /* INET6 */
			error = ip_ctloutput(op, so, level, optname, mp);
		splx(s);
		return (error);
	}
#ifndef INET6
	tp = intotcpcb(inp);
#endif /* !INET6 */

	switch (op) {

	case PRCO_SETOPT:
		m = *mp;
		switch (optname) {

		case TCP_NODELAY:
			if (m == NULL || m->m_len < sizeof (int))
				error = EINVAL;
			else if (*mtod(m, int *))
				tp->t_flags |= TF_NODELAY;
			else
				tp->t_flags &= ~TF_NODELAY;
			break;

		case TCP_MAXSEG:
			if (m == NULL || m->m_len < sizeof (int)) {
				error = EINVAL;
				break;
			}

			i = *mtod(m, int *);
			if (i > 0 && i <= tp->t_maxseg)
				tp->t_maxseg = i;
			else
				error = EINVAL;
			break;

#ifdef TCP_SACK
		case TCP_SACK_DISABLE:
			if (m == NULL || m->m_len < sizeof (int)) {
				error = EINVAL;
				break;
			}

			if (TCPS_HAVEESTABLISHED(tp->t_state)) {
				error = EPERM;
				break;
			}

			if (tp->t_flags & TF_SIGNATURE) {
				error = EPERM;
				break;
			}

			if (*mtod(m, int *))
				tp->sack_disable = 1;
			else
				tp->sack_disable = 0;
			break;
#endif
#ifdef TCP_SIGNATURE
		case TCP_SIGNATURE_ENABLE:
			if (m == NULL || m->m_len < sizeof (int)) {
				error = EINVAL;
				break;
			}

			if (TCPS_HAVEESTABLISHED(tp->t_state)) {
				error = EPERM;
				break;
			}

			if (*mtod(m, int *)) {
				tp->t_flags |= TF_SIGNATURE;
#ifdef TCP_SACK
				tp->sack_disable = 1;
#endif /* TCP_SACK */
			} else
				tp->t_flags &= ~TF_SIGNATURE;
			break;
#endif /* TCP_SIGNATURE */
 		default:
			error = ENOPROTOOPT;
			break;
		}
		if (m)
			(void) m_free(m);
		break;

	case PRCO_GETOPT:
		*mp = m = m_get(M_WAIT, MT_SOOPTS);
		m->m_len = sizeof(int);

		switch (optname) {
		case TCP_NODELAY:
			*mtod(m, int *) = tp->t_flags & TF_NODELAY;
			break;
		case TCP_MAXSEG:
			*mtod(m, int *) = tp->t_maxseg;
			break;
#ifdef TCP_SACK
		case TCP_SACK_DISABLE:
			*mtod(m, int *) = tp->sack_disable;
			break;
#endif
		default:
			error = ENOPROTOOPT;
			break;
		}
		break;
	}
	splx(s);
	return (error);
}

#ifndef TCP_SENDSPACE
#define	TCP_SENDSPACE	1024*16;
#endif
u_int	tcp_sendspace = TCP_SENDSPACE;
#ifndef TCP_RECVSPACE
#define	TCP_RECVSPACE	1024*16;
#endif
u_int	tcp_recvspace = TCP_RECVSPACE;

/*
 * Attach TCP protocol to socket, allocating
 * internet protocol control block, tcp control block,
 * bufer space, and entering LISTEN state if to accept connections.
 */
int
tcp_attach(so)
	struct socket *so;
{
	register struct tcpcb *tp;
	struct inpcb *inp;
	int error;

	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
		error = soreserve(so, tcp_sendspace, tcp_recvspace);
		if (error)
			return (error);
	}
	error = in_pcballoc(so, &tcbtable);
	if (error)
		return (error);
	inp = sotoinpcb(so);
	tp = tcp_newtcpcb(inp);
	if (tp == NULL) {
		int nofd = so->so_state & SS_NOFDREF;	/* XXX */

		so->so_state &= ~SS_NOFDREF;	/* don't free the socket yet */
		in_pcbdetach(inp);
		so->so_state |= nofd;
		return (ENOBUFS);
	}
	tp->t_state = TCPS_CLOSED;
	return (0);
}

/*
 * Initiate (or continue) disconnect.
 * If embryonic state, just send reset (once).
 * If in ``let data drain'' option and linger null, just drop.
 * Otherwise (hard), mark socket disconnecting and drop
 * current input data; switch states based on user close, and
 * send segment to peer (with FIN).
 */
struct tcpcb *
tcp_disconnect(tp)
	register struct tcpcb *tp;
{
	struct socket *so = tp->t_inpcb->inp_socket;

	if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)
		tp = tcp_close(tp);
	else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
		tp = tcp_drop(tp, 0);
	else {
		soisdisconnecting(so);
		sbflush(&so->so_rcv);
		tp = tcp_usrclosed(tp);
		if (tp)
			(void) tcp_output(tp);
	}
	return (tp);
}

/*
 * User issued close, and wish to trail through shutdown states:
 * if never received SYN, just forget it.  If got a SYN from peer,
 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
 * If already got a FIN from peer, then almost done; go to LAST_ACK
 * state.  In all other cases, have already sent FIN to peer (e.g.
 * after PRU_SHUTDOWN), and just have to play tedious game waiting
 * for peer to send FIN or not respond to keep-alives, etc.
 * We can let the user exit from the close as soon as the FIN is acked.
 */
struct tcpcb *
tcp_usrclosed(tp)
	register struct tcpcb *tp;
{

	switch (tp->t_state) {

	case TCPS_CLOSED:
	case TCPS_LISTEN:
	case TCPS_SYN_SENT:
		tp->t_state = TCPS_CLOSED;
		tp = tcp_close(tp);
		break;

	case TCPS_SYN_RECEIVED:
	case TCPS_ESTABLISHED:
		tp->t_state = TCPS_FIN_WAIT_1;
		break;

	case TCPS_CLOSE_WAIT:
		tp->t_state = TCPS_LAST_ACK;
		break;
	}
	if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
		soisdisconnected(tp->t_inpcb->inp_socket);
		/*
		 * If we are in FIN_WAIT_2, we arrived here because the
		 * application did a shutdown of the send side.  Like the
		 * case of a transition from FIN_WAIT_1 to FIN_WAIT_2 after
		 * a full close, we start a timer to make sure sockets are
		 * not left in FIN_WAIT_2 forever.
		 */
		if (tp->t_state == TCPS_FIN_WAIT_2)
			tp->t_timer[TCPT_2MSL] = tcp_maxidle;
	}
	return (tp);
}

/*
 * Look up a socket for ident..
 */
int
tcp_ident(oldp, oldlenp, newp, newlen)
	void *oldp;
	size_t *oldlenp;
	void *newp;
	size_t newlen;
{
	int error = 0, s;
	struct tcp_ident_mapping tir;
	struct inpcb *inp;
	struct sockaddr_in *fin, *lin;

	if (oldp == NULL || newp != NULL || newlen != 0)
		return (EINVAL);
	if  (*oldlenp < sizeof(tir))
		return (ENOMEM);
	if ((error = copyin(oldp, &tir, sizeof (tir))) != 0 )
		return (error);
	if (tir.faddr.sa_len != sizeof (struct sockaddr) ||
	    tir.faddr.sa_family != AF_INET)
		return (EINVAL);
	fin = (struct sockaddr_in *)&tir.faddr;
	lin = (struct sockaddr_in *)&tir.laddr;

	s = splsoftnet();
	inp = in_pcbhashlookup(&tcbtable,  fin->sin_addr, fin->sin_port,
	    lin->sin_addr, lin->sin_port);
	if (inp == NULL) {
		++tcpstat.tcps_pcbhashmiss;
		inp = in_pcblookup(&tcbtable, &fin->sin_addr, fin->sin_port,
		    &lin->sin_addr, lin->sin_port, 0);
	}
	if (inp != NULL && (inp->inp_socket->so_state & SS_CONNECTOUT)) {
		tir.ruid = inp->inp_socket->so_ruid;
		tir.euid = inp->inp_socket->so_euid;
	} else {
		tir.ruid = -1;
		tir.euid = -1;
	}
	splx(s);

	*oldlenp = sizeof (tir);
	error = copyout((void *)&tir, oldp, sizeof (tir));
	return (error);
}

#ifdef CYGPKG_NET_SYSCTL
/*
 * Sysctl for tcp variables.
 */
int
tcp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
	int *name;
	u_int namelen;
	void *oldp;
	size_t *oldlenp;
	void *newp;
	size_t newlen;
{

	/* All sysctl names at this level are terminal. */
	if (namelen != 1)
		return (ENOTDIR);

	switch (name[0]) {
	case TCPCTL_RFC1323:
		return (sysctl_int(oldp, oldlenp, newp, newlen,
		    &tcp_do_rfc1323));
#ifdef TCP_SACK
	case TCPCTL_SACK:
		return (sysctl_int(oldp, oldlenp, newp, newlen,
		    &tcp_do_sack));
#endif
	case TCPCTL_MSSDFLT:
		return (sysctl_int(oldp, oldlenp, newp, newlen,
		    &tcp_mssdflt));
	case TCPCTL_KEEPINITTIME:
		return (sysctl_int(oldp, oldlenp, newp, newlen,
		    &tcptv_keep_init));

	case TCPCTL_KEEPIDLE:
		return (sysctl_int(oldp, oldlenp, newp, newlen,
		    &tcp_keepidle));

	case TCPCTL_KEEPINTVL:
		return (sysctl_int(oldp, oldlenp, newp, newlen,
		    &tcp_keepintvl));

	case TCPCTL_SLOWHZ:
		return (sysctl_rdint(oldp, oldlenp, newp, PR_SLOWHZ));

	case TCPCTL_BADDYNAMIC:
		return (sysctl_struct(oldp, oldlenp, newp, newlen,
		    baddynamicports.tcp, sizeof(baddynamicports.tcp)));

	case TCPCTL_RECVSPACE:
		return (sysctl_int(oldp, oldlenp, newp, newlen,&tcp_recvspace));

	case TCPCTL_SENDSPACE:
		return (sysctl_int(oldp, oldlenp, newp, newlen,&tcp_sendspace));
	case TCPCTL_IDENT:
		return (tcp_ident(oldp, oldlenp, newp, newlen));
	default:
		return (ENOPROTOOPT);
	}
	/* NOTREACHED */
}
#endif // CYGPKG_NET_SYSCTL

⌨️ 快捷键说明

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