2005-04-17 02:20:36 +04:00
/* net/atm/pvc.c - ATM PVC sockets */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
# include <linux/net.h> /* struct socket, struct proto_ops */
# include <linux/atm.h> /* ATM stuff */
# include <linux/atmdev.h> /* ATM devices */
# include <linux/errno.h> /* error codes */
# include <linux/kernel.h> /* printk */
# include <linux/init.h>
# include <linux/skbuff.h>
# include <linux/bitops.h>
# include <net/sock.h> /* for sock_no_* */
# include "resources.h" /* devs and vccs */
# include "common.h" /* common for PVCs and SVCs */
static int pvc_shutdown ( struct socket * sock , int how )
{
return 0 ;
}
static int pvc_bind ( struct socket * sock , struct sockaddr * sockaddr ,
int sockaddr_len )
{
struct sock * sk = sock - > sk ;
struct sockaddr_atmpvc * addr ;
struct atm_vcc * vcc ;
int error ;
if ( sockaddr_len ! = sizeof ( struct sockaddr_atmpvc ) ) return - EINVAL ;
addr = ( struct sockaddr_atmpvc * ) sockaddr ;
if ( addr - > sap_family ! = AF_ATMPVC ) return - EAFNOSUPPORT ;
lock_sock ( sk ) ;
vcc = ATM_SD ( sock ) ;
if ( ! test_bit ( ATM_VF_HASQOS , & vcc - > flags ) ) {
error = - EBADFD ;
goto out ;
}
if ( test_bit ( ATM_VF_PARTIAL , & vcc - > flags ) ) {
if ( vcc - > vpi ! = ATM_VPI_UNSPEC ) addr - > sap_addr . vpi = vcc - > vpi ;
if ( vcc - > vci ! = ATM_VCI_UNSPEC ) addr - > sap_addr . vci = vcc - > vci ;
}
error = vcc_connect ( sock , addr - > sap_addr . itf , addr - > sap_addr . vpi ,
addr - > sap_addr . vci ) ;
out :
release_sock ( sk ) ;
return error ;
}
static int pvc_connect ( struct socket * sock , struct sockaddr * sockaddr ,
int sockaddr_len , int flags )
{
return pvc_bind ( sock , sockaddr , sockaddr_len ) ;
}
static int pvc_setsockopt ( struct socket * sock , int level , int optname ,
2009-10-01 03:12:20 +04:00
char __user * optval , unsigned int optlen )
2005-04-17 02:20:36 +04:00
{
struct sock * sk = sock - > sk ;
int error ;
lock_sock ( sk ) ;
error = vcc_setsockopt ( sock , level , optname , optval , optlen ) ;
release_sock ( sk ) ;
return error ;
}
static int pvc_getsockopt ( struct socket * sock , int level , int optname ,
2007-02-09 17:24:29 +03:00
char __user * optval , int __user * optlen )
2005-04-17 02:20:36 +04:00
{
struct sock * sk = sock - > sk ;
int error ;
lock_sock ( sk ) ;
error = vcc_getsockopt ( sock , level , optname , optval , optlen ) ;
release_sock ( sk ) ;
return error ;
}
static int pvc_getname ( struct socket * sock , struct sockaddr * sockaddr ,
int * sockaddr_len , int peer )
{
struct sockaddr_atmpvc * addr ;
struct atm_vcc * vcc = ATM_SD ( sock ) ;
if ( ! vcc - > dev | | ! test_bit ( ATM_VF_ADDR , & vcc - > flags ) ) return - ENOTCONN ;
2007-02-09 17:24:29 +03:00
* sockaddr_len = sizeof ( struct sockaddr_atmpvc ) ;
2005-04-17 02:20:36 +04:00
addr = ( struct sockaddr_atmpvc * ) sockaddr ;
addr - > sap_family = AF_ATMPVC ;
addr - > sap_addr . itf = vcc - > dev - > number ;
addr - > sap_addr . vpi = vcc - > vpi ;
addr - > sap_addr . vci = vcc - > vci ;
return 0 ;
}
2005-12-22 23:49:22 +03:00
static const struct proto_ops pvc_proto_ops = {
2005-04-17 02:20:36 +04:00
. family = PF_ATMPVC ,
. owner = THIS_MODULE ,
. release = vcc_release ,
. bind = pvc_bind ,
. connect = pvc_connect ,
. socketpair = sock_no_socketpair ,
. accept = sock_no_accept ,
. getname = pvc_getname ,
. poll = vcc_poll ,
. ioctl = vcc_ioctl ,
atm: 32-bit ioctl compatibility
We lack compat ioctl support through most of the ATM code. This patch
deals with most of it, and I can now at least use BR2684 and PPPoATM
with 32-bit userspace.
I haven't added a .compat_ioctl method to struct atm_ioctl, because
AFAICT none of the current users need any conversion -- so we can just
call the ->ioctl() method in every case. I looked at br2684, clip, lec,
mpc, pppoatm and atmtcp.
In svc_compat_ioctl() the only mangling which is needed is to change
COMPAT_ATM_ADDPARTY to ATM_ADDPARTY. Although it's defined as
_IOW('a', ATMIOC_SPECIAL+4,struct atm_iobuf)
it doesn't actually _take_ a struct atm_iobuf as an argument -- it takes
a struct sockaddr_atmsvc, which _is_ the same between 32-bit and 64-bit
code, so doesn't need conversion.
Almost all of vcc_ioctl() would have been identical, so I converted that
into a core do_vcc_ioctl() function with an 'int compat' argument.
I've done the same with atm_dev_ioctl(), where there _are_ a few
differences, but still it's relatively contained and there would
otherwise have been a lot of duplication.
I haven't done any of the actual device-specific ioctls, although I've
added a compat_ioctl method to struct atmdev_ops.
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2008-12-04 09:12:38 +03:00
# ifdef CONFIG_COMPAT
. compat_ioctl = vcc_compat_ioctl ,
# endif
2005-04-17 02:20:36 +04:00
. listen = sock_no_listen ,
. shutdown = pvc_shutdown ,
. setsockopt = pvc_setsockopt ,
. getsockopt = pvc_getsockopt ,
. sendmsg = vcc_sendmsg ,
. recvmsg = vcc_recvmsg ,
. mmap = sock_no_mmap ,
. sendpage = sock_no_sendpage ,
} ;
2009-11-06 09:18:14 +03:00
static int pvc_create ( struct net * net , struct socket * sock , int protocol ,
int kern )
2005-04-17 02:20:36 +04:00
{
2007-10-09 10:24:22 +04:00
if ( net ! = & init_net )
return - EAFNOSUPPORT ;
2005-04-17 02:20:36 +04:00
sock - > ops = & pvc_proto_ops ;
2007-10-09 10:24:22 +04:00
return vcc_create ( net , sock , protocol , PF_ATMPVC ) ;
2005-04-17 02:20:36 +04:00
}
2009-10-05 09:58:39 +04:00
static const struct net_proto_family pvc_family_ops = {
2005-04-17 02:20:36 +04:00
. family = PF_ATMPVC ,
. create = pvc_create ,
. owner = THIS_MODULE ,
} ;
/*
* Initialize the ATM PVC protocol family
*/
int __init atmpvc_init ( void )
{
return sock_register ( & pvc_family_ops ) ;
}
void atmpvc_exit ( void )
{
sock_unregister ( PF_ATMPVC ) ;
}