2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/******************************************************************************
* vlanproc . c VLAN Module . / proc filesystem interface .
*
* This module is completely hardware - independent and provides
* access to the router using Linux / proc filesystem .
*
* Author : Ben Greear , < greearb @ candelatech . com > coppied from wanproc . c
* by : Gene Kozin < genek @ compuserve . com >
*
* Copyright : ( c ) 1998 Ben Greear
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Jan 20 , 1998 Ben Greear Initial Version
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-05-26 14:58:31 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
2008-07-15 09:51:55 +04:00
# include <linux/errno.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
2008-07-15 09:51:55 +04:00
# include <linux/string.h>
2005-04-17 02:20:36 +04:00
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <linux/fs.h>
# include <linux/netdevice.h>
# include <linux/if_vlan.h>
2007-09-12 14:01:34 +04:00
# include <net/net_namespace.h>
2008-04-16 11:51:51 +04:00
# include <net/netns/generic.h>
2005-04-17 02:20:36 +04:00
# include "vlanproc.h"
# include "vlan.h"
/****** Function Prototypes *************************************************/
/* Methods for preparing data for reading proc entries */
static int vlan_seq_show ( struct seq_file * seq , void * v ) ;
static void * vlan_seq_start ( struct seq_file * seq , loff_t * pos ) ;
static void * vlan_seq_next ( struct seq_file * seq , void * v , loff_t * pos ) ;
static void vlan_seq_stop ( struct seq_file * seq , void * ) ;
static int vlandev_seq_show ( struct seq_file * seq , void * v ) ;
/*
* Global Data
*/
/*
2007-02-09 17:24:25 +03:00
* Names of the proc directory entries
2005-04-17 02:20:36 +04:00
*/
static const char name_root [ ] = " vlan " ;
static const char name_conf [ ] = " config " ;
/*
* Structures for interfacing with the / proc filesystem .
2011-03-31 05:57:33 +04:00
* VLAN creates its own directory / proc / net / vlan with the following
2005-04-17 02:20:36 +04:00
* entries :
* config device status / configuration
* < device > entry for each device
*/
/*
2007-02-09 17:24:25 +03:00
* Generic / proc / net / vlan / < file > file and inode operations
2005-04-17 02:20:36 +04:00
*/
2007-07-11 10:07:31 +04:00
static const struct seq_operations vlan_seq_ops = {
2005-04-17 02:20:36 +04:00
. start = vlan_seq_start ,
. next = vlan_seq_next ,
. stop = vlan_seq_stop ,
. show = vlan_seq_show ,
} ;
/*
2012-09-01 21:31:09 +04:00
* Proc filesystem directory entries .
2005-04-17 02:20:36 +04:00
*/
/* Strings */
2009-08-05 21:42:58 +04:00
static const char * const vlan_name_type_str [ VLAN_NAME_TYPE_HIGHEST ] = {
2008-01-21 11:26:41 +03:00
[ VLAN_NAME_TYPE_RAW_PLUS_VID ] = " VLAN_NAME_TYPE_RAW_PLUS_VID " ,
[ VLAN_NAME_TYPE_PLUS_VID_NO_PAD ] = " VLAN_NAME_TYPE_PLUS_VID_NO_PAD " ,
[ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD ] = " VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD " ,
[ VLAN_NAME_TYPE_PLUS_VID ] = " VLAN_NAME_TYPE_PLUS_VID " ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Interface functions
*/
/*
* Clean up / proc / net / vlan entries
*/
2008-04-16 11:51:12 +04:00
void vlan_proc_cleanup ( struct net * net )
2005-04-17 02:20:36 +04:00
{
2008-04-16 11:51:51 +04:00
struct vlan_net * vn = net_generic ( net , vlan_net_id ) ;
2008-04-16 11:51:12 +04:00
2008-04-16 11:51:51 +04:00
if ( vn - > proc_vlan_conf )
remove_proc_entry ( name_conf , vn - > proc_vlan_dir ) ;
2005-04-17 02:20:36 +04:00
2008-04-16 11:51:51 +04:00
if ( vn - > proc_vlan_dir )
2013-02-18 05:34:56 +04:00
remove_proc_entry ( name_root , net - > proc_net ) ;
2005-04-17 02:20:36 +04:00
/* Dynamically added entries should be cleaned up as their vlan_device
* is removed , so we should not have to take care of it here . . .
*/
}
/*
* Create / proc / net / vlan entries
*/
2010-01-17 06:35:32 +03:00
int __net_init vlan_proc_init ( struct net * net )
2005-04-17 02:20:36 +04:00
{
2008-04-16 11:51:51 +04:00
struct vlan_net * vn = net_generic ( net , vlan_net_id ) ;
2008-04-16 11:51:12 +04:00
2008-04-16 11:51:51 +04:00
vn - > proc_vlan_dir = proc_net_mkdir ( net , name_root , net - > proc_net ) ;
if ( ! vn - > proc_vlan_dir )
2008-01-21 11:25:15 +03:00
goto err ;
2018-04-10 20:42:55 +03:00
vn - > proc_vlan_conf = proc_create_net ( name_conf , S_IFREG | 0600 ,
vn - > proc_vlan_dir , & vlan_seq_ops ,
sizeof ( struct seq_net_private ) ) ;
2008-04-16 11:51:51 +04:00
if ( ! vn - > proc_vlan_conf )
2008-01-21 11:25:15 +03:00
goto err ;
return 0 ;
err :
2011-05-26 14:58:31 +04:00
pr_err ( " can't create entry in proc filesystem! \n " ) ;
2008-04-16 11:51:12 +04:00
vlan_proc_cleanup ( net ) ;
2005-04-17 02:20:36 +04:00
return - ENOBUFS ;
}
/*
* Add directory entry for VLAN device .
*/
2008-01-21 11:26:41 +03:00
int vlan_proc_add_dev ( struct net_device * vlandev )
2005-04-17 02:20:36 +04:00
{
2011-12-08 08:11:15 +04:00
struct vlan_dev_priv * vlan = vlan_dev_priv ( vlandev ) ;
2008-04-16 11:51:51 +04:00
struct vlan_net * vn = net_generic ( dev_net ( vlandev ) , vlan_net_id ) ;
2005-04-17 02:20:36 +04:00
2014-07-26 02:25:10 +04:00
if ( ! strcmp ( vlandev - > name , name_conf ) )
return - EINVAL ;
2018-05-15 16:57:23 +03:00
vlan - > dent = proc_create_single_data ( vlandev - > name , S_IFREG | 0600 ,
vn - > proc_vlan_dir , vlandev_seq_show , vlandev ) ;
2011-12-08 08:11:15 +04:00
if ( ! vlan - > dent )
2005-04-17 02:20:36 +04:00
return - ENOBUFS ;
return 0 ;
}
/*
* Delete directory entry for VLAN device .
*/
2016-02-18 05:29:30 +03:00
void vlan_proc_rem_dev ( struct net_device * vlandev )
2005-04-17 02:20:36 +04:00
{
/** NOTE: This will consume the memory pointed to by dent, it seems. */
2013-04-12 20:27:28 +04:00
proc_remove ( vlan_dev_priv ( vlandev ) - > dent ) ;
vlan_dev_priv ( vlandev ) - > dent = NULL ;
2005-04-17 02:20:36 +04:00
}
/****** Proc filesystem entry points ****************************************/
/*
* The following few functions build the content of / proc / net / vlan / config
*/
2007-02-09 17:24:25 +03:00
/* start read of /proc/net/vlan/config */
2005-04-17 02:20:36 +04:00
static void * vlan_seq_start ( struct seq_file * seq , loff_t * pos )
2009-11-10 10:54:48 +03:00
__acquires ( rcu )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev ;
2008-04-16 11:52:24 +04:00
struct net * net = seq_file_net ( seq ) ;
2005-04-17 02:20:36 +04:00
loff_t i = 1 ;
2009-11-10 10:54:48 +03:00
rcu_read_lock ( ) ;
2005-04-17 02:20:36 +04:00
if ( * pos = = 0 )
return SEQ_START_TOKEN ;
2007-02-09 17:24:25 +03:00
2009-11-10 10:54:48 +03:00
for_each_netdev_rcu ( net , dev ) {
2007-05-04 02:13:45 +04:00
if ( ! is_vlan_dev ( dev ) )
continue ;
if ( i + + = = * pos )
return dev ;
}
2007-02-09 17:24:25 +03:00
2007-05-04 02:13:45 +04:00
return NULL ;
2007-02-09 17:24:25 +03:00
}
2005-04-17 02:20:36 +04:00
static void * vlan_seq_next ( struct seq_file * seq , void * v , loff_t * pos )
{
2007-05-04 02:13:45 +04:00
struct net_device * dev ;
2008-04-16 11:52:24 +04:00
struct net * net = seq_file_net ( seq ) ;
2007-05-04 02:13:45 +04:00
2005-04-17 02:20:36 +04:00
+ + * pos ;
2011-06-13 20:21:26 +04:00
dev = v ;
2007-05-04 02:13:45 +04:00
if ( v = = SEQ_START_TOKEN )
2008-04-16 11:52:24 +04:00
dev = net_device_entry ( & net - > dev_base_head ) ;
2007-05-04 02:13:45 +04:00
2009-11-10 10:54:48 +03:00
for_each_netdev_continue_rcu ( net , dev ) {
2007-05-04 02:13:45 +04:00
if ( ! is_vlan_dev ( dev ) )
continue ;
return dev ;
}
return NULL ;
2005-04-17 02:20:36 +04:00
}
static void vlan_seq_stop ( struct seq_file * seq , void * v )
2009-11-10 10:54:48 +03:00
__releases ( rcu )
2005-04-17 02:20:36 +04:00
{
2009-11-10 10:54:48 +03:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
}
static int vlan_seq_show ( struct seq_file * seq , void * v )
{
2008-04-16 11:54:39 +04:00
struct net * net = seq_file_net ( seq ) ;
struct vlan_net * vn = net_generic ( net , vlan_net_id ) ;
2005-04-17 02:20:36 +04:00
if ( v = = SEQ_START_TOKEN ) {
const char * nmtype = NULL ;
seq_puts ( seq , " VLAN Dev name | VLAN ID \n " ) ;
2008-04-16 11:54:39 +04:00
if ( vn - > name_type < ARRAY_SIZE ( vlan_name_type_str ) )
nmtype = vlan_name_type_str [ vn - > name_type ] ;
2005-04-17 02:20:36 +04:00
2007-02-09 17:24:25 +03:00
seq_printf ( seq , " Name-Type: %s \n " ,
2008-01-21 11:26:41 +03:00
nmtype ? nmtype : " UNKNOWN " ) ;
2005-04-17 02:20:36 +04:00
} else {
const struct net_device * vlandev = v ;
2011-12-08 08:11:15 +04:00
const struct vlan_dev_priv * vlan = vlan_dev_priv ( vlandev ) ;
2005-04-17 02:20:36 +04:00
2007-02-09 17:24:25 +03:00
seq_printf ( seq , " %-15s| %d | %s \n " , vlandev - > name ,
2011-12-08 08:11:15 +04:00
vlan - > vlan_id , vlan - > real_dev - > name ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
static int vlandev_seq_show ( struct seq_file * seq , void * offset )
{
struct net_device * vlandev = ( struct net_device * ) seq - > private ;
2011-12-08 08:11:15 +04:00
const struct vlan_dev_priv * vlan = vlan_dev_priv ( vlandev ) ;
2010-07-08 01:58:56 +04:00
struct rtnl_link_stats64 temp ;
2010-06-08 11:19:54 +04:00
const struct rtnl_link_stats64 * stats ;
static const char fmt64 [ ] = " %30s %12llu \n " ;
2005-04-17 02:20:36 +04:00
int i ;
2008-07-08 14:22:16 +04:00
if ( ! is_vlan_dev ( vlandev ) )
2005-04-17 02:20:36 +04:00
return 0 ;
2010-07-08 01:58:56 +04:00
stats = dev_get_stats ( vlandev , & temp ) ;
2008-01-21 11:26:41 +03:00
seq_printf ( seq ,
" %s VID: %d REORDER_HDR: %i dev->priv_flags: %hx \n " ,
2011-12-08 08:11:15 +04:00
vlandev - > name , vlan - > vlan_id ,
( int ) ( vlan - > flags & 1 ) , vlandev - > priv_flags ) ;
2005-04-17 02:20:36 +04:00
2010-06-08 11:19:54 +04:00
seq_printf ( seq , fmt64 , " total frames received " , stats - > rx_packets ) ;
seq_printf ( seq , fmt64 , " total bytes received " , stats - > rx_bytes ) ;
seq_printf ( seq , fmt64 , " Broadcast/Multicast Rcvd " , stats - > multicast ) ;
2005-04-17 02:20:36 +04:00
seq_puts ( seq , " \n " ) ;
2010-06-08 11:19:54 +04:00
seq_printf ( seq , fmt64 , " total frames transmitted " , stats - > tx_packets ) ;
seq_printf ( seq , fmt64 , " total bytes transmitted " , stats - > tx_bytes ) ;
2011-12-08 08:11:15 +04:00
seq_printf ( seq , " Device: %s " , vlan - > real_dev - > name ) ;
2005-04-17 02:20:36 +04:00
/* now show all PRIORITY mappings relating to this VLAN */
2008-01-21 11:26:41 +03:00
seq_printf ( seq , " \n INGRESS priority mappings: "
" 0:%u 1:%u 2:%u 3:%u 4:%u 5:%u 6:%u 7:%u \n " ,
2011-12-08 08:11:15 +04:00
vlan - > ingress_priority_map [ 0 ] ,
vlan - > ingress_priority_map [ 1 ] ,
vlan - > ingress_priority_map [ 2 ] ,
vlan - > ingress_priority_map [ 3 ] ,
vlan - > ingress_priority_map [ 4 ] ,
vlan - > ingress_priority_map [ 5 ] ,
vlan - > ingress_priority_map [ 6 ] ,
vlan - > ingress_priority_map [ 7 ] ) ;
2005-04-17 02:20:36 +04:00
2008-11-11 00:37:40 +03:00
seq_printf ( seq , " EGRESS priority mappings: " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < 16 ; i + + ) {
const struct vlan_priority_tci_mapping * mp
2011-12-08 08:11:15 +04:00
= vlan - > egress_priority_map [ i ] ;
2005-04-17 02:20:36 +04:00
while ( mp ) {
2007-06-13 23:07:07 +04:00
seq_printf ( seq , " %u:%hu " ,
2005-04-17 02:20:36 +04:00
mp - > priority , ( ( mp - > vlan_qos > > 13 ) & 0x7 ) ) ;
mp = mp - > next ;
}
}
seq_puts ( seq , " \n " ) ;
return 0 ;
}