• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/batman-adv/
1/*
2 * Copyright (C) 2010 B.A.T.M.A.N. contributors:
3 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 *
20 */
21
22#include "main.h"
23
24#include <linux/debugfs.h>
25
26#include "bat_debugfs.h"
27#include "translation-table.h"
28#include "originator.h"
29#include "hard-interface.h"
30#include "vis.h"
31#include "icmp_socket.h"
32
33static struct dentry *bat_debugfs;
34
35#ifdef CONFIG_BATMAN_ADV_DEBUG
36#define LOG_BUFF_MASK (log_buff_len-1)
37#define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK])
38
39static int log_buff_len = LOG_BUF_LEN;
40
41static void emit_log_char(struct debug_log *debug_log, char c)
42{
43	LOG_BUFF(debug_log->log_end) = c;
44	debug_log->log_end++;
45
46	if (debug_log->log_end - debug_log->log_start > log_buff_len)
47		debug_log->log_start = debug_log->log_end - log_buff_len;
48}
49
50static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
51{
52	int printed_len;
53	va_list args;
54	static char debug_log_buf[256];
55	char *p;
56	unsigned long flags;
57
58	if (!debug_log)
59		return 0;
60
61	spin_lock_irqsave(&debug_log->lock, flags);
62	va_start(args, fmt);
63	printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf),
64				 fmt, args);
65	va_end(args);
66
67	for (p = debug_log_buf; *p != 0; p++)
68		emit_log_char(debug_log, *p);
69
70	spin_unlock_irqrestore(&debug_log->lock, flags);
71
72	wake_up(&debug_log->queue_wait);
73
74	return 0;
75}
76
77int debug_log(struct bat_priv *bat_priv, char *fmt, ...)
78{
79	va_list args;
80	char tmp_log_buf[256];
81
82	va_start(args, fmt);
83	vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
84	fdebug_log(bat_priv->debug_log, "[%10u] %s",
85		   (jiffies / HZ), tmp_log_buf);
86	va_end(args);
87
88	return 0;
89}
90
91static int log_open(struct inode *inode, struct file *file)
92{
93	file->private_data = inode->i_private;
94	inc_module_count();
95	return 0;
96}
97
98static int log_release(struct inode *inode, struct file *file)
99{
100	dec_module_count();
101	return 0;
102}
103
104static ssize_t log_read(struct file *file, char __user *buf,
105			size_t count, loff_t *ppos)
106{
107	struct bat_priv *bat_priv = file->private_data;
108	struct debug_log *debug_log = bat_priv->debug_log;
109	int error, i = 0;
110	char c;
111	unsigned long flags;
112
113	if ((file->f_flags & O_NONBLOCK) &&
114	    !(debug_log->log_end - debug_log->log_start))
115		return -EAGAIN;
116
117	if ((!buf) || (count < 0))
118		return -EINVAL;
119
120	if (count == 0)
121		return 0;
122
123	if (!access_ok(VERIFY_WRITE, buf, count))
124		return -EFAULT;
125
126	error = wait_event_interruptible(debug_log->queue_wait,
127				(debug_log->log_start - debug_log->log_end));
128
129	if (error)
130		return error;
131
132	spin_lock_irqsave(&debug_log->lock, flags);
133
134	while ((!error) && (i < count) &&
135	       (debug_log->log_start != debug_log->log_end)) {
136		c = LOG_BUFF(debug_log->log_start);
137
138		debug_log->log_start++;
139
140		spin_unlock_irqrestore(&debug_log->lock, flags);
141
142		error = __put_user(c, buf);
143
144		spin_lock_irqsave(&debug_log->lock, flags);
145
146		buf++;
147		i++;
148
149	}
150
151	spin_unlock_irqrestore(&debug_log->lock, flags);
152
153	if (!error)
154		return i;
155
156	return error;
157}
158
159static unsigned int log_poll(struct file *file, poll_table *wait)
160{
161	struct bat_priv *bat_priv = file->private_data;
162	struct debug_log *debug_log = bat_priv->debug_log;
163
164	poll_wait(file, &debug_log->queue_wait, wait);
165
166	if (debug_log->log_end - debug_log->log_start)
167		return POLLIN | POLLRDNORM;
168
169	return 0;
170}
171
172static const struct file_operations log_fops = {
173	.open           = log_open,
174	.release        = log_release,
175	.read           = log_read,
176	.poll           = log_poll,
177};
178
179static int debug_log_setup(struct bat_priv *bat_priv)
180{
181	struct dentry *d;
182
183	if (!bat_priv->debug_dir)
184		goto err;
185
186	bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC);
187	if (!bat_priv->debug_log)
188		goto err;
189
190	spin_lock_init(&bat_priv->debug_log->lock);
191	init_waitqueue_head(&bat_priv->debug_log->queue_wait);
192
193	d = debugfs_create_file("log", S_IFREG | S_IRUSR,
194				bat_priv->debug_dir, bat_priv, &log_fops);
195	if (d)
196		goto err;
197
198	return 0;
199
200err:
201	return 1;
202}
203
204static void debug_log_cleanup(struct bat_priv *bat_priv)
205{
206	kfree(bat_priv->debug_log);
207	bat_priv->debug_log = NULL;
208}
209#else /* CONFIG_BATMAN_ADV_DEBUG */
210static int debug_log_setup(struct bat_priv *bat_priv)
211{
212	bat_priv->debug_log = NULL;
213	return 0;
214}
215
216static void debug_log_cleanup(struct bat_priv *bat_priv)
217{
218	return;
219}
220#endif
221
222static int originators_open(struct inode *inode, struct file *file)
223{
224	struct net_device *net_dev = (struct net_device *)inode->i_private;
225	return single_open(file, orig_seq_print_text, net_dev);
226}
227
228static int transtable_global_open(struct inode *inode, struct file *file)
229{
230	struct net_device *net_dev = (struct net_device *)inode->i_private;
231	return single_open(file, hna_global_seq_print_text, net_dev);
232}
233
234static int transtable_local_open(struct inode *inode, struct file *file)
235{
236	struct net_device *net_dev = (struct net_device *)inode->i_private;
237	return single_open(file, hna_local_seq_print_text, net_dev);
238}
239
240static int vis_data_open(struct inode *inode, struct file *file)
241{
242	struct net_device *net_dev = (struct net_device *)inode->i_private;
243	return single_open(file, vis_seq_print_text, net_dev);
244}
245
246struct bat_debuginfo {
247	struct attribute attr;
248	const struct file_operations fops;
249};
250
251#define BAT_DEBUGINFO(_name, _mode, _open)	\
252struct bat_debuginfo bat_debuginfo_##_name = {	\
253	.attr = { .name = __stringify(_name),	\
254		  .mode = _mode, },		\
255	.fops = { .owner = THIS_MODULE,		\
256		  .open = _open,		\
257		  .read	= seq_read,		\
258		  .llseek = seq_lseek,		\
259		  .release = single_release,	\
260		}				\
261};
262
263static BAT_DEBUGINFO(originators, S_IRUGO, originators_open);
264static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open);
265static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open);
266static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open);
267
268static struct bat_debuginfo *mesh_debuginfos[] = {
269	&bat_debuginfo_originators,
270	&bat_debuginfo_transtable_global,
271	&bat_debuginfo_transtable_local,
272	&bat_debuginfo_vis_data,
273	NULL,
274};
275
276void debugfs_init(void)
277{
278	bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL);
279	if (bat_debugfs == ERR_PTR(-ENODEV))
280		bat_debugfs = NULL;
281}
282
283void debugfs_destroy(void)
284{
285	if (bat_debugfs) {
286		debugfs_remove_recursive(bat_debugfs);
287		bat_debugfs = NULL;
288	}
289}
290
291int debugfs_add_meshif(struct net_device *dev)
292{
293	struct bat_priv *bat_priv = netdev_priv(dev);
294	struct bat_debuginfo **bat_debug;
295	struct dentry *file;
296
297	if (!bat_debugfs)
298		goto out;
299
300	bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs);
301	if (!bat_priv->debug_dir)
302		goto out;
303
304	bat_socket_setup(bat_priv);
305	debug_log_setup(bat_priv);
306
307	for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) {
308		file = debugfs_create_file(((*bat_debug)->attr).name,
309					  S_IFREG | ((*bat_debug)->attr).mode,
310					  bat_priv->debug_dir,
311					  dev, &(*bat_debug)->fops);
312		if (!file) {
313			bat_err(dev, "Can't add debugfs file: %s/%s\n",
314				dev->name, ((*bat_debug)->attr).name);
315			goto rem_attr;
316		}
317	}
318
319	return 0;
320rem_attr:
321	debugfs_remove_recursive(bat_priv->debug_dir);
322	bat_priv->debug_dir = NULL;
323out:
324#ifdef CONFIG_DEBUG_FS
325	return -ENOMEM;
326#else
327	return 0;
328#endif /* CONFIG_DEBUG_FS */
329}
330
331void debugfs_del_meshif(struct net_device *dev)
332{
333	struct bat_priv *bat_priv = netdev_priv(dev);
334
335	debug_log_cleanup(bat_priv);
336
337	if (bat_debugfs) {
338		debugfs_remove_recursive(bat_priv->debug_dir);
339		bat_priv->debug_dir = NULL;
340	}
341}
342