at v3.7 421 lines 10 kB view raw
1/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors: 2 * 3 * Marek Lindner 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of version 2 of the GNU General Public 7 * License as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 * 02110-1301, USA 18 */ 19 20#include "main.h" 21 22#include <linux/debugfs.h> 23 24#include "debugfs.h" 25#include "translation-table.h" 26#include "originator.h" 27#include "hard-interface.h" 28#include "gateway_common.h" 29#include "gateway_client.h" 30#include "soft-interface.h" 31#include "vis.h" 32#include "icmp_socket.h" 33#include "bridge_loop_avoidance.h" 34 35static struct dentry *batadv_debugfs; 36 37#ifdef CONFIG_BATMAN_ADV_DEBUG 38#define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1) 39 40static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN; 41 42static char *batadv_log_char_addr(struct batadv_debug_log *debug_log, 43 size_t idx) 44{ 45 return &debug_log->log_buff[idx & BATADV_LOG_BUFF_MASK]; 46} 47 48static void batadv_emit_log_char(struct batadv_debug_log *debug_log, char c) 49{ 50 char *char_addr; 51 52 char_addr = batadv_log_char_addr(debug_log, debug_log->log_end); 53 *char_addr = c; 54 debug_log->log_end++; 55 56 if (debug_log->log_end - debug_log->log_start > batadv_log_buff_len) 57 debug_log->log_start = debug_log->log_end - batadv_log_buff_len; 58} 59 60__printf(2, 3) 61static int batadv_fdebug_log(struct batadv_debug_log *debug_log, 62 const char *fmt, ...) 63{ 64 va_list args; 65 static char debug_log_buf[256]; 66 char *p; 67 68 if (!debug_log) 69 return 0; 70 71 spin_lock_bh(&debug_log->lock); 72 va_start(args, fmt); 73 vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args); 74 va_end(args); 75 76 for (p = debug_log_buf; *p != 0; p++) 77 batadv_emit_log_char(debug_log, *p); 78 79 spin_unlock_bh(&debug_log->lock); 80 81 wake_up(&debug_log->queue_wait); 82 83 return 0; 84} 85 86int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...) 87{ 88 va_list args; 89 char tmp_log_buf[256]; 90 91 va_start(args, fmt); 92 vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); 93 batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s", 94 jiffies_to_msecs(jiffies), tmp_log_buf); 95 va_end(args); 96 97 return 0; 98} 99 100static int batadv_log_open(struct inode *inode, struct file *file) 101{ 102 nonseekable_open(inode, file); 103 file->private_data = inode->i_private; 104 batadv_inc_module_count(); 105 return 0; 106} 107 108static int batadv_log_release(struct inode *inode, struct file *file) 109{ 110 batadv_dec_module_count(); 111 return 0; 112} 113 114static int batadv_log_empty(struct batadv_debug_log *debug_log) 115{ 116 return !(debug_log->log_start - debug_log->log_end); 117} 118 119static ssize_t batadv_log_read(struct file *file, char __user *buf, 120 size_t count, loff_t *ppos) 121{ 122 struct batadv_priv *bat_priv = file->private_data; 123 struct batadv_debug_log *debug_log = bat_priv->debug_log; 124 int error, i = 0; 125 char *char_addr; 126 char c; 127 128 if ((file->f_flags & O_NONBLOCK) && batadv_log_empty(debug_log)) 129 return -EAGAIN; 130 131 if (!buf) 132 return -EINVAL; 133 134 if (count == 0) 135 return 0; 136 137 if (!access_ok(VERIFY_WRITE, buf, count)) 138 return -EFAULT; 139 140 error = wait_event_interruptible(debug_log->queue_wait, 141 (!batadv_log_empty(debug_log))); 142 143 if (error) 144 return error; 145 146 spin_lock_bh(&debug_log->lock); 147 148 while ((!error) && (i < count) && 149 (debug_log->log_start != debug_log->log_end)) { 150 char_addr = batadv_log_char_addr(debug_log, 151 debug_log->log_start); 152 c = *char_addr; 153 154 debug_log->log_start++; 155 156 spin_unlock_bh(&debug_log->lock); 157 158 error = __put_user(c, buf); 159 160 spin_lock_bh(&debug_log->lock); 161 162 buf++; 163 i++; 164 165 } 166 167 spin_unlock_bh(&debug_log->lock); 168 169 if (!error) 170 return i; 171 172 return error; 173} 174 175static unsigned int batadv_log_poll(struct file *file, poll_table *wait) 176{ 177 struct batadv_priv *bat_priv = file->private_data; 178 struct batadv_debug_log *debug_log = bat_priv->debug_log; 179 180 poll_wait(file, &debug_log->queue_wait, wait); 181 182 if (!batadv_log_empty(debug_log)) 183 return POLLIN | POLLRDNORM; 184 185 return 0; 186} 187 188static const struct file_operations batadv_log_fops = { 189 .open = batadv_log_open, 190 .release = batadv_log_release, 191 .read = batadv_log_read, 192 .poll = batadv_log_poll, 193 .llseek = no_llseek, 194}; 195 196static int batadv_debug_log_setup(struct batadv_priv *bat_priv) 197{ 198 struct dentry *d; 199 200 if (!bat_priv->debug_dir) 201 goto err; 202 203 bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC); 204 if (!bat_priv->debug_log) 205 goto err; 206 207 spin_lock_init(&bat_priv->debug_log->lock); 208 init_waitqueue_head(&bat_priv->debug_log->queue_wait); 209 210 d = debugfs_create_file("log", S_IFREG | S_IRUSR, 211 bat_priv->debug_dir, bat_priv, 212 &batadv_log_fops); 213 if (!d) 214 goto err; 215 216 return 0; 217 218err: 219 return -ENOMEM; 220} 221 222static void batadv_debug_log_cleanup(struct batadv_priv *bat_priv) 223{ 224 kfree(bat_priv->debug_log); 225 bat_priv->debug_log = NULL; 226} 227#else /* CONFIG_BATMAN_ADV_DEBUG */ 228static int batadv_debug_log_setup(struct batadv_priv *bat_priv) 229{ 230 bat_priv->debug_log = NULL; 231 return 0; 232} 233 234static void batadv_debug_log_cleanup(struct batadv_priv *bat_priv) 235{ 236 return; 237} 238#endif 239 240static int batadv_algorithms_open(struct inode *inode, struct file *file) 241{ 242 return single_open(file, batadv_algo_seq_print_text, NULL); 243} 244 245static int batadv_originators_open(struct inode *inode, struct file *file) 246{ 247 struct net_device *net_dev = (struct net_device *)inode->i_private; 248 return single_open(file, batadv_orig_seq_print_text, net_dev); 249} 250 251static int batadv_gateways_open(struct inode *inode, struct file *file) 252{ 253 struct net_device *net_dev = (struct net_device *)inode->i_private; 254 return single_open(file, batadv_gw_client_seq_print_text, net_dev); 255} 256 257static int batadv_transtable_global_open(struct inode *inode, struct file *file) 258{ 259 struct net_device *net_dev = (struct net_device *)inode->i_private; 260 return single_open(file, batadv_tt_global_seq_print_text, net_dev); 261} 262 263#ifdef CONFIG_BATMAN_ADV_BLA 264static int batadv_bla_claim_table_open(struct inode *inode, struct file *file) 265{ 266 struct net_device *net_dev = (struct net_device *)inode->i_private; 267 return single_open(file, batadv_bla_claim_table_seq_print_text, 268 net_dev); 269} 270 271static int batadv_bla_backbone_table_open(struct inode *inode, 272 struct file *file) 273{ 274 struct net_device *net_dev = (struct net_device *)inode->i_private; 275 return single_open(file, batadv_bla_backbone_table_seq_print_text, 276 net_dev); 277} 278 279#endif 280 281static int batadv_transtable_local_open(struct inode *inode, struct file *file) 282{ 283 struct net_device *net_dev = (struct net_device *)inode->i_private; 284 return single_open(file, batadv_tt_local_seq_print_text, net_dev); 285} 286 287static int batadv_vis_data_open(struct inode *inode, struct file *file) 288{ 289 struct net_device *net_dev = (struct net_device *)inode->i_private; 290 return single_open(file, batadv_vis_seq_print_text, net_dev); 291} 292 293struct batadv_debuginfo { 294 struct attribute attr; 295 const struct file_operations fops; 296}; 297 298#define BATADV_DEBUGINFO(_name, _mode, _open) \ 299struct batadv_debuginfo batadv_debuginfo_##_name = { \ 300 .attr = { .name = __stringify(_name), \ 301 .mode = _mode, }, \ 302 .fops = { .owner = THIS_MODULE, \ 303 .open = _open, \ 304 .read = seq_read, \ 305 .llseek = seq_lseek, \ 306 .release = single_release, \ 307 } \ 308}; 309 310static BATADV_DEBUGINFO(routing_algos, S_IRUGO, batadv_algorithms_open); 311static BATADV_DEBUGINFO(originators, S_IRUGO, batadv_originators_open); 312static BATADV_DEBUGINFO(gateways, S_IRUGO, batadv_gateways_open); 313static BATADV_DEBUGINFO(transtable_global, S_IRUGO, 314 batadv_transtable_global_open); 315#ifdef CONFIG_BATMAN_ADV_BLA 316static BATADV_DEBUGINFO(bla_claim_table, S_IRUGO, batadv_bla_claim_table_open); 317static BATADV_DEBUGINFO(bla_backbone_table, S_IRUGO, 318 batadv_bla_backbone_table_open); 319#endif 320static BATADV_DEBUGINFO(transtable_local, S_IRUGO, 321 batadv_transtable_local_open); 322static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open); 323 324static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { 325 &batadv_debuginfo_originators, 326 &batadv_debuginfo_gateways, 327 &batadv_debuginfo_transtable_global, 328#ifdef CONFIG_BATMAN_ADV_BLA 329 &batadv_debuginfo_bla_claim_table, 330 &batadv_debuginfo_bla_backbone_table, 331#endif 332 &batadv_debuginfo_transtable_local, 333 &batadv_debuginfo_vis_data, 334 NULL, 335}; 336 337void batadv_debugfs_init(void) 338{ 339 struct batadv_debuginfo *bat_debug; 340 struct dentry *file; 341 342 batadv_debugfs = debugfs_create_dir(BATADV_DEBUGFS_SUBDIR, NULL); 343 if (batadv_debugfs == ERR_PTR(-ENODEV)) 344 batadv_debugfs = NULL; 345 346 if (!batadv_debugfs) 347 goto out; 348 349 bat_debug = &batadv_debuginfo_routing_algos; 350 file = debugfs_create_file(bat_debug->attr.name, 351 S_IFREG | bat_debug->attr.mode, 352 batadv_debugfs, NULL, &bat_debug->fops); 353 if (!file) 354 pr_err("Can't add debugfs file: %s\n", bat_debug->attr.name); 355 356out: 357 return; 358} 359 360void batadv_debugfs_destroy(void) 361{ 362 if (batadv_debugfs) { 363 debugfs_remove_recursive(batadv_debugfs); 364 batadv_debugfs = NULL; 365 } 366} 367 368int batadv_debugfs_add_meshif(struct net_device *dev) 369{ 370 struct batadv_priv *bat_priv = netdev_priv(dev); 371 struct batadv_debuginfo **bat_debug; 372 struct dentry *file; 373 374 if (!batadv_debugfs) 375 goto out; 376 377 bat_priv->debug_dir = debugfs_create_dir(dev->name, batadv_debugfs); 378 if (!bat_priv->debug_dir) 379 goto out; 380 381 if (batadv_socket_setup(bat_priv) < 0) 382 goto rem_attr; 383 384 if (batadv_debug_log_setup(bat_priv) < 0) 385 goto rem_attr; 386 387 for (bat_debug = batadv_mesh_debuginfos; *bat_debug; ++bat_debug) { 388 file = debugfs_create_file(((*bat_debug)->attr).name, 389 S_IFREG | ((*bat_debug)->attr).mode, 390 bat_priv->debug_dir, 391 dev, &(*bat_debug)->fops); 392 if (!file) { 393 batadv_err(dev, "Can't add debugfs file: %s/%s\n", 394 dev->name, ((*bat_debug)->attr).name); 395 goto rem_attr; 396 } 397 } 398 399 return 0; 400rem_attr: 401 debugfs_remove_recursive(bat_priv->debug_dir); 402 bat_priv->debug_dir = NULL; 403out: 404#ifdef CONFIG_DEBUG_FS 405 return -ENOMEM; 406#else 407 return 0; 408#endif /* CONFIG_DEBUG_FS */ 409} 410 411void batadv_debugfs_del_meshif(struct net_device *dev) 412{ 413 struct batadv_priv *bat_priv = netdev_priv(dev); 414 415 batadv_debug_log_cleanup(bat_priv); 416 417 if (batadv_debugfs) { 418 debugfs_remove_recursive(bat_priv->debug_dir); 419 bat_priv->debug_dir = NULL; 420 } 421}