cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

proc.c (15065B)


      1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
      2/*
      3 * proc.c - procfs support for Protocol family CAN core module
      4 *
      5 * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
      6 * All rights reserved.
      7 *
      8 * Redistribution and use in source and binary forms, with or without
      9 * modification, are permitted provided that the following conditions
     10 * are met:
     11 * 1. Redistributions of source code must retain the above copyright
     12 *    notice, this list of conditions and the following disclaimer.
     13 * 2. Redistributions in binary form must reproduce the above copyright
     14 *    notice, this list of conditions and the following disclaimer in the
     15 *    documentation and/or other materials provided with the distribution.
     16 * 3. Neither the name of Volkswagen nor the names of its contributors
     17 *    may be used to endorse or promote products derived from this software
     18 *    without specific prior written permission.
     19 *
     20 * Alternatively, provided that this notice is retained in full, this
     21 * software may be distributed under the terms of the GNU General
     22 * Public License ("GPL") version 2, in which case the provisions of the
     23 * GPL apply INSTEAD OF those given above.
     24 *
     25 * The provided data structures and external interfaces from this code
     26 * are not restricted to be used by modules with a GPL compatible license.
     27 *
     28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
     39 * DAMAGE.
     40 *
     41 */
     42
     43#include <linux/module.h>
     44#include <linux/proc_fs.h>
     45#include <linux/list.h>
     46#include <linux/rcupdate.h>
     47#include <linux/if_arp.h>
     48#include <linux/can/can-ml.h>
     49#include <linux/can/core.h>
     50
     51#include "af_can.h"
     52
     53/*
     54 * proc filenames for the PF_CAN core
     55 */
     56
     57#define CAN_PROC_STATS       "stats"
     58#define CAN_PROC_RESET_STATS "reset_stats"
     59#define CAN_PROC_RCVLIST_ALL "rcvlist_all"
     60#define CAN_PROC_RCVLIST_FIL "rcvlist_fil"
     61#define CAN_PROC_RCVLIST_INV "rcvlist_inv"
     62#define CAN_PROC_RCVLIST_SFF "rcvlist_sff"
     63#define CAN_PROC_RCVLIST_EFF "rcvlist_eff"
     64#define CAN_PROC_RCVLIST_ERR "rcvlist_err"
     65
     66static int user_reset;
     67
     68static const char rx_list_name[][8] = {
     69	[RX_ERR] = "rx_err",
     70	[RX_ALL] = "rx_all",
     71	[RX_FIL] = "rx_fil",
     72	[RX_INV] = "rx_inv",
     73};
     74
     75/*
     76 * af_can statistics stuff
     77 */
     78
     79static void can_init_stats(struct net *net)
     80{
     81	struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
     82	struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
     83	/*
     84	 * This memset function is called from a timer context (when
     85	 * can_stattimer is active which is the default) OR in a process
     86	 * context (reading the proc_fs when can_stattimer is disabled).
     87	 */
     88	memset(pkg_stats, 0, sizeof(struct can_pkg_stats));
     89	pkg_stats->jiffies_init = jiffies;
     90
     91	rcv_lists_stats->stats_reset++;
     92
     93	if (user_reset) {
     94		user_reset = 0;
     95		rcv_lists_stats->user_reset++;
     96	}
     97}
     98
     99static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif,
    100			       unsigned long count)
    101{
    102	if (oldjif == newjif)
    103		return 0;
    104
    105	/* see can_stat_update() - this should NEVER happen! */
    106	if (count > (ULONG_MAX / HZ)) {
    107		printk(KERN_ERR "can: calc_rate: count exceeded! %ld\n",
    108		       count);
    109		return 99999999;
    110	}
    111
    112	return (count * HZ) / (newjif - oldjif);
    113}
    114
    115void can_stat_update(struct timer_list *t)
    116{
    117	struct net *net = from_timer(net, t, can.stattimer);
    118	struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
    119	unsigned long j = jiffies; /* snapshot */
    120
    121	/* restart counting in timer context on user request */
    122	if (user_reset)
    123		can_init_stats(net);
    124
    125	/* restart counting on jiffies overflow */
    126	if (j < pkg_stats->jiffies_init)
    127		can_init_stats(net);
    128
    129	/* prevent overflow in calc_rate() */
    130	if (pkg_stats->rx_frames > (ULONG_MAX / HZ))
    131		can_init_stats(net);
    132
    133	/* prevent overflow in calc_rate() */
    134	if (pkg_stats->tx_frames > (ULONG_MAX / HZ))
    135		can_init_stats(net);
    136
    137	/* matches overflow - very improbable */
    138	if (pkg_stats->matches > (ULONG_MAX / 100))
    139		can_init_stats(net);
    140
    141	/* calc total values */
    142	if (pkg_stats->rx_frames)
    143		pkg_stats->total_rx_match_ratio = (pkg_stats->matches * 100) /
    144			pkg_stats->rx_frames;
    145
    146	pkg_stats->total_tx_rate = calc_rate(pkg_stats->jiffies_init, j,
    147					    pkg_stats->tx_frames);
    148	pkg_stats->total_rx_rate = calc_rate(pkg_stats->jiffies_init, j,
    149					    pkg_stats->rx_frames);
    150
    151	/* calc current values */
    152	if (pkg_stats->rx_frames_delta)
    153		pkg_stats->current_rx_match_ratio =
    154			(pkg_stats->matches_delta * 100) /
    155			pkg_stats->rx_frames_delta;
    156
    157	pkg_stats->current_tx_rate = calc_rate(0, HZ, pkg_stats->tx_frames_delta);
    158	pkg_stats->current_rx_rate = calc_rate(0, HZ, pkg_stats->rx_frames_delta);
    159
    160	/* check / update maximum values */
    161	if (pkg_stats->max_tx_rate < pkg_stats->current_tx_rate)
    162		pkg_stats->max_tx_rate = pkg_stats->current_tx_rate;
    163
    164	if (pkg_stats->max_rx_rate < pkg_stats->current_rx_rate)
    165		pkg_stats->max_rx_rate = pkg_stats->current_rx_rate;
    166
    167	if (pkg_stats->max_rx_match_ratio < pkg_stats->current_rx_match_ratio)
    168		pkg_stats->max_rx_match_ratio = pkg_stats->current_rx_match_ratio;
    169
    170	/* clear values for 'current rate' calculation */
    171	pkg_stats->tx_frames_delta = 0;
    172	pkg_stats->rx_frames_delta = 0;
    173	pkg_stats->matches_delta   = 0;
    174
    175	/* restart timer (one second) */
    176	mod_timer(&net->can.stattimer, round_jiffies(jiffies + HZ));
    177}
    178
    179/*
    180 * proc read functions
    181 */
    182
    183static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
    184			      struct net_device *dev)
    185{
    186	struct receiver *r;
    187
    188	hlist_for_each_entry_rcu(r, rx_list, list) {
    189		char *fmt = (r->can_id & CAN_EFF_FLAG)?
    190			"   %-5s  %08x  %08x  %pK  %pK  %8ld  %s\n" :
    191			"   %-5s     %03x    %08x  %pK  %pK  %8ld  %s\n";
    192
    193		seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
    194				r->func, r->data, r->matches, r->ident);
    195	}
    196}
    197
    198static void can_print_recv_banner(struct seq_file *m)
    199{
    200	/*
    201	 *                  can1.  00000000  00000000  00000000
    202	 *                 .......          0  tp20
    203	 */
    204	if (IS_ENABLED(CONFIG_64BIT))
    205		seq_puts(m, "  device   can_id   can_mask      function          userdata       matches  ident\n");
    206	else
    207		seq_puts(m, "  device   can_id   can_mask  function  userdata   matches  ident\n");
    208}
    209
    210static int can_stats_proc_show(struct seq_file *m, void *v)
    211{
    212	struct net *net = m->private;
    213	struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
    214	struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
    215
    216	seq_putc(m, '\n');
    217	seq_printf(m, " %8ld transmitted frames (TXF)\n", pkg_stats->tx_frames);
    218	seq_printf(m, " %8ld received frames (RXF)\n", pkg_stats->rx_frames);
    219	seq_printf(m, " %8ld matched frames (RXMF)\n", pkg_stats->matches);
    220
    221	seq_putc(m, '\n');
    222
    223	if (net->can.stattimer.function == can_stat_update) {
    224		seq_printf(m, " %8ld %% total match ratio (RXMR)\n",
    225				pkg_stats->total_rx_match_ratio);
    226
    227		seq_printf(m, " %8ld frames/s total tx rate (TXR)\n",
    228				pkg_stats->total_tx_rate);
    229		seq_printf(m, " %8ld frames/s total rx rate (RXR)\n",
    230				pkg_stats->total_rx_rate);
    231
    232		seq_putc(m, '\n');
    233
    234		seq_printf(m, " %8ld %% current match ratio (CRXMR)\n",
    235				pkg_stats->current_rx_match_ratio);
    236
    237		seq_printf(m, " %8ld frames/s current tx rate (CTXR)\n",
    238				pkg_stats->current_tx_rate);
    239		seq_printf(m, " %8ld frames/s current rx rate (CRXR)\n",
    240				pkg_stats->current_rx_rate);
    241
    242		seq_putc(m, '\n');
    243
    244		seq_printf(m, " %8ld %% max match ratio (MRXMR)\n",
    245				pkg_stats->max_rx_match_ratio);
    246
    247		seq_printf(m, " %8ld frames/s max tx rate (MTXR)\n",
    248				pkg_stats->max_tx_rate);
    249		seq_printf(m, " %8ld frames/s max rx rate (MRXR)\n",
    250				pkg_stats->max_rx_rate);
    251
    252		seq_putc(m, '\n');
    253	}
    254
    255	seq_printf(m, " %8ld current receive list entries (CRCV)\n",
    256			rcv_lists_stats->rcv_entries);
    257	seq_printf(m, " %8ld maximum receive list entries (MRCV)\n",
    258			rcv_lists_stats->rcv_entries_max);
    259
    260	if (rcv_lists_stats->stats_reset)
    261		seq_printf(m, "\n %8ld statistic resets (STR)\n",
    262				rcv_lists_stats->stats_reset);
    263
    264	if (rcv_lists_stats->user_reset)
    265		seq_printf(m, " %8ld user statistic resets (USTR)\n",
    266				rcv_lists_stats->user_reset);
    267
    268	seq_putc(m, '\n');
    269	return 0;
    270}
    271
    272static int can_reset_stats_proc_show(struct seq_file *m, void *v)
    273{
    274	struct net *net = m->private;
    275	struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
    276	struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
    277
    278	user_reset = 1;
    279
    280	if (net->can.stattimer.function == can_stat_update) {
    281		seq_printf(m, "Scheduled statistic reset #%ld.\n",
    282				rcv_lists_stats->stats_reset + 1);
    283	} else {
    284		if (pkg_stats->jiffies_init != jiffies)
    285			can_init_stats(net);
    286
    287		seq_printf(m, "Performed statistic reset #%ld.\n",
    288				rcv_lists_stats->stats_reset);
    289	}
    290	return 0;
    291}
    292
    293static inline void can_rcvlist_proc_show_one(struct seq_file *m, int idx,
    294					     struct net_device *dev,
    295					     struct can_dev_rcv_lists *dev_rcv_lists)
    296{
    297	if (!hlist_empty(&dev_rcv_lists->rx[idx])) {
    298		can_print_recv_banner(m);
    299		can_print_rcvlist(m, &dev_rcv_lists->rx[idx], dev);
    300	} else
    301		seq_printf(m, "  (%s: no entry)\n", DNAME(dev));
    302
    303}
    304
    305static int can_rcvlist_proc_show(struct seq_file *m, void *v)
    306{
    307	/* double cast to prevent GCC warning */
    308	int idx = (int)(long)pde_data(m->file->f_inode);
    309	struct net_device *dev;
    310	struct can_dev_rcv_lists *dev_rcv_lists;
    311	struct net *net = m->private;
    312
    313	seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]);
    314
    315	rcu_read_lock();
    316
    317	/* receive list for 'all' CAN devices (dev == NULL) */
    318	dev_rcv_lists = net->can.rx_alldev_list;
    319	can_rcvlist_proc_show_one(m, idx, NULL, dev_rcv_lists);
    320
    321	/* receive list for registered CAN devices */
    322	for_each_netdev_rcu(net, dev) {
    323		struct can_ml_priv *can_ml = can_get_ml_priv(dev);
    324
    325		if (can_ml)
    326			can_rcvlist_proc_show_one(m, idx, dev,
    327						  &can_ml->dev_rcv_lists);
    328	}
    329
    330	rcu_read_unlock();
    331
    332	seq_putc(m, '\n');
    333	return 0;
    334}
    335
    336static inline void can_rcvlist_proc_show_array(struct seq_file *m,
    337					       struct net_device *dev,
    338					       struct hlist_head *rcv_array,
    339					       unsigned int rcv_array_sz)
    340{
    341	unsigned int i;
    342	int all_empty = 1;
    343
    344	/* check whether at least one list is non-empty */
    345	for (i = 0; i < rcv_array_sz; i++)
    346		if (!hlist_empty(&rcv_array[i])) {
    347			all_empty = 0;
    348			break;
    349		}
    350
    351	if (!all_empty) {
    352		can_print_recv_banner(m);
    353		for (i = 0; i < rcv_array_sz; i++) {
    354			if (!hlist_empty(&rcv_array[i]))
    355				can_print_rcvlist(m, &rcv_array[i], dev);
    356		}
    357	} else
    358		seq_printf(m, "  (%s: no entry)\n", DNAME(dev));
    359}
    360
    361static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
    362{
    363	struct net_device *dev;
    364	struct can_dev_rcv_lists *dev_rcv_lists;
    365	struct net *net = m->private;
    366
    367	/* RX_SFF */
    368	seq_puts(m, "\nreceive list 'rx_sff':\n");
    369
    370	rcu_read_lock();
    371
    372	/* sff receive list for 'all' CAN devices (dev == NULL) */
    373	dev_rcv_lists = net->can.rx_alldev_list;
    374	can_rcvlist_proc_show_array(m, NULL, dev_rcv_lists->rx_sff,
    375				    ARRAY_SIZE(dev_rcv_lists->rx_sff));
    376
    377	/* sff receive list for registered CAN devices */
    378	for_each_netdev_rcu(net, dev) {
    379		struct can_ml_priv *can_ml = can_get_ml_priv(dev);
    380
    381		if (can_ml) {
    382			dev_rcv_lists = &can_ml->dev_rcv_lists;
    383			can_rcvlist_proc_show_array(m, dev, dev_rcv_lists->rx_sff,
    384						    ARRAY_SIZE(dev_rcv_lists->rx_sff));
    385		}
    386	}
    387
    388	rcu_read_unlock();
    389
    390	seq_putc(m, '\n');
    391	return 0;
    392}
    393
    394static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v)
    395{
    396	struct net_device *dev;
    397	struct can_dev_rcv_lists *dev_rcv_lists;
    398	struct net *net = m->private;
    399
    400	/* RX_EFF */
    401	seq_puts(m, "\nreceive list 'rx_eff':\n");
    402
    403	rcu_read_lock();
    404
    405	/* eff receive list for 'all' CAN devices (dev == NULL) */
    406	dev_rcv_lists = net->can.rx_alldev_list;
    407	can_rcvlist_proc_show_array(m, NULL, dev_rcv_lists->rx_eff,
    408				    ARRAY_SIZE(dev_rcv_lists->rx_eff));
    409
    410	/* eff receive list for registered CAN devices */
    411	for_each_netdev_rcu(net, dev) {
    412		struct can_ml_priv *can_ml = can_get_ml_priv(dev);
    413
    414		if (can_ml) {
    415			dev_rcv_lists = &can_ml->dev_rcv_lists;
    416			can_rcvlist_proc_show_array(m, dev, dev_rcv_lists->rx_eff,
    417						    ARRAY_SIZE(dev_rcv_lists->rx_eff));
    418		}
    419	}
    420
    421	rcu_read_unlock();
    422
    423	seq_putc(m, '\n');
    424	return 0;
    425}
    426
    427/*
    428 * can_init_proc - create main CAN proc directory and procfs entries
    429 */
    430void can_init_proc(struct net *net)
    431{
    432	/* create /proc/net/can directory */
    433	net->can.proc_dir = proc_net_mkdir(net, "can", net->proc_net);
    434
    435	if (!net->can.proc_dir) {
    436		printk(KERN_INFO "can: failed to create /proc/net/can . "
    437			   "CONFIG_PROC_FS missing?\n");
    438		return;
    439	}
    440
    441	/* own procfs entries from the AF_CAN core */
    442	net->can.pde_stats = proc_create_net_single(CAN_PROC_STATS, 0644,
    443			net->can.proc_dir, can_stats_proc_show, NULL);
    444	net->can.pde_reset_stats = proc_create_net_single(CAN_PROC_RESET_STATS,
    445			0644, net->can.proc_dir, can_reset_stats_proc_show,
    446			NULL);
    447	net->can.pde_rcvlist_err = proc_create_net_single(CAN_PROC_RCVLIST_ERR,
    448			0644, net->can.proc_dir, can_rcvlist_proc_show,
    449			(void *)RX_ERR);
    450	net->can.pde_rcvlist_all = proc_create_net_single(CAN_PROC_RCVLIST_ALL,
    451			0644, net->can.proc_dir, can_rcvlist_proc_show,
    452			(void *)RX_ALL);
    453	net->can.pde_rcvlist_fil = proc_create_net_single(CAN_PROC_RCVLIST_FIL,
    454			0644, net->can.proc_dir, can_rcvlist_proc_show,
    455			(void *)RX_FIL);
    456	net->can.pde_rcvlist_inv = proc_create_net_single(CAN_PROC_RCVLIST_INV,
    457			0644, net->can.proc_dir, can_rcvlist_proc_show,
    458			(void *)RX_INV);
    459	net->can.pde_rcvlist_eff = proc_create_net_single(CAN_PROC_RCVLIST_EFF,
    460			0644, net->can.proc_dir, can_rcvlist_eff_proc_show, NULL);
    461	net->can.pde_rcvlist_sff = proc_create_net_single(CAN_PROC_RCVLIST_SFF,
    462			0644, net->can.proc_dir, can_rcvlist_sff_proc_show, NULL);
    463}
    464
    465/*
    466 * can_remove_proc - remove procfs entries and main CAN proc directory
    467 */
    468void can_remove_proc(struct net *net)
    469{
    470	if (!net->can.proc_dir)
    471		return;
    472
    473	if (net->can.pde_stats)
    474		remove_proc_entry(CAN_PROC_STATS, net->can.proc_dir);
    475
    476	if (net->can.pde_reset_stats)
    477		remove_proc_entry(CAN_PROC_RESET_STATS, net->can.proc_dir);
    478
    479	if (net->can.pde_rcvlist_err)
    480		remove_proc_entry(CAN_PROC_RCVLIST_ERR, net->can.proc_dir);
    481
    482	if (net->can.pde_rcvlist_all)
    483		remove_proc_entry(CAN_PROC_RCVLIST_ALL, net->can.proc_dir);
    484
    485	if (net->can.pde_rcvlist_fil)
    486		remove_proc_entry(CAN_PROC_RCVLIST_FIL, net->can.proc_dir);
    487
    488	if (net->can.pde_rcvlist_inv)
    489		remove_proc_entry(CAN_PROC_RCVLIST_INV, net->can.proc_dir);
    490
    491	if (net->can.pde_rcvlist_eff)
    492		remove_proc_entry(CAN_PROC_RCVLIST_EFF, net->can.proc_dir);
    493
    494	if (net->can.pde_rcvlist_sff)
    495		remove_proc_entry(CAN_PROC_RCVLIST_SFF, net->can.proc_dir);
    496
    497	remove_proc_entry("can", net->proc_net);
    498}