Impact: Attribute functions with __acquires(...) resp. __releases(...). Fix this sparse warnings: net/wanrouter/wanproc.c:82:13: warning: context imbalance in 'r_start' - wrong count at exit net/wanrouter/wanproc.c:103:13: warning: context imbalance in 'r_stop' - unexpected unlock net/wanrouter/wanmain.c:765:13: warning: context imbalance in 'lock_adapter_irq' - wrong count at exit net/wanrouter/wanmain.c:771:13: warning: context imbalance in 'unlock_adapter_irq' - unexpected unlock Signed-off-by: Hannes Eder <hannes@hanneseder.net> Signed-off-by: David S. Miller <davem@davemloft.net>
		
			
				
	
	
		
			381 lines
		
	
	
	
		
			9.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			381 lines
		
	
	
	
		
			9.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*****************************************************************************
 | 
						|
* wanproc.c	WAN Router Module. /proc filesystem interface.
 | 
						|
*
 | 
						|
*		This module is completely hardware-independent and provides
 | 
						|
*		access to the router using Linux /proc filesystem.
 | 
						|
*
 | 
						|
* Author: 	Gideon Hack
 | 
						|
*
 | 
						|
* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
 | 
						|
*
 | 
						|
*		This program is free software; you can redistribute it and/or
 | 
						|
*		modify it under the terms of the GNU General Public License
 | 
						|
*		as published by the Free Software Foundation; either version
 | 
						|
*		2 of the License, or (at your option) any later version.
 | 
						|
* ============================================================================
 | 
						|
* Jun 02, 1999  Gideon Hack	Updates for Linux 2.2.X kernels.
 | 
						|
* Jun 29, 1997	Alan Cox	Merged with 1.0.3 vendor code
 | 
						|
* Jan 29, 1997	Gene Kozin	v1.0.1. Implemented /proc read routines
 | 
						|
* Jan 30, 1997	Alan Cox	Hacked around for 2.1
 | 
						|
* Dec 13, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
#include <linux/init.h>		/* __initfunc et al. */
 | 
						|
#include <linux/stddef.h>	/* offsetof(), etc. */
 | 
						|
#include <linux/errno.h>	/* return codes */
 | 
						|
#include <linux/kernel.h>
 | 
						|
#include <linux/module.h>
 | 
						|
#include <linux/wanrouter.h>	/* WAN router API definitions */
 | 
						|
#include <linux/seq_file.h>
 | 
						|
#include <linux/smp_lock.h>
 | 
						|
 | 
						|
#include <net/net_namespace.h>
 | 
						|
#include <asm/io.h>
 | 
						|
 | 
						|
#define PROC_STATS_FORMAT "%30s: %12lu\n"
 | 
						|
 | 
						|
/****** Defines and Macros **************************************************/
 | 
						|
 | 
						|
#define PROT_DECODE(prot) ((prot == WANCONFIG_FR) ? " FR" :\
 | 
						|
			      (prot == WANCONFIG_X25) ? " X25" : \
 | 
						|
				 (prot == WANCONFIG_PPP) ? " PPP" : \
 | 
						|
				    (prot == WANCONFIG_CHDLC) ? " CHDLC": \
 | 
						|
				       (prot == WANCONFIG_MPPP) ? " MPPP" : \
 | 
						|
					   " Unknown" )
 | 
						|
 | 
						|
/****** Function Prototypes *************************************************/
 | 
						|
 | 
						|
#ifdef CONFIG_PROC_FS
 | 
						|
 | 
						|
/* Miscellaneous */
 | 
						|
 | 
						|
/*
 | 
						|
 *	Structures for interfacing with the /proc filesystem.
 | 
						|
 *	Router creates its own directory /proc/net/router with the folowing
 | 
						|
 *	entries:
 | 
						|
 *	config		device configuration
 | 
						|
 *	status		global device statistics
 | 
						|
 *	<device>	entry for each WAN device
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 *	Generic /proc/net/router/<file> file and inode operations
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 *	/proc/net/router
 | 
						|
 */
 | 
						|
 | 
						|
static struct proc_dir_entry *proc_router;
 | 
						|
 | 
						|
/* Strings */
 | 
						|
 | 
						|
/*
 | 
						|
 *	Interface functions
 | 
						|
 */
 | 
						|
 | 
						|
/****** Proc filesystem entry points ****************************************/
 | 
						|
 | 
						|
/*
 | 
						|
 *	Iterator
 | 
						|
 */
 | 
						|
static void *r_start(struct seq_file *m, loff_t *pos)
 | 
						|
	__acquires(kernel_lock)
 | 
						|
{
 | 
						|
	struct wan_device *wandev;
 | 
						|
	loff_t l = *pos;
 | 
						|
 | 
						|
	lock_kernel();
 | 
						|
	if (!l--)
 | 
						|
		return SEQ_START_TOKEN;
 | 
						|
	for (wandev = wanrouter_router_devlist; l-- && wandev;
 | 
						|
	     wandev = wandev->next)
 | 
						|
		;
 | 
						|
	return wandev;
 | 
						|
}
 | 
						|
 | 
						|
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
 | 
						|
{
 | 
						|
	struct wan_device *wandev = v;
 | 
						|
	(*pos)++;
 | 
						|
	return (v == SEQ_START_TOKEN) ? wanrouter_router_devlist : wandev->next;
 | 
						|
}
 | 
						|
 | 
						|
