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