diff options
Diffstat (limited to 'net/core/net-procfs.c')
| -rw-r--r-- | net/core/net-procfs.c | 38 | 
1 files changed, 34 insertions, 4 deletions
| diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c index d8b9dbabd4a4..88cc0ad7d386 100644 --- a/net/core/net-procfs.c +++ b/net/core/net-procfs.c @@ -190,12 +190,23 @@ static const struct seq_operations softnet_seq_ops = {  	.show  = softnet_seq_show,  }; -static void *ptype_get_idx(loff_t pos) +static void *ptype_get_idx(struct seq_file *seq, loff_t pos)  { +	struct list_head *ptype_list = NULL;  	struct packet_type *pt = NULL; +	struct net_device *dev;  	loff_t i = 0;  	int t; +	for_each_netdev_rcu(seq_file_net(seq), dev) { +		ptype_list = &dev->ptype_all; +		list_for_each_entry_rcu(pt, ptype_list, list) { +			if (i == pos) +				return pt; +			++i; +		} +	} +  	list_for_each_entry_rcu(pt, &ptype_all, list) {  		if (i == pos)  			return pt; @@ -216,22 +227,40 @@ static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)  	__acquires(RCU)  {  	rcu_read_lock(); -	return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN; +	return *pos ? ptype_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;  }  static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)  { +	struct net_device *dev;  	struct packet_type *pt;  	struct list_head *nxt;  	int hash;  	++*pos;  	if (v == SEQ_START_TOKEN) -		return ptype_get_idx(0); +		return ptype_get_idx(seq, 0);  	pt = v;  	nxt = pt->list.next; +	if (pt->dev) { +		if (nxt != &pt->dev->ptype_all) +			goto found; + +		dev = pt->dev; +		for_each_netdev_continue_rcu(seq_file_net(seq), dev) { +			if (!list_empty(&dev->ptype_all)) { +				nxt = dev->ptype_all.next; +				goto found; +			} +		} + +		nxt = ptype_all.next; +		goto ptype_all; +	} +  	if (pt->type == htons(ETH_P_ALL)) { +ptype_all:  		if (nxt != &ptype_all)  			goto found;  		hash = 0; @@ -260,7 +289,8 @@ static int ptype_seq_show(struct seq_file *seq, void *v)  	if (v == SEQ_START_TOKEN)  		seq_puts(seq, "Type Device      Function\n"); -	else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) { +	else if ((!pt->af_packet_net || net_eq(pt->af_packet_net, seq_file_net(seq))) && +		 (!pt->dev || net_eq(dev_net(pt->dev), seq_file_net(seq)))) {  		if (pt->type == htons(ETH_P_ALL))  			seq_puts(seq, "ALL ");  		else |