Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bca735bd authored by Vladislav Yasevich's avatar Vladislav Yasevich Committed by David S. Miller
Browse files

[SCTP] Extend the info exported via /proc/net/sctp to support netstat for SCTP.

parent 0fd9a65a
Loading
Loading
Loading
Loading
+151 −43
Original line number Original line Diff line number Diff line
@@ -132,14 +132,25 @@ void sctp_snmp_proc_exit(void)
static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
{
{
	struct list_head *pos;
	struct list_head *pos;
	struct sctp_association *asoc;
	struct sctp_sockaddr_entry *laddr;
	struct sctp_sockaddr_entry *laddr;
	union sctp_addr *addr;
	struct sctp_transport *peer;
	union sctp_addr *addr, *primary = NULL;
	struct sctp_af *af;
	struct sctp_af *af;


	if (epb->type == SCTP_EP_TYPE_ASSOCIATION) {
	    asoc = sctp_assoc(epb);
	    peer = asoc->peer.primary_path;
	    primary = &peer->saddr;
	}

	list_for_each(pos, &epb->bind_addr.address_list) {
	list_for_each(pos, &epb->bind_addr.address_list) {
		laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
		laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
		addr = (union sctp_addr *)&laddr->a;
		addr = (union sctp_addr *)&laddr->a;
		af = sctp_get_af_specific(addr->sa.sa_family);
		af = sctp_get_af_specific(addr->sa.sa_family);
		if (primary && af->cmp_addr(addr, primary)) {
			seq_printf(seq, "*");
		}
		af->seq_dump_addr(seq, addr);
		af->seq_dump_addr(seq, addr);
	}
	}
}
}
@@ -149,17 +160,54 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa
{
{
	struct list_head *pos;
	struct list_head *pos;
	struct sctp_transport *transport;
	struct sctp_transport *transport;
	union sctp_addr *addr;
	union sctp_addr *addr, *primary;
	struct sctp_af *af;
	struct sctp_af *af;


	primary = &(assoc->peer.primary_addr);
	list_for_each(pos, &assoc->peer.transport_addr_list) {
	list_for_each(pos, &assoc->peer.transport_addr_list) {
		transport = list_entry(pos, struct sctp_transport, transports);
		transport = list_entry(pos, struct sctp_transport, transports);
		addr = (union sctp_addr *)&transport->ipaddr;
		addr = (union sctp_addr *)&transport->ipaddr;
		af = sctp_get_af_specific(addr->sa.sa_family);
		af = sctp_get_af_specific(addr->sa.sa_family);
		if (af->cmp_addr(addr, primary)) {
			seq_printf(seq, "*");
		}
		af->seq_dump_addr(seq, addr);
		af->seq_dump_addr(seq, addr);
	}
	}
}
}


static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
{
	if (*pos > sctp_ep_hashsize)
		return NULL;

	if (*pos < 0)
		*pos = 0;

	if (*pos == 0)
		seq_printf(seq, " ENDPT     SOCK   STY SST HBKT LPORT   UID INODE LADDRS\n");

	++*pos;

	return (void *)pos;
}

static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
{
	return;
}


static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
	if (*pos > sctp_ep_hashsize)
		return NULL;

	++*pos;

	return pos;
}


/* Display sctp endpoints (/proc/net/sctp/eps). */
/* Display sctp endpoints (/proc/net/sctp/eps). */
static int sctp_eps_seq_show(struct seq_file *seq, void *v)
static int sctp_eps_seq_show(struct seq_file *seq, void *v)
{
{
@@ -167,38 +215,50 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
	struct sctp_ep_common *epb;
	struct sctp_ep_common *epb;
	struct sctp_endpoint *ep;
	struct sctp_endpoint *ep;
	struct sock *sk;
	struct sock *sk;
	int hash;
	int    hash = *(int *)v;


	seq_printf(seq, " ENDPT     SOCK   STY SST HBKT LPORT LADDRS\n");
	if (hash > sctp_ep_hashsize)
	for (hash = 0; hash < sctp_ep_hashsize; hash++) {
		return -ENOMEM;
		head = &sctp_ep_hashtable[hash];

	head = &sctp_ep_hashtable[hash-1];
	sctp_local_bh_disable();
	read_lock(&head->lock);
	read_lock(&head->lock);
	for (epb = head->chain; epb; epb = epb->next) {
	for (epb = head->chain; epb; epb = epb->next) {
		ep = sctp_ep(epb);
		ep = sctp_ep(epb);
		sk = epb->sk;
		sk = epb->sk;
			seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d ", ep, sk,
		seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
				   sctp_sk(sk)->type, sk->sk_state, hash,
			   sctp_sk(sk)->type, sk->sk_state, hash-1,
				   epb->bind_addr.port);
			   epb->bind_addr.port,
			   sock_i_uid(sk), sock_i_ino(sk));

		sctp_seq_dump_local_addrs(seq, epb);
		sctp_seq_dump_local_addrs(seq, epb);
		seq_printf(seq, "\n");
		seq_printf(seq, "\n");
	}
	}
	read_unlock(&head->lock);
	read_unlock(&head->lock);
	}
	sctp_local_bh_enable();


	return 0;
	return 0;
}
}


