📄 tcp_ipv4.c
字号:
if (tp->bind_hash) tcp_put_port(sk); /* * If sendmsg cached page exists, toss it. */ if (sk->sk_sndmsg_page) { __free_page(sk->sk_sndmsg_page); sk->sk_sndmsg_page = NULL; } atomic_dec(&tcp_sockets_allocated); return 0;}EXPORT_SYMBOL(tcp_v4_destroy_sock);#ifdef CONFIG_PROC_FS/* Proc filesystem TCP sock list dumping. */static inline struct tcp_tw_bucket *tw_head(struct hlist_head *head){ return hlist_empty(head) ? NULL : list_entry(head->first, struct tcp_tw_bucket, tw_node);}static inline struct tcp_tw_bucket *tw_next(struct tcp_tw_bucket *tw){ return tw->tw_node.next ? hlist_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL;}static void *listening_get_next(struct seq_file *seq, void *cur){ struct tcp_opt *tp; struct hlist_node *node; struct sock *sk = cur; struct tcp_iter_state* st = seq->private; if (!sk) { st->bucket = 0; sk = sk_head(&tcp_listening_hash[0]); goto get_sk; } ++st->num; if (st->state == TCP_SEQ_STATE_OPENREQ) { struct open_request *req = cur; tp = tcp_sk(st->syn_wait_sk); req = req->dl_next; while (1) { while (req) { if (req->class->family == st->family) { cur = req; goto out; } req = req->dl_next; } if (++st->sbucket >= TCP_SYNQ_HSIZE) break;get_req: req = tp->listen_opt->syn_table[st->sbucket]; } sk = sk_next(st->syn_wait_sk); st->state = TCP_SEQ_STATE_LISTENING; read_unlock_bh(&tp->syn_wait_lock); } else { tp = tcp_sk(sk); read_lock_bh(&tp->syn_wait_lock); if (tp->listen_opt && tp->listen_opt->qlen) goto start_req; read_unlock_bh(&tp->syn_wait_lock); sk = sk_next(sk); }get_sk: sk_for_each_from(sk, node) { if (sk->sk_family == st->family) { cur = sk; goto out; } tp = tcp_sk(sk); read_lock_bh(&tp->syn_wait_lock); if (tp->listen_opt && tp->listen_opt->qlen) {start_req: st->uid = sock_i_uid(sk); st->syn_wait_sk = sk; st->state = TCP_SEQ_STATE_OPENREQ; st->sbucket = 0; goto get_req; } read_unlock_bh(&tp->syn_wait_lock); } if (++st->bucket < TCP_LHTABLE_SIZE) { sk = sk_head(&tcp_listening_hash[st->bucket]); goto get_sk; } cur = NULL;out: return cur;}static void *listening_get_idx(struct seq_file *seq, loff_t *pos){ void *rc = listening_get_next(seq, NULL); while (rc && *pos) { rc = listening_get_next(seq, rc); --*pos; } return rc;}static void *established_get_first(struct seq_file *seq){ struct tcp_iter_state* st = seq->private; void *rc = NULL; for (st->bucket = 0; st->bucket < tcp_ehash_size; ++st->bucket) { struct sock *sk; struct hlist_node *node; struct tcp_tw_bucket *tw; read_lock(&tcp_ehash[st->bucket].lock); sk_for_each(sk, node, &tcp_ehash[st->bucket].chain) { if (sk->sk_family != st->family) { continue; } rc = sk; goto out; } st->state = TCP_SEQ_STATE_TIME_WAIT; tw_for_each(tw, node, &tcp_ehash[st->bucket + tcp_ehash_size].chain) { if (tw->tw_family != st->family) { continue; } rc = tw; goto out; } read_unlock(&tcp_ehash[st->bucket].lock); st->state = TCP_SEQ_STATE_ESTABLISHED; }out: return rc;}static void *established_get_next(struct seq_file *seq, void *cur){ struct sock *sk = cur; struct tcp_tw_bucket *tw; struct hlist_node *node; struct tcp_iter_state* st = seq->private; ++st->num; if (st->state == TCP_SEQ_STATE_TIME_WAIT) { tw = cur; tw = tw_next(tw);get_tw: while (tw && tw->tw_family != st->family) { tw = tw_next(tw); } if (tw) { cur = tw; goto out; } read_unlock(&tcp_ehash[st->bucket].lock); st->state = TCP_SEQ_STATE_ESTABLISHED; if (++st->bucket < tcp_ehash_size) { read_lock(&tcp_ehash[st->bucket].lock); sk = sk_head(&tcp_ehash[st->bucket].chain); } else { cur = NULL; goto out; } } else sk = sk_next(sk); sk_for_each_from(sk, node) { if (sk->sk_family == st->family) goto found; } st->state = TCP_SEQ_STATE_TIME_WAIT; tw = tw_head(&tcp_ehash[st->bucket + tcp_ehash_size].chain); goto get_tw;found: cur = sk;out: return cur;}static void *established_get_idx(struct seq_file *seq, loff_t pos){ void *rc = established_get_first(seq); while (rc && pos) { rc = established_get_next(seq, rc); --pos; } return rc;}static void *tcp_get_idx(struct seq_file *seq, loff_t pos){ void *rc; struct tcp_iter_state* st = seq->private; tcp_listen_lock(); st->state = TCP_SEQ_STATE_LISTENING; rc = listening_get_idx(seq, &pos); if (!rc) { tcp_listen_unlock(); local_bh_disable(); st->state = TCP_SEQ_STATE_ESTABLISHED; rc = established_get_idx(seq, pos); } return rc;}static void *tcp_seq_start(struct seq_file *seq, loff_t *pos){ struct tcp_iter_state* st = seq->private; st->state = TCP_SEQ_STATE_LISTENING; st->num = 0; return *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;}static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos){ void *rc = NULL; struct tcp_iter_state* st; if (v == SEQ_START_TOKEN) { rc = tcp_get_idx(seq, 0); goto out; } st = seq->private; switch (st->state) { case TCP_SEQ_STATE_OPENREQ: case TCP_SEQ_STATE_LISTENING: rc = listening_get_next(seq, v); if (!rc) { tcp_listen_unlock(); local_bh_disable(); st->state = TCP_SEQ_STATE_ESTABLISHED; rc = established_get_first(seq); } break; case TCP_SEQ_STATE_ESTABLISHED: case TCP_SEQ_STATE_TIME_WAIT: rc = established_get_next(seq, v); break; }out: ++*pos; return rc;}static void tcp_seq_stop(struct seq_file *seq, void *v){ struct tcp_iter_state* st = seq->private; switch (st->state) { case TCP_SEQ_STATE_OPENREQ: if (v) { struct tcp_opt *tp = tcp_sk(st->syn_wait_sk); read_unlock_bh(&tp->syn_wait_lock); } case TCP_SEQ_STATE_LISTENING: if (v != SEQ_START_TOKEN) tcp_listen_unlock(); break; case TCP_SEQ_STATE_TIME_WAIT: case TCP_SEQ_STATE_ESTABLISHED: if (v) read_unlock(&tcp_ehash[st->bucket].lock); local_bh_enable(); break; }}static int tcp_seq_open(struct inode *inode, struct file *file){ struct tcp_seq_afinfo *afinfo = PDE(inode)->data; struct seq_file *seq; struct tcp_iter_state *s; int rc; if (unlikely(afinfo == NULL)) return -EINVAL; s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) return -ENOMEM; memset(s, 0, sizeof(*s)); s->family = afinfo->family; s->seq_ops.start = tcp_seq_start; s->seq_ops.next = tcp_seq_next; s->seq_ops.show = afinfo->seq_show; s->seq_ops.stop = tcp_seq_stop; rc = seq_open(file, &s->seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = s;out: return rc;out_kfree: kfree(s); goto out;}int tcp_proc_register(struct tcp_seq_afinfo *afinfo){ int rc = 0; struct proc_dir_entry *p; if (!afinfo) return -EINVAL; afinfo->seq_fops->owner = afinfo->owner; afinfo->seq_fops->open = tcp_seq_open; afinfo->seq_fops->read = seq_read; afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = seq_release_private; p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; else rc = -ENOMEM; return rc;}void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo){ if (!afinfo) return; proc_net_remove(afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); }static void get_openreq4(struct sock *sk, struct open_request *req, char *tmpbuf, int i, int uid){ int ttd = req->expires - jiffies; sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p", i, req->af.v4_req.loc_addr, ntohs(inet_sk(sk)->sport), req->af.v4_req.rmt_addr, 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 */ atomic_read(&sk->sk_refcnt), req);}static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i){ int timer_active; unsigned long timer_expires; struct tcp_opt *tp = tcp_sk(sp); struct inet_opt *inet = inet_sk(sp); unsigned int dest = inet->daddr; unsigned int src = inet->rcv_saddr; __u16 destp = ntohs(inet->dport); __u16 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; } sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " "%08X %5d %8d %lu %d %p %u %u %u %u %d", i, src, srcp, dest, 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_timewait4_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i){ unsigned int dest, src; __u16 destp, srcp; int ttd = tw->tw_ttd - jiffies; if (ttd < 0) ttd = 0; dest = tw->tw_daddr; src = tw->tw_rcv_saddr; destp = ntohs(tw->tw_dport); srcp = ntohs(tw->tw_sport); sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p", i, src, srcp, dest, destp, tw->tw_substate, 0, 0, 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0, atomic_read(&tw->tw_refcnt), tw);}#define TMPSZ 150static int tcp4_seq_show(struct seq_file *seq, void *v){ struct tcp_iter_state* st; char tmpbuf[TMPSZ + 1]; if (v == SEQ_START_TOKEN) { seq_printf(seq, "%-*s\n", TMPSZ - 1, " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout " "inode"); goto out; } st = seq->private; switch (st->state) { case TCP_SEQ_STATE_LISTENING: case TCP_SEQ_STATE_ESTABLISHED: get_tcp4_sock(v, tmpbuf, st->num); break; case TCP_SEQ_STATE_OPENREQ: get_openreq4(st->syn_wait_sk, v, tmpbuf, st->num, st->uid); break; case TCP_SEQ_STATE_TIME_WAIT: get_timewait4_sock(v, tmpbuf, st->num); break; } seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf);out: return 0;}static struct file_operations tcp4_seq_fops;static struct tcp_seq_afinfo tcp4_seq_afinfo = { .owner = THIS_MODULE, .name = "tcp", .family = AF_INET, .seq_show = tcp4_seq_show, .seq_fops = &tcp4_seq_fops,};int __init tcp4_proc_init(void){ return tcp_proc_register(&tcp4_seq_afinfo);}void tcp4_proc_exit(void){ tcp_proc_unregister(&tcp4_seq_afinfo);}#endif /* CONFIG_PROC_FS */struct proto tcp_prot = { .name = "TCP", .close = tcp_close, .connect = tcp_v4_connect, .disconnect = tcp_disconnect, .accept = tcp_accept, .ioctl = tcp_ioctl, .init = tcp_v4_init_sock, .destroy = tcp_v4_destroy_sock, .shutdown = tcp_shutdown, .setsockopt = tcp_setsockopt, .getsockopt = tcp_getsockopt, .sendmsg = tcp_sendmsg, .recvmsg = tcp_recvmsg, .backlog_rcv = tcp_v4_do_rcv, .hash = tcp_v4_hash, .unhash = tcp_unhash, .get_port = tcp_v4_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 tcp_sock),};void __init tcp_v4_init(struct net_proto_family *ops){ int err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket); if (err < 0) panic("Failed to create the TCP control socket.\n"); tcp_socket->sk->sk_allocation = GFP_ATOMIC; inet_sk(tcp_socket->sk)->
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -