Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
0002 /*
0003  * proc.c - procfs support for Protocol family CAN core module
0004  *
0005  * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
0006  * All rights reserved.
0007  *
0008  * Redistribution and use in source and binary forms, with or without
0009  * modification, are permitted provided that the following conditions
0010  * are met:
0011  * 1. Redistributions of source code must retain the above copyright
0012  *    notice, this list of conditions and the following disclaimer.
0013  * 2. Redistributions in binary form must reproduce the above copyright
0014  *    notice, this list of conditions and the following disclaimer in the
0015  *    documentation and/or other materials provided with the distribution.
0016  * 3. Neither the name of Volkswagen nor the names of its contributors
0017  *    may be used to endorse or promote products derived from this software
0018  *    without specific prior written permission.
0019  *
0020  * Alternatively, provided that this notice is retained in full, this
0021  * software may be distributed under the terms of the GNU General
0022  * Public License ("GPL") version 2, in which case the provisions of the
0023  * GPL apply INSTEAD OF those given above.
0024  *
0025  * The provided data structures and external interfaces from this code
0026  * are not restricted to be used by modules with a GPL compatible license.
0027  *
0028  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0029  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0030  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0031  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0032  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0033  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0034  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0035  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0036  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0037  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0038  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
0039  * DAMAGE.
0040  *
0041  */
0042 
0043 #include <linux/module.h>
0044 #include <linux/proc_fs.h>
0045 #include <linux/list.h>
0046 #include <linux/rcupdate.h>
0047 #include <linux/if_arp.h>
0048 #include <linux/can/can-ml.h>
0049 #include <linux/can/core.h>
0050 
0051 #include "af_can.h"
0052 
0053 /*
0054  * proc filenames for the PF_CAN core
0055  */
0056 
0057 #define CAN_PROC_STATS       "stats"
0058 #define CAN_PROC_RESET_STATS "reset_stats"
0059 #define CAN_PROC_RCVLIST_ALL "rcvlist_all"
0060 #define CAN_PROC_RCVLIST_FIL "rcvlist_fil"
0061 #define CAN_PROC_RCVLIST_INV "rcvlist_inv"
0062 #define CAN_PROC_RCVLIST_SFF "rcvlist_sff"
0063 #define CAN_PROC_RCVLIST_EFF "rcvlist_eff"
0064 #define CAN_PROC_RCVLIST_ERR "rcvlist_err"
0065 
0066 static int user_reset;
0067 
0068 static const char rx_list_name[][8] = {
0069     [RX_ERR] = "rx_err",
0070     [RX_ALL] = "rx_all",
0071     [RX_FIL] = "rx_fil",
0072     [RX_INV] = "rx_inv",
0073 };
0074 
0075 /*
0076  * af_can statistics stuff
0077  */
0078 
0079 static void can_init_stats(struct net *net)
0080 {
0081     struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
0082     struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
0083     /*
0084      * This memset function is called from a timer context (when
0085      * can_stattimer is active which is the default) OR in a process
0086      * context (reading the proc_fs when can_stattimer is disabled).
0087      */
0088     memset(pkg_stats, 0, sizeof(struct can_pkg_stats));
0089     pkg_stats->jiffies_init = jiffies;
0090 
0091     rcv_lists_stats->stats_reset++;
0092 
0093     if (user_reset) {
0094         user_reset = 0;
0095         rcv_lists_stats->user_reset++;
0096     }
0097 }
0098 
0099 static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif,
0100                    unsigned long count)
0101 {
0102     if (oldjif == newjif)
0103         return 0;
0104 
0105     /* see can_stat_update() - this should NEVER happen! */
0106     if (count > (ULONG_MAX / HZ)) {
0107         printk(KERN_ERR "can: calc_rate: count exceeded! %ld\n",
0108                count);
0109         return 99999999;
0110     }
0111 
0112     return (count * HZ) / (newjif - oldjif);
0113 }
0114 
0115 void can_stat_update(struct timer_list *t)
0116 {
0117     struct net *net = from_timer(net, t, can.stattimer);
0118     struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
0119     unsigned long j = jiffies; /* snapshot */
0120 
0121     /* restart counting in timer context on user request */
0122     if (user_reset)
0123         can_init_stats(net);
0124 
0125     /* restart counting on jiffies overflow */
0126     if (j < pkg_stats->jiffies_init)
0127         can_init_stats(net);
0128 
0129     /* prevent overflow in calc_rate() */
0130     if (pkg_stats->rx_frames > (ULONG_MAX / HZ))
0131         can_init_stats(net);
0132 
0133     /* prevent overflow in calc_rate() */
0134     if (pkg_stats->tx_frames > (ULONG_MAX / HZ))
0135         can_init_stats(net);
0136 
0137     /* matches overflow - very improbable */
0138     if (pkg_stats->matches > (ULONG_MAX / 100))
0139         can_init_stats(net);
0140 
0141     /* calc total values */
0142     if (pkg_stats->rx_frames)
0143         pkg_stats->total_rx_match_ratio = (pkg_stats->matches * 100) /
0144             pkg_stats->rx_frames;
0145 
0146     pkg_stats->total_tx_rate = calc_rate(pkg_stats->jiffies_init, j,
0147                         pkg_stats->tx_frames);
0148     pkg_stats->total_rx_rate = calc_rate(pkg_stats->jiffies_init, j,
0149                         pkg_stats->rx_frames);
0150 
0151     /* calc current values */
0152     if (pkg_stats->rx_frames_delta)
0153         pkg_stats->current_rx_match_ratio =
0154             (pkg_stats->matches_delta * 100) /
0155             pkg_stats->rx_frames_delta;
0156 
0157     pkg_stats->current_tx_rate = calc_rate(0, HZ, pkg_stats->tx_frames_delta);
0158     pkg_stats->current_rx_rate = calc_rate(0, HZ, pkg_stats->rx_frames_delta);
0159 
0160     /* check / update maximum values */
0161     if (pkg_stats->max_tx_rate < pkg_stats->current_tx_rate)
0162         pkg_stats->max_tx_rate = pkg_stats->current_tx_rate;
0163 
0164     if (pkg_stats->max_rx_rate < pkg_stats->current_rx_rate)
0165         pkg_stats->max_rx_rate = pkg_stats->current_rx_rate;
0166 
0167     if (pkg_stats->max_rx_match_ratio < pkg_stats->current_rx_match_ratio)
0168         pkg_stats->max_rx_match_ratio = pkg_stats->current_rx_match_ratio;
0169 
0170     /* clear values for 'current rate' calculation */
0171     pkg_stats->tx_frames_delta = 0;
0172     pkg_stats->rx_frames_delta = 0;
0173     pkg_stats->matches_delta   = 0;
0174 
0175     /* restart timer (one second) */
0176     mod_timer(&net->can.stattimer, round_jiffies(jiffies + HZ));
0177 }
0178 
0179 /*
0180  * proc read functions
0181  */
0182 
0183 static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
0184                   struct net_device *dev)
0185 {
0186     struct receiver *r;
0187 
0188     hlist_for_each_entry_rcu(r, rx_list, list) {
0189         char *fmt = (r->can_id & CAN_EFF_FLAG)?
0190             "   %-5s  %08x  %08x  %pK  %pK  %8ld  %s\n" :
0191             "   %-5s     %03x    %08x  %pK  %pK  %8ld  %s\n";
0192 
0193         seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
0194                 r->func, r->data, r->matches, r->ident);
0195     }
0196 }
0197 
0198 static void can_print_recv_banner(struct seq_file *m)
0199 {
0200     /*
0201      *                  can1.  00000000  00000000  00000000
0202      *                 .......          0  tp20
0203      */
0204     if (IS_ENABLED(CONFIG_64BIT))
0205         seq_puts(m, "  device   can_id   can_mask      function          userdata       matches  ident\n");
0206     else
0207         seq_puts(m, "  device   can_id   can_mask  function  userdata   matches  ident\n");
0208 }
0209 
0210 static int can_stats_proc_show(struct seq_file *m, void *v)
0211 {
0212     struct net *net = m->private;
0213     struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
0214     struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
0215 
0216     seq_putc(m, '\n');
0217     seq_printf(m, " %8ld transmitted frames (TXF)\n", pkg_stats->tx_frames);
0218     seq_printf(m, " %8ld received frames (RXF)\n", pkg_stats->rx_frames);
0219     seq_printf(m, " %8ld matched frames (RXMF)\n", pkg_stats->matches);
0220 
0221     seq_putc(m, '\n');
0222 
0223     if (net->can.stattimer.function == can_stat_update) {
0224         seq_printf(m, " %8ld %% total match ratio (RXMR)\n",
0225                 pkg_stats->total_rx_match_ratio);
0226 
0227         seq_printf(m, " %8ld frames/s total tx rate (TXR)\n",
0228                 pkg_stats->total_tx_rate);
0229         seq_printf(m, " %8ld frames/s total rx rate (RXR)\n",
0230                 pkg_stats->total_rx_rate);
0231 
0232         seq_putc(m, '\n');
0233 
0234         seq_printf(m, " %8ld %% current match ratio (CRXMR)\n",
0235                 pkg_stats->current_rx_match_ratio);
0236 
0237         seq_printf(m, " %8ld frames/s current tx rate (CTXR)\n",
0238                 pkg_stats->current_tx_rate);
0239         seq_printf(m, " %8ld frames/s current rx rate (CRXR)\n",
0240                 pkg_stats->current_rx_rate);
0241 
0242         seq_putc(m, '\n');
0243 
0244         seq_printf(m, " %8ld %% max match ratio (MRXMR)\n",
0245                 pkg_stats->max_rx_match_ratio);
0246 
0247         seq_printf(m, " %8ld frames/s max tx rate (MTXR)\n",
0248                 pkg_stats->max_tx_rate);
0249         seq_printf(m, " %8ld frames/s max rx rate (MRXR)\n",
0250                 pkg_stats->max_rx_rate);
0251 
0252         seq_putc(m, '\n');
0253     }
0254 
0255     seq_printf(m, " %8ld current receive list entries (CRCV)\n",
0256             rcv_lists_stats->rcv_entries);
0257     seq_printf(m, " %8ld maximum receive list entries (MRCV)\n",
0258             rcv_lists_stats->rcv_entries_max);
0259 
0260     if (rcv_lists_stats->stats_reset)
0261         seq_printf(m, "\n %8ld statistic resets (STR)\n",
0262                 rcv_lists_stats->stats_reset);
0263 
0264     if (rcv_lists_stats->user_reset)
0265         seq_printf(m, " %8ld user statistic resets (USTR)\n",
0266                 rcv_lists_stats->user_reset);
0267 
0268     seq_putc(m, '\n');
0269     return 0;
0270 }
0271 
0272 static int can_reset_stats_proc_show(struct seq_file *m, void *v)
0273 {
0274     struct net *net = m->private;
0275     struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
0276     struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
0277 
0278     user_reset = 1;
0279 
0280     if (net->can.stattimer.function == can_stat_update) {
0281         seq_printf(m, "Scheduled statistic reset #%ld.\n",
0282                 rcv_lists_stats->stats_reset + 1);
0283     } else {
0284         if (pkg_stats->jiffies_init != jiffies)
0285             can_init_stats(net);
0286 
0287         seq_printf(m, "Performed statistic reset #%ld.\n",
0288                 rcv_lists_stats->stats_reset);
0289     }
0290     return 0;
0291 }
0292 
0293 static inline void can_rcvlist_proc_show_one(struct seq_file *m, int idx,
0294                          struct net_device *dev,
0295                          struct can_dev_rcv_lists *dev_rcv_lists)
0296 {
0297     if (!hlist_empty(&dev_rcv_lists->rx[idx])) {
0298         can_print_recv_banner(m);
0299         can_print_rcvlist(m, &dev_rcv_lists->rx[idx], dev);
0300     } else
0301         seq_printf(m, "  (%s: no entry)\n", DNAME(dev));
0302 
0303 }
0304 
0305 static int can_rcvlist_proc_show(struct seq_file *m, void *v)
0306 {
0307     /* double cast to prevent GCC warning */
0308     int idx = (int)(long)pde_data(m->file->f_inode);
0309     struct net_device *dev;
0310     struct can_dev_rcv_lists *dev_rcv_lists;
0311     struct net *net = m->private;
0312 
0313     seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]);
0314 
0315     rcu_read_lock();
0316 
0317     /* receive list for 'all' CAN devices (dev == NULL) */
0318     dev_rcv_lists = net->can.rx_alldev_list;
0319     can_rcvlist_proc_show_one(m, idx, NULL, dev_rcv_lists);
0320 
0321     /* receive list for registered CAN devices */
0322     for_each_netdev_rcu(net, dev) {
0323         struct can_ml_priv *can_ml = can_get_ml_priv(dev);
0324 
0325         if (can_ml)
0326             can_rcvlist_proc_show_one(m, idx, dev,
0327                           &can_ml->dev_rcv_lists);
0328     }
0329 
0330     rcu_read_unlock();
0331 
0332     seq_putc(m, '\n');
0333     return 0;
0334 }
0335 
0336 static inline void can_rcvlist_proc_show_array(struct seq_file *m,
0337                            struct net_device *dev,
0338                            struct hlist_head *rcv_array,
0339                            unsigned int rcv_array_sz)
0340 {
0341     unsigned int i;
0342     int all_empty = 1;
0343 
0344     /* check whether at least one list is non-empty */
0345     for (i = 0; i < rcv_array_sz; i++)
0346         if (!hlist_empty(&rcv_array[i])) {
0347             all_empty = 0;
0348             break;
0349         }
0350 
0351     if (!all_empty) {
0352         can_print_recv_banner(m);
0353         for (i = 0; i < rcv_array_sz; i++) {
0354             if (!hlist_empty(&rcv_array[i]))
0355                 can_print_rcvlist(m, &rcv_array[i], dev);
0356         }
0357     } else
0358         seq_printf(m, "  (%s: no entry)\n", DNAME(dev));
0359 }
0360 
0361 static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
0362 {
0363     struct net_device *dev;
0364     struct can_dev_rcv_lists *dev_rcv_lists;
0365     struct net *net = m->private;
0366 
0367     /* RX_SFF */
0368     seq_puts(m, "\nreceive list 'rx_sff':\n");
0369 
0370     rcu_read_lock();
0371 
0372     /* sff receive list for 'all' CAN devices (dev == NULL) */
0373     dev_rcv_lists = net->can.rx_alldev_list;
0374     can_rcvlist_proc_show_array(m, NULL, dev_rcv_lists->rx_sff,
0375                     ARRAY_SIZE(dev_rcv_lists->rx_sff));
0376 
0377     /* sff receive list for registered CAN devices */
0378     for_each_netdev_rcu(net, dev) {
0379         struct can_ml_priv *can_ml = can_get_ml_priv(dev);
0380 
0381         if (can_ml) {
0382             dev_rcv_lists = &can_ml->dev_rcv_lists;
0383             can_rcvlist_proc_show_array(m, dev, dev_rcv_lists->rx_sff,
0384                             ARRAY_SIZE(dev_rcv_lists->rx_sff));
0385         }
0386     }
0387 
0388     rcu_read_unlock();
0389 
0390     seq_putc(m, '\n');
0391     return 0;
0392 }
0393 
0394 static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v)
0395 {
0396     struct net_device *dev;
0397     struct can_dev_rcv_lists *dev_rcv_lists;
0398     struct net *net = m->private;
0399 
0400     /* RX_EFF */
0401     seq_puts(m, "\nreceive list 'rx_eff':\n");
0402 
0403     rcu_read_lock();
0404 
0405     /* eff receive list for 'all' CAN devices (dev == NULL) */
0406     dev_rcv_lists = net->can.rx_alldev_list;
0407     can_rcvlist_proc_show_array(m, NULL, dev_rcv_lists->rx_eff,
0408                     ARRAY_SIZE(dev_rcv_lists->rx_eff));
0409 
0410     /* eff receive list for registered CAN devices */
0411     for_each_netdev_rcu(net, dev) {
0412         struct can_ml_priv *can_ml = can_get_ml_priv(dev);
0413 
0414         if (can_ml) {
0415             dev_rcv_lists = &can_ml->dev_rcv_lists;
0416             can_rcvlist_proc_show_array(m, dev, dev_rcv_lists->rx_eff,
0417                             ARRAY_SIZE(dev_rcv_lists->rx_eff));
0418         }
0419     }
0420 
0421     rcu_read_unlock();
0422 
0423     seq_putc(m, '\n');
0424     return 0;
0425 }
0426 
0427 /*
0428  * can_init_proc - create main CAN proc directory and procfs entries
0429  */
0430 void can_init_proc(struct net *net)
0431 {
0432     /* create /proc/net/can directory */
0433     net->can.proc_dir = proc_net_mkdir(net, "can", net->proc_net);
0434 
0435     if (!net->can.proc_dir) {
0436         printk(KERN_INFO "can: failed to create /proc/net/can . "
0437                "CONFIG_PROC_FS missing?\n");
0438         return;
0439     }
0440 
0441     /* own procfs entries from the AF_CAN core */
0442     net->can.pde_stats = proc_create_net_single(CAN_PROC_STATS, 0644,
0443             net->can.proc_dir, can_stats_proc_show, NULL);
0444     net->can.pde_reset_stats = proc_create_net_single(CAN_PROC_RESET_STATS,
0445             0644, net->can.proc_dir, can_reset_stats_proc_show,
0446             NULL);
0447     net->can.pde_rcvlist_err = proc_create_net_single(CAN_PROC_RCVLIST_ERR,
0448             0644, net->can.proc_dir, can_rcvlist_proc_show,
0449             (void *)RX_ERR);
0450     net->can.pde_rcvlist_all = proc_create_net_single(CAN_PROC_RCVLIST_ALL,
0451             0644, net->can.proc_dir, can_rcvlist_proc_show,
0452             (void *)RX_ALL);
0453     net->can.pde_rcvlist_fil = proc_create_net_single(CAN_PROC_RCVLIST_FIL,
0454             0644, net->can.proc_dir, can_rcvlist_proc_show,
0455             (void *)RX_FIL);
0456     net->can.pde_rcvlist_inv = proc_create_net_single(CAN_PROC_RCVLIST_INV,
0457             0644, net->can.proc_dir, can_rcvlist_proc_show,
0458             (void *)RX_INV);
0459     net->can.pde_rcvlist_eff = proc_create_net_single(CAN_PROC_RCVLIST_EFF,
0460             0644, net->can.proc_dir, can_rcvlist_eff_proc_show, NULL);
0461     net->can.pde_rcvlist_sff = proc_create_net_single(CAN_PROC_RCVLIST_SFF,
0462             0644, net->can.proc_dir, can_rcvlist_sff_proc_show, NULL);
0463 }
0464 
0465 /*
0466  * can_remove_proc - remove procfs entries and main CAN proc directory
0467  */
0468 void can_remove_proc(struct net *net)
0469 {
0470     if (!net->can.proc_dir)
0471         return;
0472 
0473     if (net->can.pde_stats)
0474         remove_proc_entry(CAN_PROC_STATS, net->can.proc_dir);
0475 
0476     if (net->can.pde_reset_stats)
0477         remove_proc_entry(CAN_PROC_RESET_STATS, net->can.proc_dir);
0478 
0479     if (net->can.pde_rcvlist_err)
0480         remove_proc_entry(CAN_PROC_RCVLIST_ERR, net->can.proc_dir);
0481 
0482     if (net->can.pde_rcvlist_all)
0483         remove_proc_entry(CAN_PROC_RCVLIST_ALL, net->can.proc_dir);
0484 
0485     if (net->can.pde_rcvlist_fil)
0486         remove_proc_entry(CAN_PROC_RCVLIST_FIL, net->can.proc_dir);
0487 
0488     if (net->can.pde_rcvlist_inv)
0489         remove_proc_entry(CAN_PROC_RCVLIST_INV, net->can.proc_dir);
0490 
0491     if (net->can.pde_rcvlist_eff)
0492         remove_proc_entry(CAN_PROC_RCVLIST_EFF, net->can.proc_dir);
0493 
0494     if (net->can.pde_rcvlist_sff)
0495         remove_proc_entry(CAN_PROC_RCVLIST_SFF, net->can.proc_dir);
0496 
0497     remove_proc_entry("can", net->proc_net);
0498 }