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