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

📄 tcp.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 5 页
字号:
	       	(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT1|		 TCPF_FIN_WAIT2|TCPF_SYN_RECV));}int tcp_disconnect(struct sock *sk, int flags){	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;	int old_state;	int err = 0;	old_state = sk->state;	if (old_state != TCP_CLOSE)		tcp_set_state(sk, TCP_CLOSE);	/* ABORT function of RFC793 */	if (old_state == TCP_LISTEN) {		tcp_listen_stop(sk);	} else if (tcp_need_reset(old_state) ||		   (tp->snd_nxt != tp->write_seq &&		    (1<<old_state)&(TCPF_CLOSING|TCPF_LAST_ACK))) {		/* The last check adjusts for discrepance of Linux wrt. RFC		 * states		 */		tcp_send_active_reset(sk, gfp_any());		sk->err = ECONNRESET;	} else if (old_state == TCP_SYN_SENT)		sk->err = ECONNRESET;	tcp_clear_xmit_timers(sk);	__skb_queue_purge(&sk->receive_queue);  	tcp_writequeue_purge(sk);  	__skb_queue_purge(&tp->out_of_order_queue);	sk->dport = 0;	if (!(sk->userlocks&SOCK_BINDADDR_LOCK)) {		sk->rcv_saddr = 0;		sk->saddr = 0;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)		memset(&sk->net_pinfo.af_inet6.saddr, 0, 16);		memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, 16);#endif	}	sk->shutdown = 0;	sk->done = 0;	tp->srtt = 0;	if ((tp->write_seq += tp->max_window+2) == 0)		tp->write_seq = 1;	tp->backoff = 0;	tp->snd_cwnd = 2;	tp->probes_out = 0;	tp->packets_out = 0;	tp->snd_ssthresh = 0x7fffffff;	tp->snd_cwnd_cnt = 0;	tp->ca_state = TCP_CA_Open;	tcp_clear_retrans(tp);	tcp_delack_init(tp);	tp->send_head = NULL;	tp->saw_tstamp = 0;	tcp_sack_reset(tp);	__sk_dst_reset(sk);	BUG_TRAP(!sk->num || sk->prev);	sk->error_report(sk);	return err;}/* *	Wait for an incoming connection, avoid race *	conditions. This must be called with the socket locked. */static int wait_for_connect(struct sock * sk, long timeo){	DECLARE_WAITQUEUE(wait, current);	int err;	/*	 * True wake-one mechanism for incoming connections: only	 * one process gets woken up, not the 'whole herd'.	 * Since we do not 'race & poll' for established sockets	 * anymore, the common case will execute the loop only once.	 *	 * Subtle issue: "add_wait_queue_exclusive()" will be added	 * after any current non-exclusive waiters, and we know that	 * it will always _stay_ after any new non-exclusive waiters	 * because all non-exclusive waiters are added at the	 * beginning of the wait-queue. As such, it's ok to "drop"	 * our exclusiveness temporarily when we get woken up without	 * having to remove and re-insert us on the wait queue.	 */	add_wait_queue_exclusive(sk->sleep, &wait);	for (;;) {		current->state = TASK_INTERRUPTIBLE;		release_sock(sk);		if (sk->tp_pinfo.af_tcp.accept_queue == NULL)			timeo = schedule_timeout(timeo);		lock_sock(sk);		err = 0;		if (sk->tp_pinfo.af_tcp.accept_queue)			break;		err = -EINVAL;		if (sk->state != TCP_LISTEN)			break;		err = sock_intr_errno(timeo);		if (signal_pending(current))			break;		err = -EAGAIN;		if (!timeo)			break;	}	current->state = TASK_RUNNING;	remove_wait_queue(sk->sleep, &wait);	return err;}/* *	This will accept the next outstanding connection. */struct sock *tcp_accept(struct sock *sk, int flags, int *err){	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;	struct open_request *req;	struct sock *newsk;	int error;	lock_sock(sk); 	/* We need to make sure that this socket is listening,	 * and that it has something pending.	 */	error = -EINVAL;	if (sk->state != TCP_LISTEN)		goto out;	/* Find already established connection */	if (!tp->accept_queue) {		long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);		/* If this is a non blocking socket don't sleep */		error = -EAGAIN;		if (!timeo)			goto out;		error = wait_for_connect(sk, timeo);		if (error)			goto out;	}	req = tp->accept_queue;	if ((tp->accept_queue = req->dl_next) == NULL)		tp->accept_queue_tail = NULL; 	newsk = req->sk;	tcp_acceptq_removed(sk);	tcp_openreq_fastfree(req);	BUG_TRAP(newsk->state != TCP_SYN_RECV);	release_sock(sk);	return newsk;out:	release_sock(sk);	*err = error; 	return NULL;}/* *	Socket option code for TCP.  */  int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, 		   int optlen){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	int val;	int err = 0;	if (level != SOL_TCP)		return tp->af_specific->setsockopt(sk, level, optname, 						   optval, optlen);	if(optlen<sizeof(int))		return -EINVAL;	if (get_user(val, (int *)optval))		return -EFAULT;	lock_sock(sk);	switch(optname) {	case TCP_MAXSEG:		/* values greater than interface MTU won't take effect.  however at		 * the point when this call is done we typically don't yet know		 * which interface is going to be used		 */		if(val < 8 || val > MAX_TCP_WINDOW) {			err = -EINVAL;			break;		}		tp->user_mss = val;		break;	case TCP_NODELAY:		/* You cannot try to use this and TCP_CORK in		 * tandem, so let the user know.		 */		if (tp->nonagle == 2) {			err = -EINVAL;			break;		}		tp->nonagle = (val == 0) ? 0 : 1;		if (val)			tcp_push_pending_frames(sk, tp);		break;	case TCP_CORK:		/* When set indicates to always queue non-full frames.		 * Later the user clears this option and we transmit		 * any pending partial frames in the queue.  This is		 * meant to be used alongside sendfile() to get properly		 * filled frames when the user (for example) must write		 * out headers with a write() call first and then use		 * sendfile to send out the data parts.		 *		 * You cannot try to use TCP_NODELAY and this mechanism		 * at the same time, so let the user know.		 */		if (tp->nonagle == 1) {			err = -EINVAL;			break;		}		if (val != 0) {			tp->nonagle = 2;		} else {			tp->nonagle = 0;			tcp_push_pending_frames(sk, tp);		}		break;			case TCP_KEEPIDLE:		if (val < 1 || val > MAX_TCP_KEEPIDLE)			err = -EINVAL;		else {			tp->keepalive_time = val * HZ;			if (sk->keepopen && !((1<<sk->state)&(TCPF_CLOSE|TCPF_LISTEN))) {				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;				if (tp->keepalive_time > elapsed)					elapsed = tp->keepalive_time - elapsed;				else					elapsed = 0;				tcp_reset_keepalive_timer(sk, elapsed);			}		}		break;	case TCP_KEEPINTVL:		if (val < 1 || val > MAX_TCP_KEEPINTVL)			err = -EINVAL;		else			tp->keepalive_intvl = val * HZ;		break;	case TCP_KEEPCNT:		if (val < 1 || val > MAX_TCP_KEEPCNT)			err = -EINVAL;		else			tp->keepalive_probes = val;		break;	case TCP_SYNCNT:		if (val < 1 || val > MAX_TCP_SYNCNT)			err = -EINVAL;		else			tp->syn_retries = val;		break;	case TCP_LINGER2:		if (val < 0)			tp->linger2 = -1;		else if (val > sysctl_tcp_fin_timeout/HZ)			tp->linger2 = 0;		else			tp->linger2 = val*HZ;		break;	case TCP_DEFER_ACCEPT:		tp->defer_accept = 0;		if (val > 0) {			/* Translate value in seconds to number of retransmits */			while (tp->defer_accept < 32 && val > ((TCP_TIMEOUT_INIT/HZ)<<tp->defer_accept))				tp->defer_accept++;			tp->defer_accept++;		}		break;	case TCP_WINDOW_CLAMP:		if (val==0) {			if (sk->state != TCP_CLOSE) {				err = -EINVAL;				break;			}			tp->window_clamp = 0;		} else {			tp->window_clamp = val<SOCK_MIN_RCVBUF/2 ?				SOCK_MIN_RCVBUF/2 : val;		}		break;	case TCP_QUICKACK:		if (!val) {			tp->ack.pingpong = 1;		} else {			tp->ack.pingpong = 0;			if ((1<<sk->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT) &&			    tcp_ack_scheduled(tp)) {				tp->ack.pending |= TCP_ACK_PUSHED;				cleanup_rbuf(sk, 1);				if (!(val & 1))					tp->ack.pingpong = 1;			}		}		break;	default:		err = -ENOPROTOOPT;		break;	};	release_sock(sk);	return err;}int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval,		   int *optlen){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	int val, len;	if(level != SOL_TCP)		return tp->af_specific->getsockopt(sk, level, optname,						   optval, optlen);	if(get_user(len,optlen))		return -EFAULT;	len = min_t(unsigned int, len, sizeof(int));		if(len < 0)		return -EINVAL;	switch(optname) {	case TCP_MAXSEG:		val = tp->mss_cache;		if (val == 0 && ((1<<sk->state)&(TCPF_CLOSE|TCPF_LISTEN)))			val = tp->user_mss;		break;	case TCP_NODELAY:		val = (tp->nonagle == 1);		break;	case TCP_CORK:		val = (tp->nonagle == 2);		break;	case TCP_KEEPIDLE:		val = (tp->keepalive_time ? : sysctl_tcp_keepalive_time)/HZ;		break;	case TCP_KEEPINTVL:		val = (tp->keepalive_intvl ? : sysctl_tcp_keepalive_intvl)/HZ;		break;	case TCP_KEEPCNT:		val = tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;		break;	case TCP_SYNCNT:		val = tp->syn_retries ? : sysctl_tcp_syn_retries;		break;	case TCP_LINGER2:		val = tp->linger2;		if (val >= 0)			val = (val ? : sysctl_tcp_fin_timeout)/HZ;		break;	case TCP_DEFER_ACCEPT:		val = tp->defer_accept == 0 ? 0 : ((TCP_TIMEOUT_INIT/HZ)<<(tp->defer_accept-1));		break;	case TCP_WINDOW_CLAMP:		val = tp->window_clamp;		break;	case TCP_INFO:	{		struct tcp_info info;		u32 now = tcp_time_stamp;		if(get_user(len,optlen))			return -EFAULT;		info.tcpi_state = sk->state;		info.tcpi_ca_state = tp->ca_state;		info.tcpi_retransmits = tp->retransmits;		info.tcpi_probes = tp->probes_out;		info.tcpi_backoff = tp->backoff;		info.tcpi_options = 0;		if (tp->tstamp_ok)			info.tcpi_options |= TCPI_OPT_TIMESTAMPS;		if (tp->sack_ok)			info.tcpi_options |= TCPI_OPT_SACK;		if (tp->wscale_ok) {			info.tcpi_options |= TCPI_OPT_WSCALE;			info.tcpi_snd_wscale = tp->snd_wscale;			info.tcpi_rcv_wscale = tp->rcv_wscale;		} else {			info.tcpi_snd_wscale = 0;			info.tcpi_rcv_wscale = 0;		}		if (tp->ecn_flags&TCP_ECN_OK)			info.tcpi_options |= TCPI_OPT_ECN;		info.tcpi_rto = (1000000*tp->rto)/HZ;		info.tcpi_ato = (1000000*tp->ack.ato)/HZ;		info.tcpi_snd_mss = tp->mss_cache;		info.tcpi_rcv_mss = tp->ack.rcv_mss;		info.tcpi_unacked = tp->packets_out;		info.tcpi_sacked = tp->sacked_out;		info.tcpi_lost = tp->lost_out;		info.tcpi_retrans = tp->retrans_out;		info.tcpi_fackets = tp->fackets_out;		info.tcpi_last_data_sent = ((now - tp->lsndtime)*1000)/HZ;		info.tcpi_last_ack_sent = 0;		info.tcpi_last_data_recv = ((now - tp->ack.lrcvtime)*1000)/HZ;		info.tcpi_last_ack_recv = ((now - tp->rcv_tstamp)*1000)/HZ;		info.tcpi_pmtu = tp->pmtu_cookie;		info.tcpi_rcv_ssthresh = tp->rcv_ssthresh;		info.tcpi_rtt = ((1000000*tp->srtt)/HZ)>>3;		info.tcpi_rttvar = ((1000000*tp->mdev)/HZ)>>2;		info.tcpi_snd_ssthresh = tp->snd_ssthresh;		info.tcpi_snd_cwnd = tp->snd_cwnd;		info.tcpi_advmss = tp->advmss;		info.tcpi_reordering = tp->reordering;		len = min_t(unsigned int, len, sizeof(info));		if(put_user(len, optlen))			return -EFAULT;		if(copy_to_user(optval, &info,len))			return -EFAULT;		return 0;	}	case TCP_QUICKACK:		val = !tp->ack.pingpong;		break;	default:		return -ENOPROTOOPT;	};  	if(put_user(len, optlen))  		return -EFAULT;	if(copy_to_user(optval, &val,len))		return -EFAULT;  	return 0;}extern void __skb_cb_too_small_for_tcp(int, int);extern void tcpdiag_init(void);void __init tcp_init(void){	struct sk_buff *skb = NULL;	unsigned long goal;	int order, i;	if(sizeof(struct tcp_skb_cb) > sizeof(skb->cb))		__skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),					   sizeof(skb->cb));	tcp_openreq_cachep = kmem_cache_create("tcp_open_request",						   sizeof(struct open_request),					       0, SLAB_HWCACHE_ALIGN,					       NULL, NULL);	if(!tcp_openreq_cachep)		panic("tcp_init: Cannot alloc open_request cache.");	tcp_bucket_cachep = kmem_cache_create("tcp_bind_bucket",					      sizeof(struct tcp_bind_bucket),					      0, SLAB_HWCACHE_ALIGN,					      NULL, NULL);	if(!tcp_bucket_cachep)		panic("tcp_init: Cannot alloc tcp_bind_bucket cache.");	tcp_timewait_cachep = kmem_cache_create("tcp_tw_bucket",						sizeof(struct tcp_tw_bucket),						0, SLAB_HWCACHE_ALIGN,						NULL, NULL);	if(!tcp_timewait_cachep)		panic("tcp_init: Cannot alloc tcp_

⌨️ 快捷键说明

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