2005-04-17 02:20:36 +04:00
/*
* linux / drivers / net / netconsole . c
*
* Copyright ( C ) 2001 Ingo Molnar < mingo @ redhat . com >
*
* This file contains the implementation of an IRQ - safe , crash - safe
* kernel console implementation that outputs kernel messages to the
* network .
*
* Modification history :
*
* 2001 - 09 - 17 started by Ingo Molnar .
* 2003 - 08 - 11 2.6 port by Matt Mackall
* simplified options
* generic card hooks
* works non - modular
* 2003 - 09 - 07 rewritten with netpoll api
*/
/****************************************************************
* 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 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/mm.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/console.h>
# include <linux/moduleparam.h>
# include <linux/string.h>
# include <linux/netpoll.h>
MODULE_AUTHOR ( " Maintainer: Matt Mackall <mpm@selenic.com> " ) ;
MODULE_DESCRIPTION ( " Console driver for network interfaces " ) ;
MODULE_LICENSE ( " GPL " ) ;
2007-08-11 02:27:24 +04:00
# define MAX_PARAM_LENGTH 256
# define MAX_PRINT_CHUNK 1000
static char config [ MAX_PARAM_LENGTH ] ;
module_param_string ( netconsole , config , MAX_PARAM_LENGTH , 0 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( netconsole , " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr] \n " ) ;
2007-08-11 02:29:47 +04:00
# ifndef MODULE
static int __init option_setup ( char * opt )
{
strlcpy ( config , opt , MAX_PARAM_LENGTH ) ;
return 1 ;
}
__setup ( " netconsole= " , option_setup ) ;
# endif /* MODULE */
2007-08-11 02:32:14 +04:00
/**
* struct netconsole_target - Represents a configured netconsole target .
* @ np : The netpoll structure for this target .
*/
struct netconsole_target {
struct netpoll np ;
} ;
static struct netconsole_target default_target = {
. np = {
. name = " netconsole " ,
. dev_name = " eth0 " ,
. local_port = 6665 ,
. remote_port = 6666 ,
. remote_mac = { 0xff , 0xff , 0xff , 0xff , 0xff , 0xff } ,
} ,
2005-04-17 02:20:36 +04:00
} ;
2007-08-11 02:33:01 +04:00
/* Handle network interface device notifications */
static int netconsole_netdev_event ( struct notifier_block * this ,
unsigned long event ,
void * ptr )
{
struct net_device * dev = ptr ;
struct netconsole_target * nt = & default_target ;
if ( nt - > np . dev = = dev ) {
switch ( event ) {
case NETDEV_CHANGEADDR :
memcpy ( nt - > np . local_mac , dev - > dev_addr , ETH_ALEN ) ;
break ;
case NETDEV_CHANGENAME :
strlcpy ( nt - > np . dev_name , dev - > name , IFNAMSIZ ) ;
break ;
}
}
return NOTIFY_DONE ;
}
static struct notifier_block netconsole_netdev_notifier = {
. notifier_call = netconsole_netdev_event ,
} ;
2005-04-17 02:20:36 +04:00
static void write_msg ( struct console * con , const char * msg , unsigned int len )
{
int frag , left ;
unsigned long flags ;
2007-08-11 02:32:14 +04:00
struct netconsole_target * nt = & default_target ;
2005-04-17 02:20:36 +04:00
2007-08-11 02:32:14 +04:00
if ( netif_running ( nt - > np . dev ) ) {
2007-08-11 02:30:31 +04:00
local_irq_save ( flags ) ;
for ( left = len ; left ; ) {
frag = min ( left , MAX_PRINT_CHUNK ) ;
2007-08-11 02:32:14 +04:00
netpoll_send_udp ( & nt - > np , msg , frag ) ;
2007-08-11 02:30:31 +04:00
msg + = frag ;
left - = frag ;
}
local_irq_restore ( flags ) ;
2005-04-17 02:20:36 +04:00
}
}
static struct console netconsole = {
2007-08-11 02:27:24 +04:00
. name = " netcon " ,
. flags = CON_ENABLED | CON_PRINTBUFFER ,
. write = write_msg ,
2005-04-17 02:20:36 +04:00
} ;
2007-08-11 02:27:24 +04:00
static int __init init_netconsole ( void )
2005-04-17 02:20:36 +04:00
{
2007-08-11 02:27:24 +04:00
int err = 0 ;
2007-08-11 02:32:14 +04:00
struct netconsole_target * nt = & default_target ;
2006-10-27 02:46:52 +04:00
2007-08-11 02:29:47 +04:00
if ( ! strnlen ( config , MAX_PARAM_LENGTH ) ) {
2007-08-11 02:27:24 +04:00
printk ( KERN_INFO " netconsole: not configured, aborting \n " ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2007-08-11 02:32:14 +04:00
err = netpoll_parse_options ( & nt - > np , config ) ;
2007-08-11 02:29:47 +04:00
if ( err )
goto out ;
2007-08-11 02:32:14 +04:00
err = netpoll_setup ( & nt - > np ) ;
2006-10-27 02:46:52 +04:00
if ( err )
2007-08-11 02:27:24 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
2007-08-11 02:33:01 +04:00
err = register_netdevice_notifier ( & netconsole_netdev_notifier ) ;
if ( err )
goto out ;
2005-04-17 02:20:36 +04:00
register_console ( & netconsole ) ;
printk ( KERN_INFO " netconsole: network logging started \n " ) ;
2007-08-11 02:27:24 +04:00
out :
return err ;
2005-04-17 02:20:36 +04:00
}
2007-08-11 02:27:24 +04:00
static void __exit cleanup_netconsole ( void )
2005-04-17 02:20:36 +04:00
{
2007-08-11 02:32:14 +04:00
struct netconsole_target * nt = & default_target ;
2005-04-17 02:20:36 +04:00
unregister_console ( & netconsole ) ;
2007-08-11 02:33:01 +04:00
unregister_netdevice_notifier ( & netconsole_netdev_notifier ) ;
2007-08-11 02:32:14 +04:00
netpoll_cleanup ( & nt - > np ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( init_netconsole ) ;
module_exit ( cleanup_netconsole ) ;