2007-10-16 12:27:29 +04:00
/*
* Copyright ( C ) 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
* Licensed under the GPL .
*/
2005-04-17 02:20:36 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <errno.h>
2007-10-16 12:27:29 +04:00
# include <fcntl.h>
# include <string.h>
2005-04-17 02:20:36 +04:00
# include <sys/termios.h>
# include <sys/wait.h>
# include "net_user.h"
# include "os.h"
2007-10-16 12:27:29 +04:00
# include "slip.h"
2006-10-20 10:28:20 +04:00
# include "um_malloc.h"
2005-04-17 02:20:36 +04:00
uml: network interface hotplug error handling
This fixes a number of problems associated with network interface hotplug.
The userspace initialization function can fail in some cases, but the
failure was never passed back to eth_configure, which proceeded with the
configuration. This results in a zombie device that is present, but can't
work. This is fixed by allowing the initialization routines to return an
error, which is checked, and the configuration aborted on failure.
eth_configure failed to check for many failures. Even when it did check,
it didn't undo whatever initializations has already happened, so a present,
but partially initialized and non-working device could result. It now
checks everything that can fail, and bails out, undoing whatever had been
done.
The return value of eth_configure was always ignored, so it is now just
void.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-07 01:51:04 +04:00
static int slip_user_init ( void * data , void * dev )
2005-04-17 02:20:36 +04:00
{
struct slip_data * pri = data ;
pri - > dev = dev ;
uml: network interface hotplug error handling
This fixes a number of problems associated with network interface hotplug.
The userspace initialization function can fail in some cases, but the
failure was never passed back to eth_configure, which proceeded with the
configuration. This results in a zombie device that is present, but can't
work. This is fixed by allowing the initialization routines to return an
error, which is checked, and the configuration aborted on failure.
eth_configure failed to check for many failures. Even when it did check,
it didn't undo whatever initializations has already happened, so a present,
but partially initialized and non-working device could result. It now
checks everything that can fail, and bails out, undoing whatever had been
done.
The return value of eth_configure was always ignored, so it is now just
void.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-07 01:51:04 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int set_up_tty ( int fd )
{
int i ;
struct termios tios ;
if ( tcgetattr ( fd , & tios ) < 0 ) {
2007-10-16 12:27:29 +04:00
printk ( UM_KERN_ERR " could not get initial terminal "
" attributes \n " ) ;
return - 1 ;
2005-04-17 02:20:36 +04:00
}
tios . c_cflag = CS8 | CREAD | HUPCL | CLOCAL ;
tios . c_iflag = IGNBRK | IGNPAR ;
tios . c_oflag = 0 ;
tios . c_lflag = 0 ;
for ( i = 0 ; i < NCCS ; i + + )
tios . c_cc [ i ] = 0 ;
tios . c_cc [ VMIN ] = 1 ;
tios . c_cc [ VTIME ] = 0 ;
cfsetospeed ( & tios , B38400 ) ;
cfsetispeed ( & tios , B38400 ) ;
if ( tcsetattr ( fd , TCSAFLUSH , & tios ) < 0 ) {
2007-10-16 12:27:29 +04:00
printk ( UM_KERN_ERR " failed to set terminal attributes \n " ) ;
return - 1 ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:27:29 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
struct slip_pre_exec_data {
int stdin ;
int stdout ;
int close_me ;
} ;
static void slip_pre_exec ( void * arg )
{
struct slip_pre_exec_data * data = arg ;
2007-10-16 12:27:29 +04:00
if ( data - > stdin > = 0 )
dup2 ( data - > stdin , 0 ) ;
2005-04-17 02:20:36 +04:00
dup2 ( data - > stdout , 1 ) ;
2007-10-16 12:27:29 +04:00
if ( data - > close_me > = 0 )
close ( data - > close_me ) ;
2005-04-17 02:20:36 +04:00
}
static int slip_tramp ( char * * argv , int fd )
{
struct slip_pre_exec_data pe_data ;
char * output ;
2007-12-18 03:19:46 +03:00
int pid , fds [ 2 ] , err , output_len ;
2005-04-17 02:20:36 +04:00
err = os_pipe ( fds , 1 , 0 ) ;
2007-10-16 12:27:29 +04:00
if ( err < 0 ) {
printk ( UM_KERN_ERR " slip_tramp : pipe failed, err = %d \n " ,
- err ) ;
2005-06-14 02:52:18 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
err = 0 ;
pe_data . stdin = fd ;
pe_data . stdout = fds [ 1 ] ;
pe_data . close_me = fds [ 0 ] ;
2007-07-16 10:38:56 +04:00
err = run_helper ( slip_pre_exec , & pe_data , argv ) ;
2007-10-16 12:27:29 +04:00
if ( err < 0 )
2005-06-14 02:52:18 +04:00
goto out_close ;
pid = err ;
2007-05-07 01:51:22 +04:00
output_len = UM_KERN_PAGE_SIZE ;
2008-05-13 01:01:52 +04:00
output = uml_kmalloc ( output_len , UM_GFP_KERNEL ) ;
2007-10-16 12:27:29 +04:00
if ( output = = NULL ) {
printk ( UM_KERN_ERR " slip_tramp : failed to allocate output "
" buffer \n " ) ;
2005-06-14 02:52:18 +04:00
os_kill_process ( pid , 1 ) ;
err = - ENOMEM ;
2011-07-26 04:12:51 +04:00
goto out_close ;
2005-06-14 02:52:18 +04:00
}
2005-04-17 02:20:36 +04:00
2007-10-16 12:27:29 +04:00
close ( fds [ 1 ] ) ;
2005-06-14 02:52:18 +04:00
read_output ( fds [ 0 ] , output , output_len ) ;
printk ( " %s " , output ) ;
2008-02-05 09:31:10 +03:00
err = helper_wait ( pid ) ;
2007-10-16 12:27:29 +04:00
close ( fds [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
2005-06-14 02:52:18 +04:00
kfree ( output ) ;
return err ;
out_close :
2007-10-16 12:27:29 +04:00
close ( fds [ 0 ] ) ;
close ( fds [ 1 ] ) ;
2005-06-14 02:52:18 +04:00
out :
return err ;
2005-04-17 02:20:36 +04:00
}
static int slip_open ( void * data )
{
struct slip_data * pri = data ;
char version_buf [ sizeof ( " nnnnn \0 " ) ] ;
char gate_buf [ sizeof ( " nnn.nnn.nnn.nnn \0 " ) ] ;
2007-10-16 12:27:29 +04:00
char * argv [ ] = { " uml_net " , version_buf , " slip " , " up " , gate_buf ,
2005-04-17 02:20:36 +04:00
NULL } ;
int sfd , mfd , err ;
2005-06-14 02:52:18 +04:00
err = get_pty ( ) ;
2007-10-16 12:27:29 +04:00
if ( err < 0 ) {
printk ( UM_KERN_ERR " slip-open : Failed to open pty, err = %d \n " ,
- err ) ;
2005-06-14 02:52:18 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
2005-06-14 02:52:18 +04:00
mfd = err ;
2007-10-16 12:27:29 +04:00
err = open ( ptsname ( mfd ) , O_RDWR , 0 ) ;
if ( err < 0 ) {
printk ( UM_KERN_ERR " Couldn't open tty for slip line, "
" err = %d \n " , - err ) ;
2005-06-14 02:52:18 +04:00
goto out_close ;
2005-04-17 02:20:36 +04:00
}
2005-06-14 02:52:18 +04:00
sfd = err ;
2007-10-16 12:27:29 +04:00
if ( set_up_tty ( sfd ) )
2005-06-14 02:52:18 +04:00
goto out_close2 ;
2005-04-17 02:20:36 +04:00
pri - > slave = sfd ;
2005-06-14 02:52:18 +04:00
pri - > slip . pos = 0 ;
pri - > slip . esc = 0 ;
2007-10-16 12:27:29 +04:00
if ( pri - > gate_addr ! = NULL ) {
2005-04-17 02:20:36 +04:00
sprintf ( version_buf , " %d " , UML_NET_VERSION ) ;
strcpy ( gate_buf , pri - > gate_addr ) ;
err = slip_tramp ( argv , sfd ) ;
2007-10-16 12:27:29 +04:00
if ( err < 0 ) {
printk ( UM_KERN_ERR " slip_tramp failed - err = %d \n " ,
- err ) ;
2005-06-14 02:52:18 +04:00
goto out_close2 ;
2005-04-17 02:20:36 +04:00
}
err = os_get_ifname ( pri - > slave , pri - > name ) ;
2007-10-16 12:27:29 +04:00
if ( err < 0 ) {
printk ( UM_KERN_ERR " get_ifname failed, err = %d \n " ,
- err ) ;
2005-06-14 02:52:18 +04:00
goto out_close2 ;
2005-04-17 02:20:36 +04:00
}
iter_addresses ( pri - > dev , open_addr , pri - > name ) ;
}
else {
err = os_set_slip ( sfd ) ;
2007-10-16 12:27:29 +04:00
if ( err < 0 ) {
printk ( UM_KERN_ERR " Failed to set slip discipline "
" encapsulation - err = %d \n " , - err ) ;
2005-06-14 02:52:18 +04:00
goto out_close2 ;
2005-04-17 02:20:36 +04:00
}
}
2007-10-16 12:27:29 +04:00
return mfd ;
2005-06-14 02:52:18 +04:00
out_close2 :
2007-10-16 12:27:29 +04:00
close ( sfd ) ;
2005-06-14 02:52:18 +04:00
out_close :
2007-10-16 12:27:29 +04:00
close ( mfd ) ;
2005-06-14 02:52:18 +04:00
out :
return err ;
2005-04-17 02:20:36 +04:00
}
static void slip_close ( int fd , void * data )
{
struct slip_data * pri = data ;
char version_buf [ sizeof ( " nnnnn \0 " ) ] ;
2007-10-16 12:27:29 +04:00
char * argv [ ] = { " uml_net " , version_buf , " slip " , " down " , pri - > name ,
2005-04-17 02:20:36 +04:00
NULL } ;
int err ;
2007-10-16 12:27:29 +04:00
if ( pri - > gate_addr ! = NULL )
2005-04-17 02:20:36 +04:00
iter_addresses ( pri - > dev , close_addr , pri - > name ) ;
sprintf ( version_buf , " %d " , UML_NET_VERSION ) ;
err = slip_tramp ( argv , pri - > slave ) ;
2007-10-16 12:27:29 +04:00
if ( err ! = 0 )
printk ( UM_KERN_ERR " slip_tramp failed - errno = %d \n " , - err ) ;
close ( fd ) ;
close ( pri - > slave ) ;
2005-04-17 02:20:36 +04:00
pri - > slave = - 1 ;
}
int slip_user_read ( int fd , void * buf , int len , struct slip_data * pri )
{
2005-06-14 02:52:18 +04:00
return slip_proto_read ( fd , buf , len , & pri - > slip ) ;
2005-04-17 02:20:36 +04:00
}
int slip_user_write ( int fd , void * buf , int len , struct slip_data * pri )
{
2005-06-14 02:52:18 +04:00
return slip_proto_write ( fd , buf , len , & pri - > slip ) ;
2005-04-17 02:20:36 +04:00
}
static void slip_add_addr ( unsigned char * addr , unsigned char * netmask ,
void * data )
{
struct slip_data * pri = data ;
2007-10-16 12:27:29 +04:00
if ( pri - > slave < 0 )
return ;
2005-04-17 02:20:36 +04:00
open_addr ( addr , netmask , pri - > name ) ;
}
static void slip_del_addr ( unsigned char * addr , unsigned char * netmask ,
void * data )
{
struct slip_data * pri = data ;
2007-10-16 12:27:29 +04:00
if ( pri - > slave < 0 )
return ;
2005-04-17 02:20:36 +04:00
close_addr ( addr , netmask , pri - > name ) ;
}
2006-09-27 12:50:33 +04:00
const struct net_user_info slip_user_info = {
2005-04-17 02:20:36 +04:00
. init = slip_user_init ,
. open = slip_open ,
. close = slip_close ,
. remove = NULL ,
. add_address = slip_add_addr ,
. delete_address = slip_del_addr ,
2007-10-16 12:27:31 +04:00
. mtu = BUF_SIZE ,
. max_packet = BUF_SIZE ,
2005-04-17 02:20:36 +04:00
} ;