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