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

📄 tcp_ipv6.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (th->doff < sizeof(struct tcphdr)/4)		goto bad_packet;	if (!pskb_may_pull(skb, th->doff*4))		goto discard_it;	if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&	     tcp_v6_checksum_init(skb) < 0))		goto bad_packet;	th = skb->h.th;	TCP_SKB_CB(skb)->seq = ntohl(th->seq);	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +				    skb->len - th->doff*4);	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);	TCP_SKB_CB(skb)->when = 0;	TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h);	TCP_SKB_CB(skb)->sacked = 0;	sk = __tcp_v6_lookup(&skb->nh.ipv6h->saddr, th->source,			     &skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb));	if (!sk)		goto no_tcp_socket;process:	if (sk->sk_state == TCP_TIME_WAIT)		goto do_time_wait;	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))		goto discard_and_relse;	if (sk_filter(sk, skb, 0))		goto discard_and_relse;	skb->dev = NULL;	bh_lock_sock(sk);	ret = 0;	if (!sock_owned_by_user(sk)) {		if (!tcp_prequeue(sk, skb))			ret = tcp_v6_do_rcv(sk, skb);	} else		sk_add_backlog(sk, skb);	bh_unlock_sock(sk);	sock_put(sk);	return ret ? -1 : 0;no_tcp_socket:	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))		goto discard_it;	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {bad_packet:		TCP_INC_STATS_BH(TCP_MIB_INERRS);	} else {		tcp_v6_send_reset(skb);	}discard_it:	/*	 *	Discard frame	 */	kfree_skb(skb);	return 0;discard_and_relse:	sock_put(sk);	goto discard_it;do_time_wait:	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {		tcp_tw_put((struct tcp_tw_bucket *) sk);		goto discard_it;	}	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {		TCP_INC_STATS_BH(TCP_MIB_INERRS);		tcp_tw_put((struct tcp_tw_bucket *) 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_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 = inet6_sk(sk);	dst = __sk_dst_check(sk, np->dst_cookie);	if (dst == NULL) {		struct inet_opt *inet = inet_sk(sk);		struct in6_addr *final_p = NULL, final;		struct flowi fl;		memset(&fl, 0, sizeof(fl));		fl.proto = IPPROTO_TCP;		ipv6_addr_copy(&fl.fl6_dst, &np->daddr);		ipv6_addr_copy(&fl.fl6_src, &np->saddr);		fl.fl6_flowlabel = np->flow_label;		fl.oif = sk->sk_bound_dev_if;		fl.fl_ip_dport = inet->dport;		fl.fl_ip_sport = inet->sport;		if (np->opt && np->opt->srcrt) {			struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;			ipv6_addr_copy(&final, &fl.fl6_dst);			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);			final_p = &final;		}		err = ip6_dst_lookup(sk, &dst, &fl);		if (err) {			sk->sk_route_caps = 0;			return err;		}		if (final_p)			ipv6_addr_copy(&fl.fl6_dst, final_p);		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {			sk->sk_err_soft = -err;			dst_release(dst);			return err;		}		ip6_dst_store(sk, dst, NULL);		sk->sk_route_caps = dst->dev->features &			~(NETIF_F_IP_CSUM | NETIF_F_TSO);		tcp_sk(sk)->ext2_header_len = dst->header_len;	}	return 0;}static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok){	struct sock *sk = skb->sk;	struct inet_opt *inet = inet_sk(sk);	struct ipv6_pinfo *np = inet6_sk(sk);	struct flowi fl;	struct dst_entry *dst;	memset(&fl, 0, sizeof(fl));	fl.proto = IPPROTO_TCP;	ipv6_addr_copy(&fl.fl6_dst, &np->daddr);	ipv6_addr_copy(&fl.fl6_src, &np->saddr);	fl.fl6_flowlabel = np->flow_label;	IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);	fl.oif = sk->sk_bound_dev_if;	fl.fl_ip_sport = inet->sport;	fl.fl_ip_dport = inet->dport;	if (np->opt && np->opt->srcrt) {		struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);	}	dst = __sk_dst_check(sk, np->dst_cookie);	if (dst == NULL) {		int err = ip6_dst_lookup(sk, &dst, &fl);		if (err) {			sk->sk_err_soft = -err;			return err;		}		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {			sk->sk_route_caps = 0;			dst_release(dst);			return err;		}		ip6_dst_store(sk, dst, NULL);		sk->sk_route_caps = dst->dev->features &			~(NETIF_F_IP_CSUM | NETIF_F_TSO);		tcp_sk(sk)->ext2_header_len = dst->header_len;	}	skb->dst = dst_clone(dst);	/* Restore final destination back after routing done */	ipv6_addr_copy(&fl.fl6_dst, &np->daddr);	return ip6_xmit(sk, skb, &fl, np->opt, 0);}static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr){	struct ipv6_pinfo *np = inet6_sk(sk);	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;	sin6->sin6_family = AF_INET6;	ipv6_addr_copy(&sin6->sin6_addr, &np->daddr);	sin6->sin6_port	= inet_sk(sk)->dport;	/* We do not store received flowlabel for TCP */	sin6->sin6_flowinfo = 0;	sin6->sin6_scope_id = 0;	if (sk->sk_bound_dev_if &&	    ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)		sin6->sin6_scope_id = sk->sk_bound_dev_if;}static int tcp_v6_remember_stamp(struct sock *sk){	/* Alas, not yet... */	return 0;}static struct tcp_func ipv6_specific = {	.queue_xmit	=	tcp_v6_xmit,	.send_check	=	tcp_v6_send_check,	.rebuild_header	=	tcp_v6_rebuild_header,	.conn_request	=	tcp_v6_conn_request,	.syn_recv_sock	=	tcp_v6_syn_recv_sock,	.remember_stamp	=	tcp_v6_remember_stamp,	.net_header_len	=	sizeof(struct ipv6hdr),	.setsockopt	=	ipv6_setsockopt,	.getsockopt	=	ipv6_getsockopt,	.addr2sockaddr	=	v6_addr2sockaddr,	.sockaddr_len	=	sizeof(struct sockaddr_in6)};/* *	TCP over IPv4 via INET6 API */static struct tcp_func ipv6_mapped = {	.queue_xmit	=	ip_queue_xmit,	.send_check	=	tcp_v4_send_check,	.rebuild_header	=	tcp_v4_rebuild_header,	.conn_request	=	tcp_v6_conn_request,	.syn_recv_sock	=	tcp_v6_syn_recv_sock,	.remember_stamp	=	tcp_v4_remember_stamp,	.net_header_len	=	sizeof(struct iphdr),	.setsockopt	=	ipv6_setsockopt,	.getsockopt	=	ipv6_getsockopt,	.addr2sockaddr	=	v6_addr2sockaddr,	.sockaddr_len	=	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 = tcp_sk(sk);	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_std = tp->mss_cache = 536;	tp->reordering = sysctl_tcp_reordering;	sk->sk_state = TCP_CLOSE;	tp->af_specific = &ipv6_specific;	sk->sk_write_space = sk_stream_write_space;	sk->sk_use_write_queue = 1;	sk->sk_sndbuf = sysctl_tcp_wmem[1];	sk->sk_rcvbuf = sysctl_tcp_rmem[1];	atomic_inc(&tcp_sockets_allocated);	return 0;}static int tcp_v6_destroy_sock(struct sock *sk){	extern int tcp_v4_destroy_sock(struct sock *sk);	tcp_v4_destroy_sock(sk);	return inet6_destroy_sock(sk);}/* Proc filesystem TCPv6 sock list dumping. */static void get_openreq6(struct seq_file *seq, 			 struct sock *sk, struct open_request *req, 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;	seq_printf(seq,		   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "		   "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",		   i,		   src->s6_addr32[0], src->s6_addr32[1],		   src->s6_addr32[2], src->s6_addr32[3],		   ntohs(inet_sk(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) */  		   jiffies_to_clock_t(ttd), 		   req->retrans,		   uid,		   0,  /* non standard timer */  		   0, /* open_requests have no inode */		   0, req);}static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i){	struct in6_addr *dest, *src;	__u16 destp, srcp;	int timer_active;	unsigned long timer_expires;	struct inet_opt *inet = inet_sk(sp);	struct tcp_opt *tp = tcp_sk(sp);	struct ipv6_pinfo *np = inet6_sk(sp);	dest  = &np->daddr;	src   = &np->rcv_saddr;	destp = ntohs(inet->dport);	srcp  = ntohs(inet->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->sk_timer)) {		timer_active	= 2;		timer_expires	= sp->sk_timer.expires;	} else {		timer_active	= 0;		timer_expires = jiffies;	}	seq_printf(seq,		   "%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\n",		   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->sk_state, 		   tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,		   timer_active,		   jiffies_to_clock_t(timer_expires - jiffies),		   tp->retransmits,		   sock_i_uid(sp),		   tp->probes_out,		   sock_i_ino(sp),		   atomic_read(&sp->sk_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 seq_file *seq, 			       struct tcp_tw_bucket *tw, int i){	struct in6_addr *dest, *src;	__u16 destp, srcp;	int ttd = tw->tw_ttd - jiffies;	if (ttd < 0)		ttd = 0;	dest  = &tw->tw_v6_daddr;	src   = &tw->tw_v6_rcv_saddr;	destp = ntohs(tw->tw_dport);	srcp  = ntohs(tw->tw_sport);	seq_printf(seq,		   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "		   "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",		   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->tw_substate, 0, 0,		   3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,		   atomic_read(&tw->tw_refcnt), tw);}#ifdef CONFIG_PROC_FSstatic int tcp6_seq_show(struct seq_file *seq, void *v){	struct tcp_iter_state *st;	if (v == SEQ_START_TOKEN) {		seq_puts(seq,			 "  sl  "			 "local_address                         "			 "remote_address                        "			 "st tx_queue rx_queue tr tm->when retrnsmt"			 "   uid  timeout inode\n");		goto out;	}	st = seq->private;	switch (st->state) {	case TCP_SEQ_STATE_LISTENING:	case TCP_SEQ_STATE_ESTABLISHED:		get_tcp6_sock(seq, v, st->num);		break;	case TCP_SEQ_STATE_OPENREQ:		get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);		break;	case TCP_SEQ_STATE_TIME_WAIT:		get_timewait6_sock(seq, v, st->num);		break;	}out:	return 0;}static struct file_operations tcp6_seq_fops;static struct tcp_seq_afinfo tcp6_seq_afinfo = {	.owner		= THIS_MODULE,	.name		= "tcp6",	.family		= AF_INET6,	.seq_show	= tcp6_seq_show,	.seq_fops	= &tcp6_seq_fops,};int __init tcp6_proc_init(void){	return tcp_proc_register(&tcp6_seq_afinfo);}void tcp6_proc_exit(void){	tcp_proc_unregister(&tcp6_seq_afinfo);}#endifstruct 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,	.enter_memory_pressure	= tcp_enter_memory_pressure,	.sockets_allocated	= &tcp_sockets_allocated,	.memory_allocated	= &tcp_memory_allocated,	.memory_pressure	= &tcp_memory_pressure,	.sysctl_mem		= sysctl_tcp_mem,	.sysctl_wmem		= sysctl_tcp_wmem,	.sysctl_rmem		= sysctl_tcp_rmem,	.max_header		= MAX_TCP_HEADER,	.slab_obj_size		= sizeof(struct tcp6_sock),};static struct inet6_protocol tcpv6_protocol = {	.handler	=	tcp_v6_rcv,	.err_handler	=	tcp_v6_err,	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,};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 */	if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)		printk(KERN_ERR "tcpv6_init: Could not register protocol\n");	inet6_register_protosw(&tcpv6_protosw);}

⌨️ 快捷键说明

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