Skip to content
Snippets Groups Projects
tcp_ipv4.c 55.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Linus Torvalds's avatar
    Linus Torvalds committed
    
    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 request_sock *req,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			 char *tmpbuf, int i, int uid)
    {
    
    	const struct inet_request_sock *ireq = inet_rsk(req);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int ttd = req->expires - jiffies;
    
    	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
    		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p",
    		i,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		ntohs(inet_sk(sk)->sport),
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		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_sock *tp = tcp_sk(sp);
    	struct inet_sock *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 inet_timewait_sock *tw, char *tmpbuf, int i)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	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 150
    
    static 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",
    	.owner			= THIS_MODULE,
    	.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,
    	.obj_size		= sizeof(struct tcp_sock),
    
    	.twsk_obj_size		= sizeof(struct tcp_timewait_sock),
    
    	.rsk_prot		= &tcp_request_sock_ops,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    };
    
    
    
    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)->uc_ttl = -1;
    
    	/* Unhash it so that IP input processing does not even
    	 * see it, we do not wish this socket to see incoming
    	 * packets.
    	 */
    	tcp_socket->sk->sk_prot->unhash(tcp_socket->sk);
    }
    
    EXPORT_SYMBOL(ipv4_specific);
    
    EXPORT_SYMBOL(inet_bind_bucket_create);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    EXPORT_SYMBOL(tcp_hashinfo);
    EXPORT_SYMBOL(tcp_prot);
    EXPORT_SYMBOL(tcp_unhash);
    EXPORT_SYMBOL(tcp_v4_conn_request);
    EXPORT_SYMBOL(tcp_v4_connect);
    EXPORT_SYMBOL(tcp_v4_do_rcv);
    EXPORT_SYMBOL(tcp_v4_remember_stamp);
    EXPORT_SYMBOL(tcp_v4_send_check);
    EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
    
    #ifdef CONFIG_PROC_FS
    EXPORT_SYMBOL(tcp_proc_register);
    EXPORT_SYMBOL(tcp_proc_unregister);
    #endif
    EXPORT_SYMBOL(sysctl_local_port_range);
    EXPORT_SYMBOL(sysctl_tcp_low_latency);
    EXPORT_SYMBOL(sysctl_tcp_tw_reuse);