static void r_stop(struct seq_file *m, void *v)
 | 
						|
	__releases(kernel_lock)
 | 
						|
{
 | 
						|
	unlock_kernel();
 | 
						|
}
 | 
						|
 | 
						|
static int config_show(struct seq_file *m, void *v)
 | 
						|
{
 | 
						|
	struct wan_device *p = v;
 | 
						|
	if (v == SEQ_START_TOKEN) {
 | 
						|
		seq_puts(m, "Device name    | port |IRQ|DMA|  mem.addr  |"
 | 
						|
			    "mem.size|option1|option2|option3|option4\n");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	if (!p->state)
 | 
						|
		return 0;
 | 
						|
	seq_printf(m, "%-15s|0x%-4X|%3u|%3u| 0x%-8lX |0x%-6X|%7u|%7u|%7u|%7u\n",
 | 
						|
			p->name, p->ioport, p->irq, p->dma, p->maddr, p->msize,
 | 
						|
			p->hw_opt[0], p->hw_opt[1], p->hw_opt[2], p->hw_opt[3]);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int status_show(struct seq_file *m, void *v)
 | 
						|
{
 | 
						|
	struct wan_device *p = v;
 | 
						|
	if (v == SEQ_START_TOKEN) {
 | 
						|
		seq_puts(m, "Device name    |protocol|station|interface|"
 | 
						|
			    "clocking|baud rate| MTU |ndev|link state\n");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	if (!p->state)
 | 
						|
		return 0;
 | 
						|
	seq_printf(m, "%-15s|%-8s| %-7s| %-9s|%-8s|%9u|%5u|%3u |",
 | 
						|
		p->name,
 | 
						|
		PROT_DECODE(p->config_id),
 | 
						|
		p->config_id == WANCONFIG_FR ?
 | 
						|
			(p->station ? "Node" : "CPE") :
 | 
						|
			(p->config_id == WANCONFIG_X25 ?
 | 
						|
			(p->station ? "DCE" : "DTE") :
 | 
						|
			("N/A")),
 | 
						|
		p->interface ? "V.35" : "RS-232",
 | 
						|
		p->clocking ? "internal" : "external",
 | 
						|
		p->bps,
 | 
						|
		p->mtu,
 | 
						|
		p->ndev);
 | 
						|
 | 
						|
	switch (p->state) {
 | 
						|
	case WAN_UNCONFIGURED:
 | 
						|
		seq_printf(m, "%-12s\n", "unconfigured");
 | 
						|
		break;
 | 
						|
	case WAN_DISCONNECTED:
 | 
						|
		seq_printf(m, "%-12s\n", "disconnected");
 | 
						|
		break;
 | 
						|
	case WAN_CONNECTING:
 | 
						|
		seq_printf(m, "%-12s\n", "connecting");
 | 
						|
		break;
 | 
						|
	case WAN_CONNECTED:
 | 
						|
		seq_printf(m, "%-12s\n", "connected");
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		seq_printf(m, "%-12s\n", "invalid");
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static const struct seq_operations config_op = {
 | 
						|
	.start	= r_start,
 | 
						|
	.next	= r_next,
 | 
						|
	.stop	= r_stop,
 | 
						|
	.show	= config_show,
 | 
						|
};
 | 
						|
 | 
						|
static const struct seq_operations status_op = {
 | 
						|
	.start	= r_start,
 | 
						|
	.next	= r_next,
 | 
						|
	.stop	= r_stop,
 | 
						|
	.show	= status_show,
 | 
						|
};
 | 
						|
 | 
						|
static int config_open(struct inode *inode, struct file *file)
 | 
						|
{
 | 
						|
	return seq_open(file, &config_op);
 | 
						|
}
 | 
						|
 | 
						|
static int status_open(struct inode *inode, struct file *file)
 | 
						|
{
 | 
						|
	return seq_open(file, &status_op);
 | 
						|
}
 | 
						|
 | 
						|
static const struct file_operations config_fops = {
 | 
						|
	.owner	 = THIS_MODULE,
 | 
						|
	.open	 = config_open,
 | 
						|
	.read	 = seq_read,
 | 
						|
	.llseek	 = seq_lseek,
 | 
						|
	.release = seq_release,
 | 
						|
};
 | 
						|
 | 
						|
static const struct file_operations status_fops = {
 | 
						|
	.owner	 = THIS_MODULE,
 | 
						|
	.open	 = status_open,
 | 
						|
	.read	 = seq_read,
 | 
						|
	.llseek	 = seq_lseek,
 | 
						|
	.release = seq_release,
 | 
						|
};
 | 
						|
 | 
						|
static int wandev_show(struct seq_file *m, void *v)
 | 
						|
{
 | 
						|
	struct wan_device *wandev = m->private;
 | 
						|
 | 
						|
	if (wandev->magic != ROUTER_MAGIC)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if (!wandev->state) {
 | 
						|
		seq_puts(m, "device is not configured!\n");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Update device statistics */
 | 
						|
	if (wandev->update) {
 | 
						|
		int err = wandev->update(wandev);
 | 
						|
		if (err == -EAGAIN) {
 | 
						|
			seq_puts(m, "Device is busy!\n");
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		if (err) {
 | 
						|
			seq_puts(m, "Device is not configured!\n");
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"total packets received", wandev->stats.rx_packets);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"total packets transmitted", wandev->stats.tx_packets);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"total bytes received", wandev->stats.rx_bytes);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"total bytes transmitted", wandev->stats.tx_bytes);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"bad packets received", wandev->stats.rx_errors);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"packet transmit problems", wandev->stats.tx_errors);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"received frames dropped", wandev->stats.rx_dropped);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"transmit frames dropped", wandev->stats.tx_dropped);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"multicast packets received", wandev->stats.multicast);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"transmit collisions", wandev->stats.collisions);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"receive length errors", wandev->stats.rx_length_errors);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"receiver overrun errors", wandev->stats.rx_over_errors);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"CRC errors", wandev->stats.rx_crc_errors);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"frame format errors (aborts)", wandev->stats.rx_frame_errors);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"receiver fifo overrun", wandev->stats.rx_fifo_errors);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"receiver missed packet", wandev->stats.rx_missed_errors);
 | 
						|
	seq_printf(m, PROC_STATS_FORMAT,
 | 
						|
		"aborted frames transmitted", wandev->stats.tx_aborted_errors);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int wandev_open(struct inode *inode, struct file *file)
 | 
						|
{
 | 
						|
	return single_open(file, wandev_show, PDE(inode)->data);
 | 
						|
}
 | 
						|
 | 
						|
