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

📄 tcp_ipv6.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
📖 第 1 页 / 共 4 页
字号:
	kfree_skb(skb);	return 0;discard_and_relse:	sock_put(sk);	goto discard_it;do_time_wait:	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {		TCP_INC_STATS_BH(TcpInErrs);		sock_put(sk);		goto discard_it;	}	switch(tcp_timewait_state_process((struct tcp_tw_bucket *)sk,					  skb, th, skb->len)) {	case TCP_TW_SYN:	{		struct sock *sk2;		sk2 = tcp_v6_lookup_listener(&skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb));		if (sk2 != NULL) {			tcp_tw_deschedule((struct tcp_tw_bucket *)sk);			tcp_timewait_kill((struct tcp_tw_bucket *)sk);			tcp_tw_put((struct tcp_tw_bucket *)sk);			sk = sk2;			goto process;		}		/* Fall through to ACK */	}	case TCP_TW_ACK:		tcp_v6_timewait_ack(sk, skb);		break;	case TCP_TW_RST:		goto no_tcp_socket;	case TCP_TW_SUCCESS:;	}	goto discard_it;}static int tcp_v6_rebuild_header(struct sock *sk){	int err;	struct dst_entry *dst;	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;	dst = __sk_dst_check(sk, np->dst_cookie);	if (dst == NULL) {		struct flowi fl;		fl.proto = IPPROTO_TCP;		fl.nl_u.ip6_u.daddr = &np->daddr;		fl.nl_u.ip6_u.saddr = &np->saddr;		fl.fl6_flowlabel = np->flow_label;		fl.oif = sk->bound_dev_if;		fl.uli_u.ports.dport = sk->dport;		fl.uli_u.ports.sport = sk->sport;		if (np->opt && np->opt->srcrt) {			struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;			fl.nl_u.ip6_u.daddr = rt0->addr;		}		dst = ip6_route_output(sk, &fl);		if (dst->error) {			err = dst->error;			dst_release(dst);			sk->route_caps = 0;			return err;		}		ip6_dst_store(sk, dst, NULL);		sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;	}	return 0;}static int tcp_v6_xmit(struct sk_buff *skb){	struct sock *sk = skb->sk;	struct ipv6_pinfo * np = &sk->net_pinfo.af_inet6;	struct flowi fl;	struct dst_entry *dst;	fl.proto = IPPROTO_TCP;	fl.fl6_dst = &np->daddr;	fl.fl6_src = &np->saddr;	fl.fl6_flowlabel = np->flow_label;	IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);	fl.oif = sk->bound_dev_if;	fl.uli_u.ports.sport = sk->sport;	fl.uli_u.ports.dport = sk->dport;	if (np->opt && np->opt->srcrt) {		struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;		fl.nl_u.ip6_u.daddr = rt0->addr;	}	dst = __sk_dst_check(sk, np->dst_cookie);	if (dst == NULL) {		dst = ip6_route_output(sk, &fl);		if (dst->error) {			sk->err_soft = -dst->error;			dst_release(dst);			return -sk->err_soft;		}		ip6_dst_store(sk, dst, NULL);	}	skb->dst = dst_clone(dst);	/* Restore final destination back after routing done */	fl.nl_u.ip6_u.daddr = &np->daddr;	return ip6_xmit(sk, skb, &fl, np->opt);}static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr){	struct ipv6_pinfo * np = &sk->net_pinfo.af_inet6;	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;	sin6->sin6_family = AF_INET6;	memcpy(&sin6->sin6_addr, &np->daddr, sizeof(struct in6_addr));	sin6->sin6_port	= sk->dport;	/* We do not store received flowlabel for TCP */	sin6->sin6_flowinfo = 0;	sin6->sin6_scope_id = 0;	if (sk->bound_dev_if && ipv6_addr_type(&sin6->sin6_addr)&IPV6_ADDR_LINKLOCAL)		sin6->sin6_scope_id = sk->bound_dev_if;}static int tcp_v6_remember_stamp(struct sock *sk){	/* Alas, not yet... */	return 0;}static struct tcp_func ipv6_specific = {	tcp_v6_xmit,	tcp_v6_send_check,	tcp_v6_rebuild_header,	tcp_v6_conn_request,	tcp_v6_syn_recv_sock,	tcp_v6_hash_connecting,	tcp_v6_remember_stamp,	sizeof(struct ipv6hdr),	ipv6_setsockopt,	ipv6_getsockopt,	v6_addr2sockaddr,	sizeof(struct sockaddr_in6)};/* *	TCP over IPv4 via INET6 API */static struct tcp_func ipv6_mapped = {	ip_queue_xmit,	tcp_v4_send_check,	tcp_v4_rebuild_header,	tcp_v6_conn_request,	tcp_v6_syn_recv_sock,	tcp_v4_hash_connecting,	tcp_v4_remember_stamp,	sizeof(struct iphdr),	ipv6_setsockopt,	ipv6_getsockopt,	v6_addr2sockaddr,	sizeof(struct sockaddr_in6)};/* NOTE: A lot of things set to zero explicitly by call to *       sk_alloc() so need not be done here. */static int tcp_v6_init_sock(struct sock *sk){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	skb_queue_head_init(&tp->out_of_order_queue);	tcp_init_xmit_timers(sk);	tcp_prequeue_init(tp);	tp->rto  = TCP_TIMEOUT_INIT;	tp->mdev = TCP_TIMEOUT_INIT;	/* So many TCP implementations out there (incorrectly) count the	 * initial SYN frame in their delayed-ACK and congestion control	 * algorithms that we must have the following bandaid to talk	 * efficiently to them.  -DaveM	 */	tp->snd_cwnd = 2;	/* See draft-stevens-tcpca-spec-01 for discussion of the	 * initialization of these values.	 */	tp->snd_ssthresh = 0x7fffffff;	tp->snd_cwnd_clamp = ~0;	tp->mss_cache = 536;	tp->reordering = sysctl_tcp_reordering;	sk->state = TCP_CLOSE;	sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;	sk->write_space = tcp_write_space;	sk->use_write_queue = 1;	sk->sndbuf = sysctl_tcp_wmem[1];	sk->rcvbuf = sysctl_tcp_rmem[1];	atomic_inc(&tcp_sockets_allocated);	return 0;}static int tcp_v6_destroy_sock(struct sock *sk){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	tcp_clear_xmit_timers(sk);	/* Cleanup up the write buffer. */  	tcp_writequeue_purge(sk);	/* Cleans up our, hopefully empty, out_of_order_queue. */  	__skb_queue_purge(&tp->out_of_order_queue);	/* Clean prequeue, it must be empty really */	__skb_queue_purge(&tp->ucopy.prequeue);	/* Clean up a referenced TCP bind bucket. */	if(sk->prev != NULL)		tcp_put_port(sk);	/* If sendmsg cached page exists, toss it. */	if (tp->sndmsg_page != NULL)		__free_page(tp->sndmsg_page);	atomic_dec(&tcp_sockets_allocated);	return inet6_destroy_sock(sk);}/* Proc filesystem TCPv6 sock list dumping. */static void get_openreq6(struct sock *sk, struct open_request *req, char *tmpbuf, int i, int uid){	struct in6_addr *dest, *src;	int ttd = req->expires - jiffies;	if (ttd < 0)		ttd = 0;	src = &req->af.v6_req.loc_addr;	dest = &req->af.v6_req.rmt_addr;	sprintf(tmpbuf,		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "		"%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p",		i,		src->s6_addr32[0], src->s6_addr32[1],		src->s6_addr32[2], src->s6_addr32[3],		ntohs(sk->sport),		dest->s6_addr32[0], dest->s6_addr32[1],		dest->s6_addr32[2], dest->s6_addr32[3],		ntohs(req->rmt_port),		TCP_SYN_RECV,		0,0, /* could print option size, but that is af dependent. */		1,   /* timers active (only the expire timer) */  		ttd, 		req->retrans,		uid,		0,  /* non standard timer */  		0, /* open_requests have no inode */		0, req);}static void get_tcp6_sock(struct sock *sp, char *tmpbuf, int i){	struct in6_addr *dest, *src;	__u16 destp, srcp;	int timer_active;	unsigned long timer_expires;	struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;	dest  = &sp->net_pinfo.af_inet6.daddr;	src   = &sp->net_pinfo.af_inet6.rcv_saddr;	destp = ntohs(sp->dport);	srcp  = ntohs(sp->sport);	if (tp->pending == TCP_TIME_RETRANS) {		timer_active	= 1;		timer_expires	= tp->timeout;	} else if (tp->pending == TCP_TIME_PROBE0) {		timer_active	= 4;		timer_expires	= tp->timeout;	} else if (timer_pending(&sp->timer)) {		timer_active	= 2;		timer_expires	= sp->timer.expires;	} else {		timer_active	= 0;		timer_expires = jiffies;	}	sprintf(tmpbuf,		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "		"%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d",		i,		src->s6_addr32[0], src->s6_addr32[1],		src->s6_addr32[2], src->s6_addr32[3], srcp,		dest->s6_addr32[0], dest->s6_addr32[1],		dest->s6_addr32[2], dest->s6_addr32[3], destp,		sp->state, 		tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,		timer_active, timer_expires-jiffies,		tp->retransmits,		sock_i_uid(sp),		tp->probes_out,		sock_i_ino(sp),		atomic_read(&sp->refcnt), sp,		tp->rto, tp->ack.ato, (tp->ack.quick<<1)|tp->ack.pingpong,		tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh		);}static void get_timewait6_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i){	struct in6_addr *dest, *src;	__u16 destp, srcp;	int ttd = tw->ttd - jiffies;	if (ttd < 0)		ttd = 0;	dest  = &tw->v6_daddr;	src   = &tw->v6_rcv_saddr;	destp = ntohs(tw->dport);	srcp  = ntohs(tw->sport);	sprintf(tmpbuf,		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "		"%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p",		i,		src->s6_addr32[0], src->s6_addr32[1],		src->s6_addr32[2], src->s6_addr32[3], srcp,		dest->s6_addr32[0], dest->s6_addr32[1],		dest->s6_addr32[2], dest->s6_addr32[3], destp,		tw->substate, 0, 0,		3, ttd, 0, 0, 0, 0,		atomic_read(&tw->refcnt), tw);}#define LINE_LEN 190#define LINE_FMT "%-190s\n"int tcp6_get_info(char *buffer, char **start, off_t offset, int length){	int len = 0, num = 0, i;	off_t begin, pos = 0;	char tmpbuf[LINE_LEN+2];	if (offset < LINE_LEN+1)		len += sprintf(buffer, LINE_FMT,			       "  sl  "						/* 6 */			       "local_address                         "		/* 38 */			       "remote_address                        "		/* 38 */			       "st tx_queue rx_queue tr tm->when retrnsmt"	/* 41 */			       "   uid  timeout inode");			/* 21 */										/*----*/										/*144 */	pos = LINE_LEN+1;	/* First, walk listening socket table. */	tcp_listen_lock();	for(i = 0; i < TCP_LHTABLE_SIZE; i++) {		struct sock *sk = tcp_listening_hash[i];		struct tcp_listen_opt *lopt;		int k;		for (sk = tcp_listening_hash[i]; sk; sk = sk->next, num++) {			struct open_request *req;			int uid;			struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);			if (sk->family != PF_INET6)				continue;			pos += LINE_LEN+1;			if (pos >= offset) {				get_tcp6_sock(sk, tmpbuf, num);				len += sprintf(buffer+len, LINE_FMT, tmpbuf);				if (pos >= offset + length) {					tcp_listen_unlock();					goto out_no_bh;				}			}			uid = sock_i_uid(sk);			read_lock_bh(&tp->syn_wait_lock);			lopt = tp->listen_opt;			if (lopt && lopt->qlen != 0) {				for (k=0; k<TCP_SYNQ_HSIZE; k++) {					for (req = lopt->syn_table[k]; req; req = req->dl_next, num++) {						if (req->class->family != PF_INET6)							continue;						pos += LINE_LEN+1;						if (pos <= offset)							continue;						get_openreq6(sk, req, tmpbuf, num, uid);						len += sprintf(buffer+len, LINE_FMT, tmpbuf);						if (pos >= offset + length) { 							read_unlock_bh(&tp->syn_wait_lock);							tcp_listen_unlock();							goto out_no_bh;						}					}				}			}			read_unlock_bh(&tp->syn_wait_lock);			/* Completed requests are in normal socket hash table */		}	}	tcp_listen_unlock();	local_bh_disable();	/* Next, walk established hash chain. */	for (i = 0; i < tcp_ehash_size; i++) {		struct tcp_ehash_bucket *head = &tcp_ehash[i];		struct sock *sk;		struct tcp_tw_bucket *tw;		read_lock(&head->lock);		for(sk = head->chain; sk; sk = sk->next, num++) {			if (sk->family != PF_INET6)				continue;			pos += LINE_LEN+1;			if (pos <= offset)				continue;			get_tcp6_sock(sk, tmpbuf, num);			len += sprintf(buffer+len, LINE_FMT, tmpbuf);			if (pos >= offset + length) {				read_unlock(&head->lock);				goto out;			}		}		for (tw = (struct tcp_tw_bucket *)tcp_ehash[i+tcp_ehash_size].chain;		     tw != NULL;		     tw = (struct tcp_tw_bucket *)tw->next, num++) {			if (tw->family != PF_INET6)				continue;			pos += LINE_LEN+1;			if (pos <= offset)				continue;			get_timewait6_sock(tw, tmpbuf, num);			len += sprintf(buffer+len, LINE_FMT, tmpbuf);			if (pos >= offset + length) {				read_unlock(&head->lock);				goto out;			}		}		read_unlock(&head->lock);	}out:	local_bh_enable();out_no_bh:	begin = len - (pos - offset);	*start = buffer + begin;	len -= begin;	if (len > length)		len = length;	if (len < 0)		len = 0; 	return len;}struct proto tcpv6_prot = {	name:		"TCPv6",	close:		tcp_close,	connect:	tcp_v6_connect,	disconnect:	tcp_disconnect,	accept:		tcp_accept,	ioctl:		tcp_ioctl,	init:		tcp_v6_init_sock,	destroy:	tcp_v6_destroy_sock,	shutdown:	tcp_shutdown,	setsockopt:	tcp_setsockopt,	getsockopt:	tcp_getsockopt,	sendmsg:	tcp_sendmsg,	recvmsg:	tcp_recvmsg,	backlog_rcv:	tcp_v6_do_rcv,	hash:		tcp_v6_hash,	unhash:		tcp_unhash,	get_port:	tcp_v6_get_port,};static struct inet6_protocol tcpv6_protocol ={	tcp_v6_rcv,		/* TCP handler		*/	tcp_v6_err,		/* TCP error control	*/	NULL,			/* next			*/	IPPROTO_TCP,		/* protocol ID		*/	0,			/* copy			*/	NULL,			/* data			*/	"TCPv6"			/* name			*/};extern struct proto_ops inet6_stream_ops;static struct inet_protosw tcpv6_protosw = {	type:        SOCK_STREAM,	protocol:    IPPROTO_TCP,	prot:        &tcpv6_prot,	ops:         &inet6_stream_ops,	capability:  -1,	no_check:    0,	flags:       INET_PROTOSW_PERMANENT,};void __init tcpv6_init(void){	/* register inet6 protocol */	inet6_add_protocol(&tcpv6_protocol);	inet6_register_protosw(&tcpv6_protosw);}

⌨️ 快捷键说明

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