2005-04-17 02:20:36 +04:00
/*
2007-10-16 12:27:29 +04:00
* Copyright ( C ) 2001 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
* Copyright ( C ) 2001 Lennert Buytenhek ( buytenh @ gnu . org ) and
2005-04-17 02:20:36 +04:00
* James Leu ( jleu @ mindspring . net ) .
* Copyright ( C ) 2001 by various other people who didn ' t put their name here .
* Licensed under the GPL .
*/
# include <stdint.h>
2007-10-16 12:27:29 +04:00
# include <unistd.h>
# include <errno.h>
# include <sys/types.h>
2005-04-17 02:20:36 +04:00
# include <sys/socket.h>
# include <sys/time.h>
2007-10-16 12:27:29 +04:00
# include <sys/un.h>
2005-04-17 02:20:36 +04:00
# include "daemon.h"
2012-10-08 06:27:32 +04:00
# include <net_user.h>
# include <os.h>
# include <um_malloc.h>
2005-04-17 02:20:36 +04:00
enum request_type { REQ_NEW_CONTROL } ;
# define SWITCH_MAGIC 0xfeedface
struct request_v3 {
uint32_t magic ;
uint32_t version ;
enum request_type type ;
struct sockaddr_un sock ;
} ;
static struct sockaddr_un * new_addr ( void * name , int len )
{
struct sockaddr_un * sun ;
2008-05-13 01:01:52 +04:00
sun = uml_kmalloc ( sizeof ( struct sockaddr_un ) , UM_GFP_KERNEL ) ;
2007-10-16 12:27:29 +04:00
if ( sun = = NULL ) {
printk ( UM_KERN_ERR " new_addr: allocation of sockaddr_un "
" failed \n " ) ;
2007-05-07 01:51:02 +04:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
sun - > sun_family = AF_UNIX ;
memcpy ( sun - > sun_path , name , len ) ;
2007-05-07 01:51:02 +04:00
return sun ;
2005-04-17 02:20:36 +04:00
}
static int connect_to_switch ( struct daemon_data * pri )
{
struct sockaddr_un * ctl_addr = pri - > ctl_addr ;
struct sockaddr_un * local_addr = pri - > local_addr ;
struct sockaddr_un * sun ;
struct request_v3 req ;
int fd , n , err ;
pri - > control = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
2007-10-16 12:27:29 +04:00
if ( pri - > control < 0 ) {
2007-03-08 07:41:14 +03:00
err = - errno ;
2007-10-16 12:27:29 +04:00
printk ( UM_KERN_ERR " daemon_open : control socket failed, "
" errno = %d \n " , - err ) ;
2007-03-08 07:41:14 +03:00
return err ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:27:29 +04:00
if ( connect ( pri - > control , ( struct sockaddr * ) ctl_addr ,
sizeof ( * ctl_addr ) ) < 0 ) {
2005-04-17 02:20:36 +04:00
err = - errno ;
2007-10-16 12:27:29 +04:00
printk ( UM_KERN_ERR " daemon_open : control connect failed, "
" errno = %d \n " , - err ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
fd = socket ( AF_UNIX , SOCK_DGRAM , 0 ) ;
2007-10-16 12:27:29 +04:00
if ( fd < 0 ) {
2005-04-17 02:20:36 +04:00
err = - errno ;
2007-10-16 12:27:29 +04:00
printk ( UM_KERN_ERR " daemon_open : data socket failed, "
" errno = %d \n " , - err ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
2007-10-16 12:27:29 +04:00
if ( bind ( fd , ( struct sockaddr * ) local_addr , sizeof ( * local_addr ) ) < 0 ) {
2005-04-17 02:20:36 +04:00
err = - errno ;
2007-10-16 12:27:29 +04:00
printk ( UM_KERN_ERR " daemon_open : data bind failed, "
" errno = %d \n " , - err ) ;
2005-04-17 02:20:36 +04:00
goto out_close ;
}
2008-05-13 01:01:52 +04:00
sun = uml_kmalloc ( sizeof ( struct sockaddr_un ) , UM_GFP_KERNEL ) ;
2007-10-16 12:27:29 +04:00
if ( sun = = NULL ) {
printk ( UM_KERN_ERR " new_addr: allocation of sockaddr_un "
" failed \n " ) ;
2005-04-17 02:20:36 +04:00
err = - ENOMEM ;
goto out_close ;
}
req . magic = SWITCH_MAGIC ;
req . version = SWITCH_VERSION ;
req . type = REQ_NEW_CONTROL ;
req . sock = * local_addr ;
2007-10-16 12:27:29 +04:00
n = write ( pri - > control , & req , sizeof ( req ) ) ;
if ( n ! = sizeof ( req ) ) {
printk ( UM_KERN_ERR " daemon_open : control setup request "
" failed, err = %d \n " , - errno ) ;
2005-04-17 02:20:36 +04:00
err = - ENOTCONN ;
2005-11-14 03:07:14 +03:00
goto out_free ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:27:29 +04:00
n = read ( pri - > control , sun , sizeof ( * sun ) ) ;
if ( n ! = sizeof ( * sun ) ) {
printk ( UM_KERN_ERR " daemon_open : read of data socket failed, "
" err = %d \n " , - errno ) ;
2005-04-17 02:20:36 +04:00
err = - ENOTCONN ;
2005-11-14 03:07:14 +03:00
goto out_free ;
2005-04-17 02:20:36 +04:00
}
pri - > data_addr = sun ;
2007-05-07 01:51:02 +04:00
return fd ;
2005-04-17 02:20:36 +04:00
2005-11-14 03:07:14 +03:00
out_free :
kfree ( sun ) ;
2005-04-17 02:20:36 +04:00
out_close :
2007-10-16 12:27:29 +04:00
close ( fd ) ;
2005-04-17 02:20:36 +04:00
out :
2007-10-16 12:27:29 +04:00
close ( pri - > control ) ;
2007-05-07 01:51:02 +04:00
return err ;
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 daemon_user_init ( void * data , void * dev )
2005-04-17 02:20:36 +04:00
{
struct daemon_data * pri = data ;
struct timeval tv ;
struct {
char zero ;
int pid ;
int usecs ;
} name ;
2007-10-16 12:27:29 +04:00
if ( ! strcmp ( pri - > sock_type , " unix " ) )
pri - > ctl_addr = new_addr ( pri - > ctl_sock ,
2005-04-17 02:20:36 +04:00
strlen ( pri - > ctl_sock ) + 1 ) ;
name . zero = 0 ;
name . pid = os_getpid ( ) ;
gettimeofday ( & tv , NULL ) ;
name . usecs = tv . tv_usec ;
pri - > local_addr = new_addr ( & name , sizeof ( name ) ) ;
pri - > dev = dev ;
pri - > fd = connect_to_switch ( pri ) ;
2007-10-16 12:27:29 +04:00
if ( pri - > fd < 0 ) {
2005-04-17 02:20:36 +04:00
kfree ( pri - > local_addr ) ;
pri - > local_addr = NULL ;
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 pri - > fd ;
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
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int daemon_open ( void * data )
{
struct daemon_data * pri = data ;
2007-05-07 01:51:02 +04:00
return pri - > fd ;
2005-04-17 02:20:36 +04:00
}
static void daemon_remove ( void * data )
{
struct daemon_data * pri = data ;
2007-10-16 12:27:29 +04:00
close ( pri - > fd ) ;
2006-01-19 04:42:53 +03:00
pri - > fd = - 1 ;
2007-10-16 12:27:29 +04:00
close ( pri - > control ) ;
2006-01-19 04:42:53 +03:00
pri - > control = - 1 ;
2005-06-26 01:55:20 +04:00
kfree ( pri - > data_addr ) ;
2006-01-19 04:42:53 +03:00
pri - > data_addr = NULL ;
2005-06-26 01:55:20 +04:00
kfree ( pri - > ctl_addr ) ;
2006-01-19 04:42:53 +03:00
pri - > ctl_addr = NULL ;
2005-06-26 01:55:20 +04:00
kfree ( pri - > local_addr ) ;
2006-01-19 04:42:53 +03:00
pri - > local_addr = NULL ;
2005-04-17 02:20:36 +04:00
}
int daemon_user_write ( int fd , void * buf , int len , struct daemon_data * pri )
{
struct sockaddr_un * data_addr = pri - > data_addr ;
2007-05-07 01:51:02 +04:00
return net_sendto ( fd , buf , len , data_addr , sizeof ( * data_addr ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-09-27 12:50:33 +04:00
const struct net_user_info daemon_user_info = {
2005-04-17 02:20:36 +04:00
. init = daemon_user_init ,
. open = daemon_open ,
. close = NULL ,
. remove = daemon_remove ,
. add_address = NULL ,
. delete_address = NULL ,
2007-10-16 12:27:31 +04:00
. mtu = ETH_MAX_PACKET ,
. max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER ,
2005-04-17 02:20:36 +04:00
} ;