static struct seq_operations sctp_eps_ops = {
	.start = sctp_eps_seq_start,
	.next  = sctp_eps_seq_next,
	.stop  = sctp_eps_seq_stop,
	.show  = sctp_eps_seq_show,
};


/* Initialize the seq file operations for 'eps' object. */
/* Initialize the seq file operations for 'eps' object. */
static int sctp_eps_seq_open(struct inode *inode, struct file *file)
static int sctp_eps_seq_open(struct inode *inode, struct file *file)
{
{
	return single_open(file, sctp_eps_seq_show, NULL);
	return seq_open(file, &sctp_eps_ops);
}
}


static struct file_operations sctp_eps_seq_fops = {
static struct file_operations sctp_eps_seq_fops = {
	.open	 = sctp_eps_seq_open,
	.open	 = sctp_eps_seq_open,
	.read	 = seq_read,
	.read	 = seq_read,
	.llseek	 = seq_lseek,
	.llseek	 = seq_lseek,
	.release = single_release,
	.release = seq_release,
};
};


/* Set up the proc fs entry for 'eps' object. */
/* Set up the proc fs entry for 'eps' object. */
@@ -221,6 +281,40 @@ void sctp_eps_proc_exit(void)
	remove_proc_entry("eps", proc_net_sctp);
	remove_proc_entry("eps", proc_net_sctp);
}
}



static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
{
	if (*pos > sctp_assoc_hashsize)
		return NULL;

	if (*pos < 0)
		*pos = 0;

	if (*pos == 0)
		seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
				"RPORT LADDRS <-> RADDRS\n");

	++*pos;

	return (void *)pos;
}

static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
{
	return;
}


static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
	if (*pos > sctp_assoc_hashsize)
		return NULL;

	++*pos;

	return pos;
}

/* Display sctp associations (/proc/net/sctp/assocs). */
/* Display sctp associations (/proc/net/sctp/assocs). */
static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
{
{
@@ -228,43 +322,57 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
	struct sctp_ep_common *epb;
	struct sctp_ep_common *epb;
	struct sctp_association *assoc;
	struct sctp_association *assoc;
	struct sock *sk;
	struct sock *sk;
	int hash;
	int    hash = *(int *)v;


	seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT LPORT RPORT "
	if (hash > sctp_assoc_hashsize)
			"LADDRS <-> RADDRS\n");
		return -ENOMEM;
	for (hash = 0; hash < sctp_assoc_hashsize; hash++) {

		head = &sctp_assoc_hashtable[hash];
	head = &sctp_assoc_hashtable[hash-1];
	sctp_local_bh_disable();
	read_lock(&head->lock);
	read_lock(&head->lock);
	for (epb = head->chain; epb; epb = epb->next) {
	for (epb = head->chain; epb; epb = epb->next) {
		assoc = sctp_assoc(epb);
		assoc = sctp_assoc(epb);
		sk = epb->sk;
		sk = epb->sk;
		seq_printf(seq,
		seq_printf(seq,
				   "%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d ",
			   "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
			   assoc, sk, sctp_sk(sk)->type, sk->sk_state,
			   assoc, sk, sctp_sk(sk)->type, sk->sk_state,
				   assoc->state, hash, epb->bind_addr.port,
			   assoc->state, hash-1, assoc->assoc_id,
			   (sk->sk_rcvbuf - assoc->rwnd),
			   assoc->sndbuf_used,
			   sock_i_uid(sk), sock_i_ino(sk),
			   epb->bind_addr.port,
			   assoc->peer.port);
			   assoc->peer.port);

		seq_printf(seq, " ");
		sctp_seq_dump_local_addrs(seq, epb);
		sctp_seq_dump_local_addrs(seq, epb);
		seq_printf(seq, "<-> ");
		seq_printf(seq, "<-> ");
		sctp_seq_dump_remote_addrs(seq, assoc);
		sctp_seq_dump_remote_addrs(seq, assoc);
		seq_printf(seq, "\n");
		seq_printf(seq, "\n");
	}
	}
	read_unlock(&head->lock);
	read_unlock(&head->lock);
	}
	sctp_local_bh_enable();


	return 0;
	return 0;
}
}


static struct seq_operations sctp_assoc_ops = {
	.start = sctp_assocs_seq_start,
	.next  = sctp_assocs_seq_next,
	.stop  = sctp_assocs_seq_stop,
	.show  = sctp_assocs_seq_show,
};

/* Initialize the seq file operations for 'assocs' object. */
/* Initialize the seq file operations for 'assocs' object. */
static int sctp_assocs_seq_open(struct inode *inode, struct file *file)
static int sctp_assocs_seq_open(struct inode *inode, struct file *file)
{
{
	return single_open(file, sctp_assocs_seq_show, NULL);
	return seq_open(file, &sctp_assoc_ops);
}
}


static struct file_operations sctp_assocs_seq_fops = {
static struct file_operations sctp_assocs_seq_fops = {
	.open	 = sctp_assocs_seq_open,
	.open	 = sctp_assocs_seq_open,
	.read	 = seq_read,
	.read	 = seq_read,
	.llseek	 = seq_lseek,
	.llseek	 = seq_lseek,
	.release = single_release,
	.release = seq_release,
};
};


/* Set up the proc fs entry for 'assocs' object. */
/* Set up the proc fs entry for 'assocs' object. */