18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/****************************************************************************** 38c2ecf20Sopenharmony_ci * vlanproc.c VLAN Module. /proc filesystem interface. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This module is completely hardware-independent and provides 68c2ecf20Sopenharmony_ci * access to the router using Linux /proc filesystem. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Ben Greear, <greearb@candelatech.com> coppied from wanproc.c 98c2ecf20Sopenharmony_ci * by: Gene Kozin <genek@compuserve.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright: (c) 1998 Ben Greear 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * ============================================================================ 148c2ecf20Sopenharmony_ci * Jan 20, 1998 Ben Greear Initial Version 158c2ecf20Sopenharmony_ci *****************************************************************************/ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/errno.h> 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/string.h> 238c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 248c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 258c2ecf20Sopenharmony_ci#include <linux/fs.h> 268c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 278c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 288c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 298c2ecf20Sopenharmony_ci#include <net/netns/generic.h> 308c2ecf20Sopenharmony_ci#include "vlanproc.h" 318c2ecf20Sopenharmony_ci#include "vlan.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/****** Function Prototypes *************************************************/ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Methods for preparing data for reading proc entries */ 368c2ecf20Sopenharmony_cistatic int vlan_seq_show(struct seq_file *seq, void *v); 378c2ecf20Sopenharmony_cistatic void *vlan_seq_start(struct seq_file *seq, loff_t *pos); 388c2ecf20Sopenharmony_cistatic void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos); 398c2ecf20Sopenharmony_cistatic void vlan_seq_stop(struct seq_file *seq, void *); 408c2ecf20Sopenharmony_cistatic int vlandev_seq_show(struct seq_file *seq, void *v); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * Global Data 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * Names of the proc directory entries 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic const char name_root[] = "vlan"; 528c2ecf20Sopenharmony_cistatic const char name_conf[] = "config"; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Structures for interfacing with the /proc filesystem. 568c2ecf20Sopenharmony_ci * VLAN creates its own directory /proc/net/vlan with the following 578c2ecf20Sopenharmony_ci * entries: 588c2ecf20Sopenharmony_ci * config device status/configuration 598c2ecf20Sopenharmony_ci * <device> entry for each device 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* 638c2ecf20Sopenharmony_ci * Generic /proc/net/vlan/<file> file and inode operations 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic const struct seq_operations vlan_seq_ops = { 678c2ecf20Sopenharmony_ci .start = vlan_seq_start, 688c2ecf20Sopenharmony_ci .next = vlan_seq_next, 698c2ecf20Sopenharmony_ci .stop = vlan_seq_stop, 708c2ecf20Sopenharmony_ci .show = vlan_seq_show, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * Proc filesystem directory entries. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Strings */ 788c2ecf20Sopenharmony_cistatic const char *const vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = { 798c2ecf20Sopenharmony_ci [VLAN_NAME_TYPE_RAW_PLUS_VID] = "VLAN_NAME_TYPE_RAW_PLUS_VID", 808c2ecf20Sopenharmony_ci [VLAN_NAME_TYPE_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_PLUS_VID_NO_PAD", 818c2ecf20Sopenharmony_ci [VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD] = "VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD", 828c2ecf20Sopenharmony_ci [VLAN_NAME_TYPE_PLUS_VID] = "VLAN_NAME_TYPE_PLUS_VID", 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * Interface functions 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci * Clean up /proc/net/vlan entries 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_civoid vlan_proc_cleanup(struct net *net) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct vlan_net *vn = net_generic(net, vlan_net_id); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (vn->proc_vlan_conf) 978c2ecf20Sopenharmony_ci remove_proc_entry(name_conf, vn->proc_vlan_dir); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (vn->proc_vlan_dir) 1008c2ecf20Sopenharmony_ci remove_proc_entry(name_root, net->proc_net); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Dynamically added entries should be cleaned up as their vlan_device 1038c2ecf20Sopenharmony_ci * is removed, so we should not have to take care of it here... 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* 1088c2ecf20Sopenharmony_ci * Create /proc/net/vlan entries 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciint __net_init vlan_proc_init(struct net *net) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct vlan_net *vn = net_generic(net, vlan_net_id); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); 1168c2ecf20Sopenharmony_ci if (!vn->proc_vlan_dir) 1178c2ecf20Sopenharmony_ci goto err; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci vn->proc_vlan_conf = proc_create_net(name_conf, S_IFREG | 0600, 1208c2ecf20Sopenharmony_ci vn->proc_vlan_dir, &vlan_seq_ops, 1218c2ecf20Sopenharmony_ci sizeof(struct seq_net_private)); 1228c2ecf20Sopenharmony_ci if (!vn->proc_vlan_conf) 1238c2ecf20Sopenharmony_ci goto err; 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cierr: 1278c2ecf20Sopenharmony_ci pr_err("can't create entry in proc filesystem!\n"); 1288c2ecf20Sopenharmony_ci vlan_proc_cleanup(net); 1298c2ecf20Sopenharmony_ci return -ENOBUFS; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* 1338c2ecf20Sopenharmony_ci * Add directory entry for VLAN device. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciint vlan_proc_add_dev(struct net_device *vlandev) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); 1398c2ecf20Sopenharmony_ci struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (!strcmp(vlandev->name, name_conf)) 1428c2ecf20Sopenharmony_ci return -EINVAL; 1438c2ecf20Sopenharmony_ci vlan->dent = proc_create_single_data(vlandev->name, S_IFREG | 0600, 1448c2ecf20Sopenharmony_ci vn->proc_vlan_dir, vlandev_seq_show, vlandev); 1458c2ecf20Sopenharmony_ci if (!vlan->dent) 1468c2ecf20Sopenharmony_ci return -ENOBUFS; 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* 1518c2ecf20Sopenharmony_ci * Delete directory entry for VLAN device. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_civoid vlan_proc_rem_dev(struct net_device *vlandev) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci /** NOTE: This will consume the memory pointed to by dent, it seems. */ 1568c2ecf20Sopenharmony_ci proc_remove(vlan_dev_priv(vlandev)->dent); 1578c2ecf20Sopenharmony_ci vlan_dev_priv(vlandev)->dent = NULL; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/****** Proc filesystem entry points ****************************************/ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 1638c2ecf20Sopenharmony_ci * The following few functions build the content of /proc/net/vlan/config 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/* start read of /proc/net/vlan/config */ 1678c2ecf20Sopenharmony_cistatic void *vlan_seq_start(struct seq_file *seq, loff_t *pos) 1688c2ecf20Sopenharmony_ci __acquires(rcu) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct net_device *dev; 1718c2ecf20Sopenharmony_ci struct net *net = seq_file_net(seq); 1728c2ecf20Sopenharmony_ci loff_t i = 1; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci rcu_read_lock(); 1758c2ecf20Sopenharmony_ci if (*pos == 0) 1768c2ecf20Sopenharmony_ci return SEQ_START_TOKEN; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci for_each_netdev_rcu(net, dev) { 1798c2ecf20Sopenharmony_ci if (!is_vlan_dev(dev)) 1808c2ecf20Sopenharmony_ci continue; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (i++ == *pos) 1838c2ecf20Sopenharmony_ci return dev; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return NULL; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct net_device *dev; 1928c2ecf20Sopenharmony_ci struct net *net = seq_file_net(seq); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci ++*pos; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci dev = v; 1978c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) 1988c2ecf20Sopenharmony_ci dev = net_device_entry(&net->dev_base_head); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci for_each_netdev_continue_rcu(net, dev) { 2018c2ecf20Sopenharmony_ci if (!is_vlan_dev(dev)) 2028c2ecf20Sopenharmony_ci continue; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return dev; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci return NULL; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void vlan_seq_stop(struct seq_file *seq, void *v) 2118c2ecf20Sopenharmony_ci __releases(rcu) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci rcu_read_unlock(); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int vlan_seq_show(struct seq_file *seq, void *v) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct net *net = seq_file_net(seq); 2198c2ecf20Sopenharmony_ci struct vlan_net *vn = net_generic(net, vlan_net_id); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) { 2228c2ecf20Sopenharmony_ci const char *nmtype = NULL; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci seq_puts(seq, "VLAN Dev name | VLAN ID\n"); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (vn->name_type < ARRAY_SIZE(vlan_name_type_str)) 2278c2ecf20Sopenharmony_ci nmtype = vlan_name_type_str[vn->name_type]; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci seq_printf(seq, "Name-Type: %s\n", 2308c2ecf20Sopenharmony_ci nmtype ? nmtype : "UNKNOWN"); 2318c2ecf20Sopenharmony_ci } else { 2328c2ecf20Sopenharmony_ci const struct net_device *vlandev = v; 2338c2ecf20Sopenharmony_ci const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci seq_printf(seq, "%-15s| %d | %s\n", vlandev->name, 2368c2ecf20Sopenharmony_ci vlan->vlan_id, vlan->real_dev->name); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int vlandev_seq_show(struct seq_file *seq, void *offset) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct net_device *vlandev = (struct net_device *) seq->private; 2448c2ecf20Sopenharmony_ci const struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); 2458c2ecf20Sopenharmony_ci struct rtnl_link_stats64 temp; 2468c2ecf20Sopenharmony_ci const struct rtnl_link_stats64 *stats; 2478c2ecf20Sopenharmony_ci static const char fmt64[] = "%30s %12llu\n"; 2488c2ecf20Sopenharmony_ci int i; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (!is_vlan_dev(vlandev)) 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci stats = dev_get_stats(vlandev, &temp); 2548c2ecf20Sopenharmony_ci seq_printf(seq, 2558c2ecf20Sopenharmony_ci "%s VID: %d REORDER_HDR: %i dev->priv_flags: %hx\n", 2568c2ecf20Sopenharmony_ci vlandev->name, vlan->vlan_id, 2578c2ecf20Sopenharmony_ci (int)(vlan->flags & 1), vlandev->priv_flags); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci seq_printf(seq, fmt64, "total frames received", stats->rx_packets); 2608c2ecf20Sopenharmony_ci seq_printf(seq, fmt64, "total bytes received", stats->rx_bytes); 2618c2ecf20Sopenharmony_ci seq_printf(seq, fmt64, "Broadcast/Multicast Rcvd", stats->multicast); 2628c2ecf20Sopenharmony_ci seq_puts(seq, "\n"); 2638c2ecf20Sopenharmony_ci seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets); 2648c2ecf20Sopenharmony_ci seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes); 2658c2ecf20Sopenharmony_ci seq_printf(seq, "Device: %s", vlan->real_dev->name); 2668c2ecf20Sopenharmony_ci /* now show all PRIORITY mappings relating to this VLAN */ 2678c2ecf20Sopenharmony_ci seq_printf(seq, "\nINGRESS priority mappings: " 2688c2ecf20Sopenharmony_ci "0:%u 1:%u 2:%u 3:%u 4:%u 5:%u 6:%u 7:%u\n", 2698c2ecf20Sopenharmony_ci vlan->ingress_priority_map[0], 2708c2ecf20Sopenharmony_ci vlan->ingress_priority_map[1], 2718c2ecf20Sopenharmony_ci vlan->ingress_priority_map[2], 2728c2ecf20Sopenharmony_ci vlan->ingress_priority_map[3], 2738c2ecf20Sopenharmony_ci vlan->ingress_priority_map[4], 2748c2ecf20Sopenharmony_ci vlan->ingress_priority_map[5], 2758c2ecf20Sopenharmony_ci vlan->ingress_priority_map[6], 2768c2ecf20Sopenharmony_ci vlan->ingress_priority_map[7]); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci seq_printf(seq, " EGRESS priority mappings: "); 2798c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 2808c2ecf20Sopenharmony_ci const struct vlan_priority_tci_mapping *mp 2818c2ecf20Sopenharmony_ci = vlan->egress_priority_map[i]; 2828c2ecf20Sopenharmony_ci while (mp) { 2838c2ecf20Sopenharmony_ci seq_printf(seq, "%u:%hu ", 2848c2ecf20Sopenharmony_ci mp->priority, ((mp->vlan_qos >> 13) & 0x7)); 2858c2ecf20Sopenharmony_ci mp = mp->next; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci seq_puts(seq, "\n"); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci} 292