Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /******************************************************************************
0003  * vlanproc.c   VLAN Module. /proc filesystem interface.
0004  *
0005  *      This module is completely hardware-independent and provides
0006  *      access to the router using Linux /proc filesystem.
0007  *
0008  * Author:  Ben Greear, <greearb@candelatech.com> coppied from wanproc.c
0009  *               by: Gene Kozin <genek@compuserve.com>
0010  *
0011  * Copyright:   (c) 1998 Ben Greear
0012  *
0013  * ============================================================================
0014  * Jan 20, 1998        Ben Greear     Initial Version
0015  *****************************************************************************/
0016 
0017 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0018 
0019 #include <linux/module.h>
0020 #include <linux/errno.h>
0021 #include <linux/kernel.h>
0022 #include <linux/string.h>
0023 #include <linux/proc_fs.h>
0024 #include <linux/seq_file.h>
0025 #include <linux/fs.h>
0026 #include <linux/netdevice.h>
0027 #include <linux/if_vlan.h>
0028 #include <net/net_namespace.h>
0029 #include <net/netns/generic.h>
0030 #include "vlanproc.h"
0031 #include "vlan.h"
0032 
0033 /****** Function Prototypes *************************************************/
0034 
0035 /* Methods for preparing data for reading proc entries */
0036 static int vlan_seq_show(struct seq_file *seq, void *v);
0037 static void *vlan_seq_start(struct seq_file *seq, loff_t *pos);
0038 static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos);
0039 static void vlan_seq_stop(struct seq_file *seq, void *);
0040 static int vlandev_seq_show(struct seq_file *seq, void *v);
0041 
0042 /*
0043  *  Global Data
0044  */
0045 
0046 
0047 /*
0048  *  Names of the proc directory entries
0049  */
0050 
0051 static const char name_root[]    = "vlan";
0052 static const char name_conf[]    = "config";
0053 
0054 /*
0055  *  Structures for interfacing with the /proc filesystem.
0056  *  VLAN creates its own directory /proc/net/vlan with the following
0057  *  entries:
0058  *  config      device status/configuration
0059  *  <device>    entry for each  device
0060  */
0061 
0062 /*
0063  *  Generic /proc/net/vlan/<file> file and inode operations
0064  */
0065 
0066 static const struct seq_operations vlan_seq_ops = {
0067     .start = vlan_seq_start,
0068     .next = vlan_seq_next,
0069     .stop = vlan_seq_stop,
0070     .show = vlan_seq_show,
0071 };
0072 
0073 /*
0074  * Proc filesystem directory entries.
0075  */
0076 
0077 /* Strings */
0078 static const char *const vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = {
0079     [VLAN_NAME_TYPE_RAW_PLUS_VID]        = "VLAN_NAME_TYPE_RAW_PLUS_VID",
0080     [VLAN_NAME_TYPE_PLUS_VID_NO_PAD]     = "VLAN_NAME_TYPE_PLUS_VID_NO_PAD",
0081     [VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD",
0082     [VLAN_NAME_TYPE_PLUS_VID]        = "VLAN_NAME_TYPE_PLUS_VID",
0083 };
0084 /*
0085  *  Interface functions
0086  */
0087 
0088 /*
0089  *  Clean up /proc/net/vlan entries
0090  */
0091 
0092 void vlan_proc_cleanup(struct net *net)
0093 {
0094     struct vlan_net *vn = net_generic(net, vlan_net_id);
0095 
0096     if (vn->proc_vlan_conf)
0097         remove_proc_entry(name_conf, vn->proc_vlan_dir);
0098 
0099     if (vn->proc_vlan_dir)
0100         remove_proc_entry(name_root, net->proc_net);
0101 
0102     /* Dynamically added entries should be cleaned up as their vlan_device
0103      * is removed, so we should not have to take care of it here...
0104      */
0105 }
0106 
0107 /*
0108  *  Create /proc/net/vlan entries
0109  */
0110 
0111 int __net_init vlan_proc_init(struct net *net)
0112 {
0113     struct vlan_net *vn = net_generic(net, vlan_net_id);
0114 
0115     vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
0116     if (!vn->proc_vlan_dir)
0117         goto err;
0118 
0119     vn->proc_vlan_conf = proc_create_net(name_conf, S_IFREG | 0600,
0120             vn->proc_vlan_dir, &vlan_seq_ops,
0121             sizeof(struct seq_net_private));
0122     if (!vn->proc_vlan_conf)
0123         goto err;
0124     return 0;
0125 
0126 err:
0127     pr_err("can't create entry in proc filesystem!\n");
0128     vlan_proc_cleanup(net);
0129     return -ENOBUFS;
0130 }
0131 
0132 /*
0133  *  Add directory entry for VLAN device.
0134  */
0135 
0136 int vlan_proc_add_dev(struct net_device *vlandev)
0137 {
0138     struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
0139     struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);
0140 
0141     if (!strcmp(vlandev->name, name_conf))
0142         return -EINVAL;
0143     vlan->dent = proc_create_single_data(vlandev->name, S_IFREG | 0600,
0144             vn->proc_vlan_dir, vlandev_seq_show, vlandev);
0145     if (!vlan->dent)
0146         return -ENOBUFS;
0147     return 0;
0148 }
0149 
0150 /*
0151  *  Delete directory entry for VLAN device.
0152  */
0153 void vlan_proc_rem_dev(struct net_device *vlandev)
0154 {
0155     /** NOTE:  This will consume the memory pointed to by dent, it seems. */
0156     proc_remove(vlan_dev_priv(vlandev)->dent);
0157     vlan_dev_priv(vlandev)->dent = NULL;
0158 }
0159 
0160 /****** Proc filesystem entry points ****************************************/
0161 
0162 /*
0163  * The following few functions build the content of /proc/net/vlan/config
0164  */
0165 
0166 /* start read of /proc/net/vlan/config */
0167 static void *vlan_seq_start(struct seq_file *seq, loff_t *pos)
0168     __acquires(rcu)
0169 {
0170     struct net_device *dev;
0171     struct net *net = seq_file_net(seq);
0172     loff_t i = 1;
0173 
0174     rcu_read_lock();
0175     if (*pos == 0)
0176         return SEQ_START_TOKEN;
0177 
0178     for_each_netdev_rcu(net, dev) {
0179         if (!is_vlan_dev(dev))
0180             continue;
0181 
0182         if (i++ == *pos)
0183             return dev;
0184     }
0185 
0186     return  NULL;
0187 }
0188 
0189 static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
0190 {
0191     struct net_device *dev;
0192     struct net *net = seq_file_net(seq);
0193 
0194     ++*pos;
0195 
0196     dev = v;
0197     if (v == SEQ_START_TOKEN)
0198         dev = net_device_entry(&net->dev_base_head);
0199 
0200     for_each_netdev_continue_rcu(net, dev) {
0201         if (!is_vlan_dev(dev))
0202             continue;
0203 
0204         return dev;
0205     }
0206 
0207     return NULL;
0208 }
0209 
0210 static void vlan_seq_stop(struct seq_file *seq, void *v)
0211     __releases(rcu)
0212 {
0213     rcu_read_unlock();
0214 }
0215 
0216 static int vlan_seq_show(struct seq_file *seq, void *v)
0217 {
0218     struct net *net = seq_file_net(seq);
0219     struct vlan_net *vn = net_generic(net, vlan_net_id);
0220 
0221     if (v == SEQ_START_TOKEN) {
0222         const char *nmtype = NULL;
0223 
0224         seq_puts(seq, "VLAN Dev name     | VLAN ID\n");
0225 
0226         if (vn->name_type < ARRAY_SIZE(vlan_name_type_str))
0227             nmtype =  vlan_name_type_str[vn->name_type];
0228 
0229         seq_printf(seq, "Name-Type: %s\n",
0230                nmtype ? nmtype :  "UNKNOWN");
0231     } else {
0232         const struct net_device *vlandev = v;
0233         const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
0234 
0235         seq_printf(seq, "%-15s| %d  | %s\n",  vlandev->name,
0236                vlan->vlan_id,    vlan->real_dev->name);
0237     }
0238     return 0;
0239 }
0240 
0241 static int vlandev_seq_show(struct seq_file *seq, void *offset)
0242 {
0243     struct net_device *vlandev = (struct net_device *) seq->private;
0244     const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
0245     struct rtnl_link_stats64 temp;
0246     const struct rtnl_link_stats64 *stats;
0247     static const char fmt64[] = "%30s %12llu\n";
0248     int i;
0249 
0250     if (!is_vlan_dev(vlandev))
0251         return 0;
0252 
0253     stats = dev_get_stats(vlandev, &temp);
0254     seq_printf(seq,
0255            "%s  VID: %d  REORDER_HDR: %i  dev->priv_flags: %llx\n",
0256            vlandev->name, vlan->vlan_id,
0257            (int)(vlan->flags & 1), vlandev->priv_flags);
0258 
0259     seq_printf(seq, fmt64, "total frames received", stats->rx_packets);
0260     seq_printf(seq, fmt64, "total bytes received", stats->rx_bytes);
0261     seq_printf(seq, fmt64, "Broadcast/Multicast Rcvd", stats->multicast);
0262     seq_puts(seq, "\n");
0263     seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
0264     seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
0265     seq_printf(seq, "Device: %s", vlan->real_dev->name);
0266     /* now show all PRIORITY mappings relating to this VLAN */
0267     seq_printf(seq, "\nINGRESS priority mappings: "
0268             "0:%u  1:%u  2:%u  3:%u  4:%u  5:%u  6:%u 7:%u\n",
0269            vlan->ingress_priority_map[0],
0270            vlan->ingress_priority_map[1],
0271            vlan->ingress_priority_map[2],
0272            vlan->ingress_priority_map[3],
0273            vlan->ingress_priority_map[4],
0274            vlan->ingress_priority_map[5],
0275            vlan->ingress_priority_map[6],
0276            vlan->ingress_priority_map[7]);
0277 
0278     seq_printf(seq, " EGRESS priority mappings: ");
0279     for (i = 0; i < 16; i++) {
0280         const struct vlan_priority_tci_mapping *mp
0281             = vlan->egress_priority_map[i];
0282         while (mp) {
0283             seq_printf(seq, "%u:%d ",
0284                    mp->priority, ((mp->vlan_qos >> 13) & 0x7));
0285             mp = mp->next;
0286         }
0287     }
0288     seq_puts(seq, "\n");
0289 
0290     return 0;
0291 }