📄 tcp_ipv6.c
字号:
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 + -