static const struct file_operations wandev_fops = {
 | 
						|
	.owner	 = THIS_MODULE,
 | 
						|
	.open	 = wandev_open,
 | 
						|
	.read	 = seq_read,
 | 
						|
	.llseek	 = seq_lseek,
 | 
						|
	.release = single_release,
 | 
						|
	.unlocked_ioctl  = wanrouter_ioctl,
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 *	Initialize router proc interface.
 | 
						|
 */
 | 
						|
 | 
						|
int __init wanrouter_proc_init(void)
 | 
						|
{
 | 
						|
	struct proc_dir_entry *p;
 | 
						|
	proc_router = proc_mkdir(ROUTER_NAME, init_net.proc_net);
 | 
						|
	if (!proc_router)
 | 
						|
		goto fail;
 | 
						|
 | 
						|
	p = proc_create("config", S_IRUGO, proc_router, &config_fops);
 | 
						|
	if (!p)
 | 
						|
		goto fail_config;
 | 
						|
	p = proc_create("status", S_IRUGO, proc_router, &status_fops);
 | 
						|
	if (!p)
 | 
						|
		goto fail_stat;
 | 
						|
	return 0;
 | 
						|
fail_stat:
 | 
						|
	remove_proc_entry("config", proc_router);
 | 
						|
fail_config:
 | 
						|
	remove_proc_entry(ROUTER_NAME, init_net.proc_net);
 | 
						|
fail:
 | 
						|
	return -ENOMEM;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *	Clean up router proc interface.
 | 
						|
 */
 | 
						|
 | 
						|
void wanrouter_proc_cleanup(void)
 | 
						|
{
 | 
						|
	remove_proc_entry("config", proc_router);
 | 
						|
	remove_proc_entry("status", proc_router);
 | 
						|
	remove_proc_entry(ROUTER_NAME, init_net.proc_net);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *	Add directory entry for WAN device.
 | 
						|
 */
 | 
						|
 | 
						|
int wanrouter_proc_add(struct wan_device* wandev)
 | 
						|
{
 | 
						|
	if (wandev->magic != ROUTER_MAGIC)
 | 
						|
		return -EINVAL;
 | 
						|
 | 
						|
	wandev->dent = proc_create(wandev->name, S_IRUGO,
 | 
						|
				   proc_router, &wandev_fops);
 | 
						|
	if (!wandev->dent)
 | 
						|
		return -ENOMEM;
 | 
						|
	wandev->dent->data	= wandev;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *	Delete directory entry for WAN device.
 | 
						|
 */
 | 
						|
int wanrouter_proc_delete(struct wan_device* wandev)
 | 
						|
{
 | 
						|
	if (wandev->magic != ROUTER_MAGIC)
 | 
						|
		return -EINVAL;
 | 
						|
	remove_proc_entry(wandev->name, proc_router);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
/*
 | 
						|
 *	No /proc - output stubs
 | 
						|
 */
 | 
						|
 | 
						|
int __init wanrouter_proc_init(void)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void wanrouter_proc_cleanup(void)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
int wanrouter_proc_add(struct wan_device *wandev)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int wanrouter_proc_delete(struct wan_device *wandev)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 *	End
 | 
						|
 */
 | 
						|
 |