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 65 static int user_reset; 66 67 static const char rx_list_name[][8] = { 68 [RX_ERR] = "rx_err", 69 [RX_ALL] = "rx_all", 70 [RX_FIL] = "rx_fil", 71 [RX_INV] = "rx_inv", 72 }; 73 74 /* 75 * af_can statistics stuff 76 */ 77 78 static void can_init_stats(void) 79 { 80 /* 81 * This memset function is called from a timer context (when 82 * can_stattimer is active which is the default) OR in a process 83 * context (reading the proc_fs when can_stattimer is disabled). 84 */ 85 memset(&can_stats, 0, sizeof(can_stats)); 86 can_stats.jiffies_init = jiffies; 87 88 can_pstats.stats_reset++; 89 90 if (user_reset) { 91 user_reset = 0; 92 can_pstats.user_reset++; 93 } 94 } 95 96 static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif, 97 unsigned long count) 98 { 99 unsigned long rate; 100 101 if (oldjif == newjif) 102 return 0; 103 104 /* see can_stat_update() - this should NEVER happen! */ 105 if (count > (ULONG_MAX / HZ)) { 106 printk(KERN_ERR "can: calc_rate: count exceeded! %ld\n", 107 count); 108 return 99999999; 109 } 110 111 rate = (count * HZ) / (newjif - oldjif); 112 113 return rate; 114 } 115 116 void can_stat_update(unsigned long data) 117 { 118 unsigned long j = jiffies; /* snapshot */ 119 120 /* restart counting in timer context on user request */ 121 if (user_reset) 122 can_init_stats(); 123 124 /* restart counting on jiffies overflow */ 125 if (j < can_stats.jiffies_init) 126 can_init_stats(); 127 128 /* prevent overflow in calc_rate() */ 129 if (can_stats.rx_frames > (ULONG_MAX / HZ)) 130 can_init_stats(); 131 132 /* prevent overflow in calc_rate() */ 133 if (can_stats.tx_frames > (ULONG_MAX / HZ)) 134 can_init_stats(); 135 136 /* matches overflow - very improbable */ 137 if (can_stats.matches > (ULONG_MAX / 100)) 138 can_init_stats(); 139 140 /* calc total values */ 141 if (can_stats.rx_frames) 142 can_stats.total_rx_match_ratio = (can_stats.matches * 100) / 143 can_stats.rx_frames; 144 145 can_stats.total_tx_rate = calc_rate(can_stats.jiffies_init, j, 146 can_stats.tx_frames); 147 can_stats.total_rx_rate = calc_rate(can_stats.jiffies_init, j, 148 can_stats.rx_frames); 149 150 /* calc current values */ 151 if (can_stats.rx_frames_delta) 152 can_stats.current_rx_match_ratio = 153 (can_stats.matches_delta * 100) / 154 can_stats.rx_frames_delta; 155 156 can_stats.current_tx_rate = calc_rate(0, HZ, can_stats.tx_frames_delta); 157 can_stats.current_rx_rate = calc_rate(0, HZ, can_stats.rx_frames_delta); 158 159 /* check / update maximum values */ 160 if (can_stats.max_tx_rate < can_stats.current_tx_rate) 161 can_stats.max_tx_rate = can_stats.current_tx_rate; 162 163 if (can_stats.max_rx_rate < can_stats.current_rx_rate) 164 can_stats.max_rx_rate = can_stats.current_rx_rate; 165 166 if (can_stats.max_rx_match_ratio < can_stats.current_rx_match_ratio) 167 can_stats.max_rx_match_ratio = can_stats.current_rx_match_ratio; 168 169 /* clear values for 'current rate' calculation */ 170 can_stats.tx_frames_delta = 0; 171 can_stats.rx_frames_delta = 0; 172 can_stats.matches_delta = 0; 173 174 /* restart timer (one second) */ 175 mod_timer(&can_stattimer, round_jiffies(jiffies + HZ)); 176 } 177 178 /* 179 * proc read functions 180 */ 181 182 static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, 183 struct net_device *dev) 184 { 185 struct receiver *r; 186 187 hlist_for_each_entry_rcu(r, rx_list, list) { 188 char *fmt = (r->can_id & CAN_EFF_FLAG)? 189 " %-5s %08x %08x %pK %pK %8ld %s\n" : 190 " %-5s %03x %08x %pK %pK %8ld %s\n"; 191 192 seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask, 193 r->func, r->data, r->matches, r->ident); 194 } 195 } 196 197 static void can_print_recv_banner(struct seq_file *m) 198 { 199 /* 200 * can1. 00000000 00000000 00000000 201 * ....... 0 tp20 202 */ 203 seq_puts(m, " device can_id can_mask function" 204 " userdata matches ident\n"); 205 } 206 207 static int can_stats_proc_show(struct seq_file *m, void *v) 208 { 209 seq_putc(m, '\n'); 210 seq_printf(m, " %8ld transmitted frames (TXF)\n", can_stats.tx_frames); 211 seq_printf(m, " %8ld received frames (RXF)\n", can_stats.rx_frames); 212 seq_printf(m, " %8ld matched frames (RXMF)\n", can_stats.matches); 213 214 seq_putc(m, '\n'); 215 216 if (can_stattimer.function == can_stat_update) { 217 seq_printf(m, " %8ld %% total match ratio (RXMR)\n", 218 can_stats.total_rx_match_ratio); 219 220 seq_printf(m, " %8ld frames/s total tx rate (TXR)\n", 221 can_stats.total_tx_rate); 222 seq_printf(m, " %8ld frames/s total rx rate (RXR)\n", 223 can_stats.total_rx_rate); 224 225 seq_putc(m, '\n'); 226 227 seq_printf(m, " %8ld %% current match ratio (CRXMR)\n", 228 can_stats.current_rx_match_ratio); 229 230 seq_printf(m, " %8ld frames/s current tx rate (CTXR)\n", 231 can_stats.current_tx_rate); 232 seq_printf(m, " %8ld frames/s current rx rate (CRXR)\n", 233 can_stats.current_rx_rate); 234 235 seq_putc(m, '\n'); 236 237 seq_printf(m, " %8ld %% max match ratio (MRXMR)\n", 238 can_stats.max_rx_match_ratio); 239 240 seq_printf(m, " %8ld frames/s max tx rate (MTXR)\n", 241 can_stats.max_tx_rate); 242 seq_printf(m, " %8ld frames/s max rx rate (MRXR)\n", 243 can_stats.max_rx_rate); 244 245 seq_putc(m, '\n'); 246 } 247 248 seq_printf(m, " %8ld current receive list entries (CRCV)\n", 249 can_pstats.rcv_entries); 250 seq_printf(m, " %8ld maximum receive list entries (MRCV)\n", 251 can_pstats.rcv_entries_max); 252 253 if (can_pstats.stats_reset) 254 seq_printf(m, "\n %8ld statistic resets (STR)\n", 255 can_pstats.stats_reset); 256 257 if (can_pstats.user_reset) 258 seq_printf(m, " %8ld user statistic resets (USTR)\n", 259 can_pstats.user_reset); 260 261 seq_putc(m, '\n'); 262 return 0; 263 } 264 265 static int can_stats_proc_open(struct inode *inode, struct file *file) 266 { 267 return single_open(file, can_stats_proc_show, NULL); 268 } 269 270 static const struct file_operations can_stats_proc_fops = { 271 .owner = THIS_MODULE, 272 .open = can_stats_proc_open, 273 .read = seq_read, 274 .llseek = seq_lseek, 275 .release = single_release, 276 }; 277 278 static int can_reset_stats_proc_show(struct seq_file *m, void *v) 279 { 280 user_reset = 1; 281 282 if (can_stattimer.function == can_stat_update) { 283 seq_printf(m, "Scheduled statistic reset #%ld.\n", 284 can_pstats.stats_reset + 1); 285 286 } else { 287 if (can_stats.jiffies_init != jiffies) 288 can_init_stats(); 289 290 seq_printf(m, "Performed statistic reset #%ld.\n", 291 can_pstats.stats_reset); 292 } 293 return 0; 294 } 295 296 static int can_reset_stats_proc_open(struct inode *inode, struct file *file) 297 { 298 return single_open(file, can_reset_stats_proc_show, NULL); 299 } 300 301 static const struct file_operations can_reset_stats_proc_fops = { 302 .owner = THIS_MODULE, 303 .open = can_reset_stats_proc_open, 304 .read = seq_read, 305 .llseek = seq_lseek, 306 .release = single_release, 307 }; 308 309 static int can_version_proc_show(struct seq_file *m, void *v) 310 { 311 seq_printf(m, "%s\n", CAN_VERSION_STRING); 312 return 0; 313 } 314 315 static int can_version_proc_open(struct inode *inode, struct file *file) 316 { 317 return single_open(file, can_version_proc_show, NULL); 318 } 319 320 static const struct file_operations can_version_proc_fops = { 321 .owner = THIS_MODULE, 322 .open = can_version_proc_open, 323 .read = seq_read, 324 .llseek = seq_lseek, 325 .release = single_release, 326 }; 327 328 static inline void can_rcvlist_proc_show_one(struct seq_file *m, int idx, 329 struct net_device *dev, 330 struct dev_rcv_lists *d) 331 { 332 if (!hlist_empty(&d->rx[idx])) { 333 can_print_recv_banner(m); 334 can_print_rcvlist(m, &d->rx[idx], dev); 335 } else 336 seq_printf(m, " (%s: no entry)\n", DNAME(dev)); 337 338 } 339 340 static int can_rcvlist_proc_show(struct seq_file *m, void *v) 341 { 342 /* double cast to prevent GCC warning */ 343 int idx = (int)(long)PDE_DATA(m->file->f_inode); 344 struct net_device *dev; 345 struct dev_rcv_lists *d; 346 struct net *net = m->private; 347 348 seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]); 349 350 rcu_read_lock(); 351 352 /* receive list for 'all' CAN devices (dev == NULL) */ 353 d = net->can.can_rx_alldev_list; 354 can_rcvlist_proc_show_one(m, idx, NULL, d); 355 356 /* receive list for registered CAN devices */ 357 for_each_netdev_rcu(net, dev) { 358 if (dev->type == ARPHRD_CAN && dev->ml_priv) 359 can_rcvlist_proc_show_one(m, idx, dev, dev->ml_priv); 360 } 361 362 rcu_read_unlock(); 363 364 seq_putc(m, '\n'); 365 return 0; 366 } 367 368 static int can_rcvlist_proc_open(struct inode *inode, struct file *file) 369 { 370 return single_open_net(inode, file, can_rcvlist_proc_show); 371 } 372 373 static const struct file_operations can_rcvlist_proc_fops = { 374 .owner = THIS_MODULE, 375 .open = can_rcvlist_proc_open, 376 .read = seq_read, 377 .llseek = seq_lseek, 378 .release = single_release, 379 }; 380 381 static inline void can_rcvlist_proc_show_array(struct seq_file *m, 382 struct net_device *dev, 383 struct hlist_head *rcv_array, 384 unsigned int rcv_array_sz) 385 { 386 unsigned int i; 387 int all_empty = 1; 388 389 /* check whether at least one list is non-empty */ 390 for (i = 0; i < rcv_array_sz; i++) 391 if (!hlist_empty(&rcv_array[i])) { 392 all_empty = 0; 393 break; 394 } 395 396 if (!all_empty) { 397 can_print_recv_banner(m); 398 for (i = 0; i < rcv_array_sz; i++) { 399 if (!hlist_empty(&rcv_array[i])) 400 can_print_rcvlist(m, &rcv_array[i], dev); 401 } 402 } else 403 seq_printf(m, " (%s: no entry)\n", DNAME(dev)); 404 } 405 406 static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v) 407 { 408 struct net_device *dev; 409 struct dev_rcv_lists *d; 410 struct net *net = m->private; 411 412 /* RX_SFF */ 413 seq_puts(m, "\nreceive list 'rx_sff':\n"); 414 415 rcu_read_lock(); 416 417 /* sff receive list for 'all' CAN devices (dev == NULL) */ 418 d = net->can.can_rx_alldev_list; 419 can_rcvlist_proc_show_array(m, NULL, d->rx_sff, ARRAY_SIZE(d->rx_sff)); 420 421 /* sff receive list for registered CAN devices */ 422 for_each_netdev_rcu(net, dev) { 423 if (dev->type == ARPHRD_CAN && dev->ml_priv) { 424 d = dev->ml_priv; 425 can_rcvlist_proc_show_array(m, dev, d->rx_sff, 426 ARRAY_SIZE(d->rx_sff)); 427 } 428 } 429 430 rcu_read_unlock(); 431 432 seq_putc(m, '\n'); 433 return 0; 434 } 435 436 static int can_rcvlist_sff_proc_open(struct inode *inode, struct file *file) 437 { 438 return single_open_net(inode, file, can_rcvlist_sff_proc_show); 439 } 440 441 static const struct file_operations can_rcvlist_sff_proc_fops = { 442 .owner = THIS_MODULE, 443 .open = can_rcvlist_sff_proc_open, 444 .read = seq_read, 445 .llseek = seq_lseek, 446 .release = single_release, 447 }; 448 449 450 static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v) 451 { 452 struct net_device *dev; 453 struct dev_rcv_lists *d; 454 struct net *net = m->private; 455 456 /* RX_EFF */ 457 seq_puts(m, "\nreceive list 'rx_eff':\n"); 458 459 rcu_read_lock(); 460 461 /* eff receive list for 'all' CAN devices (dev == NULL) */ 462 d = net->can.can_rx_alldev_list; 463 can_rcvlist_proc_show_array(m, NULL, d->rx_eff, ARRAY_SIZE(d->rx_eff)); 464 465 /* eff receive list for registered CAN devices */ 466 for_each_netdev_rcu(net, dev) { 467 if (dev->type == ARPHRD_CAN && dev->ml_priv) { 468 d = dev->ml_priv; 469 can_rcvlist_proc_show_array(m, dev, d->rx_eff, 470 ARRAY_SIZE(d->rx_eff)); 471 } 472 } 473 474 rcu_read_unlock(); 475 476 seq_putc(m, '\n'); 477 return 0; 478 } 479 480 static int can_rcvlist_eff_proc_open(struct inode *inode, struct file *file) 481 { 482 return single_open_net(inode, file, can_rcvlist_eff_proc_show); 483 } 484 485 static const struct file_operations can_rcvlist_eff_proc_fops = { 486 .owner = THIS_MODULE, 487 .open = can_rcvlist_eff_proc_open, 488 .read = seq_read, 489 .llseek = seq_lseek, 490 .release = single_release, 491 }; 492 493 /* 494 * can_init_proc - create main CAN proc directory and procfs entries 495 */ 496 void can_init_proc(struct net *net) 497 { 498 /* create /proc/net/can directory */ 499 net->can.proc_dir = proc_net_mkdir(net, "can", net->proc_net); 500 501 if (!net->can.proc_dir) { 502 printk(KERN_INFO "can: failed to create /proc/net/can . " 503 "CONFIG_PROC_FS missing?\n"); 504 return; 505 } 506 507 /* own procfs entries from the AF_CAN core */ 508 net->can.pde_version = proc_create(CAN_PROC_VERSION, 0644, 509 net->can.proc_dir, 510 &can_version_proc_fops); 511 net->can.pde_stats = proc_create(CAN_PROC_STATS, 0644, 512 net->can.proc_dir, 513 &can_stats_proc_fops); 514 net->can.pde_reset_stats = proc_create(CAN_PROC_RESET_STATS, 0644, 515 net->can.proc_dir, 516 &can_reset_stats_proc_fops); 517 net->can.pde_rcvlist_err = proc_create_data(CAN_PROC_RCVLIST_ERR, 0644, 518 net->can.proc_dir, 519 &can_rcvlist_proc_fops, 520 (void *)RX_ERR); 521 net->can.pde_rcvlist_all = proc_create_data(CAN_PROC_RCVLIST_ALL, 0644, 522 net->can.proc_dir, 523 &can_rcvlist_proc_fops, 524 (void *)RX_ALL); 525 net->can.pde_rcvlist_fil = proc_create_data(CAN_PROC_RCVLIST_FIL, 0644, 526 net->can.proc_dir, 527 &can_rcvlist_proc_fops, 528 (void *)RX_FIL); 529 net->can.pde_rcvlist_inv = proc_create_data(CAN_PROC_RCVLIST_INV, 0644, 530 net->can.proc_dir, 531 &can_rcvlist_proc_fops, 532 (void *)RX_INV); 533 net->can.pde_rcvlist_eff = proc_create(CAN_PROC_RCVLIST_EFF, 0644, 534 net->can.proc_dir, 535 &can_rcvlist_eff_proc_fops); 536 net->can.pde_rcvlist_sff = proc_create(CAN_PROC_RCVLIST_SFF, 0644, 537 net->can.proc_dir, 538 &can_rcvlist_sff_proc_fops); 539 } 540 541 /* 542 * can_remove_proc - remove procfs entries and main CAN proc directory 543 */ 544 void can_remove_proc(struct net *net) 545 { 546 if (net->can.pde_version) 547 remove_proc_entry(CAN_PROC_VERSION, net->can.proc_dir); 548 549 if (net->can.pde_stats) 550 remove_proc_entry(CAN_PROC_STATS, net->can.proc_dir); 551 552 if (net->can.pde_reset_stats) 553 remove_proc_entry(CAN_PROC_RESET_STATS, net->can.proc_dir); 554 555 if (net->can.pde_rcvlist_err) 556 remove_proc_entry(CAN_PROC_RCVLIST_ERR, net->can.proc_dir); 557 558 if (net->can.pde_rcvlist_all) 559 remove_proc_entry(CAN_PROC_RCVLIST_ALL, net->can.proc_dir); 560 561 if (net->can.pde_rcvlist_fil) 562 remove_proc_entry(CAN_PROC_RCVLIST_FIL, net->can.proc_dir); 563 564 if (net->can.pde_rcvlist_inv) 565 remove_proc_entry(CAN_PROC_RCVLIST_INV, net->can.proc_dir); 566 567 if (net->can.pde_rcvlist_eff) 568 remove_proc_entry(CAN_PROC_RCVLIST_EFF, net->can.proc_dir); 569 570 if (net->can.pde_rcvlist_sff) 571 remove_proc_entry(CAN_PROC_RCVLIST_SFF, net->can.proc_dir); 572 573 if (net->can.proc_dir) 574 remove_proc_entry("can", net->proc_net); 575 } 576