2005-04-17 02:20:36 +04:00
/*****************************************************************************
* af_wanpipe . c WANPIPE ( tm ) Secure Socket Layer .
*
* Author : Nenad Corbic < ncorbic @ sangoma . com >
*
* Copyright : ( c ) 2000 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 .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Due Credit :
* Wanpipe socket layer is based on Packet and
* the X25 socket layers . The above sockets were
* used for the specific use of Sangoma Technoloiges
* API programs .
* Packet socket Authors : Ross Biro , Fred N . van Kempen and
* Alan Cox .
* X25 socket Author : Jonathan Naylor .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Mar 15 , 2002 Arnaldo C . Melo o Use wp_sk ( ) - > num , as it isnt anymore in sock
* Apr 25 , 2000 Nenad Corbic o Added the ability to send zero length packets .
* Mar 13 , 2000 Nenad Corbic o Added a tx buffer check via ioctl call .
* Mar 06 , 2000 Nenad Corbic o Fixed the corrupt sock lcn problem .
* Server and client applicaton can run
* simultaneously without conflicts .
* Feb 29 , 2000 Nenad Corbic o Added support for PVC protocols , such as
* CHDLC , Frame Relay and HDLC API .
* Jan 17 , 2000 Nenad Corbic o Initial version , based on AF_PACKET socket .
* X25API support only .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/types.h>
# include <linux/sched.h>
# include <linux/mm.h>
2006-01-11 23:17:47 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/fcntl.h>
# include <linux/socket.h>
# include <linux/in.h>
# include <linux/inet.h>
# include <linux/netdevice.h>
# include <linux/poll.h>
# include <linux/wireless.h>
# include <linux/kmod.h>
# include <net/ip.h>
# include <net/protocol.h>
# include <linux/skbuff.h>
# include <net/sock.h>
# include <linux/errno.h>
# include <linux/timer.h>
# include <asm/system.h>
# include <asm/uaccess.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/if_wanpipe.h>
# include <linux/pkt_sched.h>
2005-08-10 07:08:28 +04:00
# include <linux/tcp_states.h>
2005-04-17 02:20:36 +04:00
# include <linux/if_wanpipe_common.h>
# ifdef CONFIG_INET
# include <net/inet_common.h>
# endif
# define SLOW_BACKOFF 0.1*HZ
# define FAST_BACKOFF 0.01*HZ
//#define PRINT_DEBUG
# ifdef PRINT_DEBUG
# define DBG_PRINTK(format, a...) printk(format, ## a)
# else
# define DBG_PRINTK(format, a...)
# endif
/* SECURE SOCKET IMPLEMENTATION
*
* TRANSMIT :
*
* When the user sends a packet via send ( ) system call
* the wanpipe_sendmsg ( ) function is executed .
*
* Each packet is enqueud into sk - > sk_write_queue transmit
* queue . When the packet is enqueued , a delayed transmit
* timer is triggerd which acts as a Bottom Half hander .
*
* wanpipe_delay_transmit ( ) function ( BH ) , dequeues packets
* from the sk - > sk_write_queue transmit queue and sends it
* to the deriver via dev - > hard_start_xmit ( skb , dev ) function .
* Note , this function is actual a function pointer of if_send ( )
* routine in the wanpipe driver .
*
* X25API GUARANTEED DELIVERY :
*
* In order to provide 100 % guaranteed packet delivery ,
* an atomic ' packet_sent ' counter is implemented . Counter
* is incremented for each packet enqueued
* into sk - > sk_write_queue . Counter is decremented each
* time wanpipe_delayed_transmit ( ) function successfuly
* passes the packet to the driver . Before each send ( ) , a poll
* routine checks the sock resources The maximum value of
* packet sent counter is 1 , thus if one packet is queued , the
* application will block until that packet is passed to the
* driver .
*
* RECEIVE :
*
* Wanpipe device drivers call the socket bottom half
* function , wanpipe_rcv ( ) to queue the incoming packets
* into an AF_WANPIPE socket queue . Based on wanpipe_rcv ( )
* return code , the driver knows whether the packet was
* successfully queued . If the socket queue is full ,
* protocol flow control is used by the driver , if any ,
* to slow down the traffic until the sock queue is free .
*
* Every time a packet arrives into a socket queue the
* socket wakes up processes which are waiting to receive
* data .
*
* If the socket queue is full , the driver sets a block
* bit which signals the socket to kick the wanpipe driver
* bottom half hander when the socket queue is partialy
* empty . wanpipe_recvmsg ( ) function performs this action .
*
* In case of x25api , packets will never be dropped , since
* flow control is available .
*
* In case of streaming protocols like CHDLC , packets will
* be dropped but the statistics will be generated .
*/
/* The code below is used to test memory leaks. It prints out
* a message every time kmalloc and kfree system calls get executed .
* If the calls match there is no leak : )
*/
/***********FOR DEBUGGING PURPOSES*********************************************
# define KMEM_SAFETYZONE 8
static void * dbg_kmalloc ( unsigned int size , int prio , int line ) {
void * v = kmalloc ( size , prio ) ;
printk ( KERN_INFO " line %d kmalloc(%d,%d) = %p \n " , line , size , prio , v ) ;
return v ;
}
static void dbg_kfree ( void * v , int line ) {
printk ( KERN_INFO " line %d kfree(%p) \n " , line , v ) ;
kfree ( v ) ;
}
# define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)
# define kfree(x) dbg_kfree(x,__LINE__)
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* List of all wanpipe sockets. */
HLIST_HEAD ( wanpipe_sklist ) ;
static DEFINE_RWLOCK ( wanpipe_sklist_lock ) ;
atomic_t wanpipe_socks_nr ;
static unsigned long wanpipe_tx_critical ;
#if 0
/* Private wanpipe socket structures. */
struct wanpipe_opt
{
void * mbox ; /* Mail box */
void * card ; /* Card bouded to */
struct net_device * dev ; /* Bounded device */
unsigned short lcn ; /* Binded LCN */
unsigned char svc ; /* 0=pvc, 1=svc */
unsigned char timer ; /* flag for delayed transmit*/
struct timer_list tx_timer ;
unsigned poll_cnt ;
unsigned char force ; /* Used to force sock release */
atomic_t packet_sent ;
} ;
# endif
static int sk_count ;
2005-12-22 23:49:22 +03:00
extern const struct proto_ops wanpipe_ops ;
2005-04-17 02:20:36 +04:00
static unsigned long find_free_critical ;
static void wanpipe_unlink_driver ( struct sock * sk ) ;
static void wanpipe_link_driver ( struct net_device * dev , struct sock * sk ) ;
static void wanpipe_wakeup_driver ( struct sock * sk ) ;
static int execute_command ( struct sock * , unsigned char , unsigned int ) ;
static int check_dev ( struct net_device * dev , sdla_t * card ) ;
struct net_device * wanpipe_find_free_dev ( sdla_t * card ) ;
static void wanpipe_unlink_card ( struct sock * ) ;
static int wanpipe_link_card ( struct sock * ) ;
static struct sock * wanpipe_make_new ( struct sock * ) ;
static struct sock * wanpipe_alloc_socket ( void ) ;
static inline int get_atomic_device ( struct net_device * dev ) ;
static int wanpipe_exec_cmd ( struct sock * , int , unsigned int ) ;
static int get_ioctl_cmd ( struct sock * , void * ) ;
static int set_ioctl_cmd ( struct sock * , void * ) ;
static void release_device ( struct net_device * dev ) ;
static void wanpipe_kill_sock_timer ( unsigned long data ) ;
static void wanpipe_kill_sock_irq ( struct sock * ) ;
static void wanpipe_kill_sock_accept ( struct sock * ) ;
static int wanpipe_do_bind ( struct sock * sk , struct net_device * dev ,
int protocol ) ;
struct sock * get_newsk_from_skb ( struct sk_buff * ) ;
static int wanpipe_debug ( struct sock * , void * ) ;
static void wanpipe_delayed_transmit ( unsigned long data ) ;
static void release_driver ( struct sock * ) ;
static void start_cleanup_timer ( struct sock * ) ;
static void check_write_queue ( struct sock * ) ;
static int check_driver_busy ( struct sock * ) ;
/*============================================================
* wanpipe_rcv
*
* Wanpipe socket bottom half handler . This function
* is called by the WANPIPE device drivers to queue a
* incoming packet into the socket receive queue .
* Once the packet is queued , all processes waiting to
* read are woken up .
*
* During socket bind , this function is bounded into
* WANPIPE driver private .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_rcv ( struct sk_buff * skb , struct net_device * dev ,
struct sock * sk )
{
struct wan_sockaddr_ll * sll = ( struct wan_sockaddr_ll * ) skb - > cb ;
wanpipe_common_t * chan = dev - > priv ;
/*
* When we registered the protocol we saved the socket in the data
* field for just this event .
*/
skb - > dev = dev ;
sll - > sll_family = AF_WANPIPE ;
sll - > sll_hatype = dev - > type ;
sll - > sll_protocol = skb - > protocol ;
sll - > sll_pkttype = skb - > pkt_type ;
sll - > sll_ifindex = dev - > ifindex ;
sll - > sll_halen = 0 ;
if ( dev - > hard_header_parse )
sll - > sll_halen = dev - > hard_header_parse ( skb , sll - > sll_addr ) ;
/*
* WAN_PACKET_DATA : Data which should be passed up the receive queue .
* WAN_PACKET_ASYC : Asynchronous data like place call , which should
* be passed up the listening sock .
* WAN_PACKET_ERR : Asynchronous data like clear call or restart
* which should go into an error queue .
*/
switch ( skb - > pkt_type ) {
case WAN_PACKET_DATA :
if ( sock_queue_rcv_skb ( sk , skb ) < 0 ) {
return - ENOMEM ;
}
break ;
case WAN_PACKET_CMD :
sk - > sk_state = chan - > state ;
/* Bug fix: update Mar6.
* Do not set the sock lcn number here , since
* cmd is not guaranteed to be executed on the
* board , thus Lcn could be wrong */
sk - > sk_data_ready ( sk , skb - > len ) ;
kfree_skb ( skb ) ;
break ;
case WAN_PACKET_ERR :
sk - > sk_state = chan - > state ;
if ( sock_queue_err_skb ( sk , skb ) < 0 ) {
return - ENOMEM ;
}
break ;
default :
printk ( KERN_INFO " wansock: BH Illegal Packet Type Dropping \n " ) ;
kfree_skb ( skb ) ;
break ;
}
//??????????????????????
// if (sk->sk_state == WANSOCK_DISCONNECTED){
// if (sk->sk_zapped) {
// //printk(KERN_INFO "wansock: Disconnected, killing early\n");
// wanpipe_unlink_driver(sk);
// sk->sk_bound_dev_if = 0;
// }
// }
return 0 ;
}
/*============================================================
* wanpipe_listen_rcv
*
* Wanpipe LISTEN socket bottom half handler . This function
* is called by the WANPIPE device drivers to queue an
* incoming call into the socket listening queue .
* Once the packet is queued , the waiting accept ( ) process
* is woken up .
*
* During socket bind , this function is bounded into
* WANPIPE driver private .
*
* IMPORTANT NOTE :
* The accept call ( ) is waiting for an skb packet
* which contains a pointer to a device structure .
*
* When we do a bind to a device structre , we
* bind a newly created socket into " chan->sk " . Thus ,
* when accept receives the skb packet , it will know
* from which dev it came form , and in turn it will know
* the address of the new sock .
*
* NOTE : This function gets called from driver ISR .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_listen_rcv ( struct sk_buff * skb , struct sock * sk )
{
wanpipe_opt * wp = wp_sk ( sk ) , * newwp ;
struct wan_sockaddr_ll * sll = ( struct wan_sockaddr_ll * ) skb - > cb ;
struct sock * newsk ;
struct net_device * dev ;
sdla_t * card ;
mbox_cmd_t * mbox_ptr ;
wanpipe_common_t * chan ;
/* Find a free device, if none found, all svc's are busy
*/
card = ( sdla_t * ) wp - > card ;
if ( ! card ) {
printk ( KERN_INFO " wansock: LISTEN ERROR, No Card \n " ) ;
return - ENODEV ;
}
dev = wanpipe_find_free_dev ( card ) ;
if ( ! dev ) {
printk ( KERN_INFO " wansock: LISTEN ERROR, No Free Device \n " ) ;
return - ENODEV ;
}
chan = dev - > priv ;
chan - > state = WANSOCK_CONNECTING ;
/* Allocate a new sock, which accept will bind
* and pass up to the user
*/
if ( ( newsk = wanpipe_make_new ( sk ) ) = = NULL ) {
release_device ( dev ) ;
return - ENOMEM ;
}
/* Initialize the new sock structure
*/
newsk - > sk_bound_dev_if = dev - > ifindex ;
newwp = wp_sk ( newsk ) ;
newwp - > card = wp - > card ;
/* Insert the sock into the main wanpipe
* sock list .
*/
atomic_inc ( & wanpipe_socks_nr ) ;
/* Allocate and fill in the new Mail Box. Then
* bind the mail box to the sock . It will be
* used by the ioctl call to read call information
* and to execute commands .
*/
2006-07-22 01:51:30 +04:00
if ( ( mbox_ptr = kzalloc ( sizeof ( mbox_cmd_t ) , GFP_ATOMIC ) ) = = NULL ) {
2005-04-17 02:20:36 +04:00
wanpipe_kill_sock_irq ( newsk ) ;
release_device ( dev ) ;
return - ENOMEM ;
}
memcpy ( mbox_ptr , skb - > data , skb - > len ) ;
/* Register the lcn on which incoming call came
* from . Thus , if we have to clear it , we know
* which lcn to clear
*/
newwp - > lcn = mbox_ptr - > cmd . lcn ;
newwp - > mbox = ( void * ) mbox_ptr ;
DBG_PRINTK ( KERN_INFO " NEWSOCK : Device %s, bind to lcn %i \n " ,
dev - > name , mbox_ptr - > cmd . lcn ) ;
chan - > lcn = mbox_ptr - > cmd . lcn ;
card - > u . x . svc_to_dev_map [ ( chan - > lcn % MAX_X25_LCN ) ] = dev ;
sock_reset_flag ( newsk , SOCK_ZAPPED ) ;
newwp - > num = htons ( X25_PROT ) ;
if ( wanpipe_do_bind ( newsk , dev , newwp - > num ) ) {
wanpipe_kill_sock_irq ( newsk ) ;
release_device ( dev ) ;
return - EINVAL ;
}
newsk - > sk_state = WANSOCK_CONNECTING ;
/* Fill in the standard sock address info */
sll - > sll_family = AF_WANPIPE ;
sll - > sll_hatype = dev - > type ;
sll - > sll_protocol = skb - > protocol ;
sll - > sll_pkttype = skb - > pkt_type ;
sll - > sll_ifindex = dev - > ifindex ;
sll - > sll_halen = 0 ;
skb - > dev = dev ;
sk - > sk_ack_backlog + + ;
/* We must do this manually, since the sock_queue_rcv_skb()
* function sets the skb - > dev to NULL . However , we use
* the dev field in the accept function . */
if ( atomic_read ( & sk - > sk_rmem_alloc ) + skb - > truesize > =
( unsigned ) sk - > sk_rcvbuf ) {
wanpipe_unlink_driver ( newsk ) ;
wanpipe_kill_sock_irq ( newsk ) ;
- - sk - > sk_ack_backlog ;
return - ENOMEM ;
}
skb_set_owner_r ( skb , sk ) ;
skb_queue_tail ( & sk - > sk_receive_queue , skb ) ;
sk - > sk_data_ready ( sk , skb - > len ) ;
return 0 ;
}
/*============================================================
* wanpipe_make_new
*
* Create a new sock , and allocate a wanpipe private
* structure to it . Also , copy the important data
* from the original sock to the new sock .
*
* This function is used by wanpipe_listen_rcv ( ) listen
* bottom half handler . A copy of the listening sock
* is created using this function .
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static struct sock * wanpipe_make_new ( struct sock * osk )
{
struct sock * sk ;
if ( osk - > sk_type ! = SOCK_RAW )
return NULL ;
if ( ( sk = wanpipe_alloc_socket ( ) ) = = NULL )
return NULL ;
sk - > sk_type = osk - > sk_type ;
sk - > sk_socket = osk - > sk_socket ;
sk - > sk_priority = osk - > sk_priority ;
sk - > sk_protocol = osk - > sk_protocol ;
wp_sk ( sk ) - > num = wp_sk ( osk ) - > num ;
sk - > sk_rcvbuf = osk - > sk_rcvbuf ;
sk - > sk_sndbuf = osk - > sk_sndbuf ;
sk - > sk_state = WANSOCK_CONNECTING ;
sk - > sk_sleep = osk - > sk_sleep ;
if ( sock_flag ( osk , SOCK_DBG ) )
sock_set_flag ( sk , SOCK_DBG ) ;
return sk ;
}
/*
* FIXME : wanpipe_opt has to include a sock in its definition and stop using
* sk_protinfo , but this code is not even compilable now , so lets leave it for
* later .
*/
static struct proto wanpipe_proto = {
. name = " WANPIPE " ,
. owner = THIS_MODULE ,
. obj_size = sizeof ( struct sock ) ,
} ;
/*============================================================
* wanpipe_make_new
*
* Allocate memory for the a new sock , and sock
* private data .
*
* Increment the module use count .
*
* This function is used by wanpipe_create ( ) and
* wanpipe_make_new ( ) functions .
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static struct sock * wanpipe_alloc_socket ( void )
{
struct sock * sk ;
struct wanpipe_opt * wan_opt ;
if ( ( sk = sk_alloc ( PF_WANPIPE , GFP_ATOMIC , & wanpipe_proto , 1 ) ) = = NULL )
return NULL ;
2006-07-22 01:51:30 +04:00
if ( ( wan_opt = kzalloc ( sizeof ( struct wanpipe_opt ) , GFP_ATOMIC ) ) = = NULL ) {
2005-04-17 02:20:36 +04:00
sk_free ( sk ) ;
return NULL ;
}
wp_sk ( sk ) = wan_opt ;
/* Use timer to send data to the driver. This will act
* as a BH handler for sendmsg functions */
init_timer ( & wan_opt - > tx_timer ) ;
wan_opt - > tx_timer . data = ( unsigned long ) sk ;
wan_opt - > tx_timer . function = wanpipe_delayed_transmit ;
sock_init_data ( NULL , sk ) ;
return sk ;
}
/*============================================================
* wanpipe_sendmsg
*
* This function implements a sendto ( ) system call ,
* for AF_WANPIPE socket family .
* During socket bind ( ) sk - > sk_bound_dev_if is initialized
* to a correct network device . This number is used
* to find a network device to which the packet should
* be passed to .
*
* Each packet is queued into sk - > sk_write_queue and
* delayed transmit bottom half handler is marked for
* execution .
*
* A socket must be in WANSOCK_CONNECTED state before
* a packet is queued into sk - > sk_write_queue .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_sendmsg ( struct kiocb * iocb , struct socket * sock ,
struct msghdr * msg , int len )
{
wanpipe_opt * wp ;
struct sock * sk = sock - > sk ;
struct wan_sockaddr_ll * saddr = ( struct wan_sockaddr_ll * ) msg - > msg_name ;
struct sk_buff * skb ;
struct net_device * dev ;
unsigned short proto ;
unsigned char * addr ;
int ifindex , err , reserve = 0 ;
if ( ! sock_flag ( sk , SOCK_ZAPPED ) )
return - ENETDOWN ;
if ( sk - > sk_state ! = WANSOCK_CONNECTED )
return - ENOTCONN ;
if ( msg - > msg_flags & ~ ( MSG_DONTWAIT | MSG_CMSG_COMPAT ) )
return ( - EINVAL ) ;
/* it was <=, now one can send
* zero length packets */
if ( len < sizeof ( x25api_hdr_t ) )
return - EINVAL ;
wp = wp_sk ( sk ) ;
if ( saddr = = NULL ) {
ifindex = sk - > sk_bound_dev_if ;
proto = wp - > num ;
addr = NULL ;
} else {
if ( msg - > msg_namelen < sizeof ( struct wan_sockaddr_ll ) ) {
return - EINVAL ;
}
ifindex = sk - > sk_bound_dev_if ;
proto = saddr - > sll_protocol ;
addr = saddr - > sll_addr ;
}
dev = dev_get_by_index ( ifindex ) ;
if ( dev = = NULL ) {
printk ( KERN_INFO " wansock: Send failed, dev index: %i \n " , ifindex ) ;
return - ENXIO ;
}
dev_put ( dev ) ;
if ( sock - > type = = SOCK_RAW )
reserve = dev - > hard_header_len ;
if ( len > dev - > mtu + reserve ) {
return - EMSGSIZE ;
}
skb = sock_alloc_send_skb ( sk , len + LL_RESERVED_SPACE ( dev ) ,
msg - > msg_flags & MSG_DONTWAIT , & err ) ;
if ( skb = = NULL ) {
goto out_unlock ;
}
skb_reserve ( skb , LL_RESERVED_SPACE ( dev ) ) ;
skb - > nh . raw = skb - > data ;
/* Returns -EFAULT on error */
err = memcpy_fromiovec ( skb_put ( skb , len ) , msg - > msg_iov , len ) ;
if ( err ) {
goto out_free ;
}
if ( dev - > hard_header ) {
int res ;
err = - EINVAL ;
res = dev - > hard_header ( skb , dev , ntohs ( proto ) , addr , NULL , len ) ;
if ( res < 0 ) {
goto out_free ;
}
}
skb - > protocol = proto ;
skb - > dev = dev ;
skb - > priority = sk - > sk_priority ;
skb - > pkt_type = WAN_PACKET_DATA ;
err = - ENETDOWN ;
if ( ! ( dev - > flags & IFF_UP ) )
goto out_free ;
if ( atomic_read ( & sk - > sk_wmem_alloc ) + skb - > truesize >
( unsigned int ) sk - > sk_sndbuf ) {
kfree_skb ( skb ) ;
return - ENOBUFS ;
}
skb_queue_tail ( & sk - > sk_write_queue , skb ) ;
atomic_inc ( & wp - > packet_sent ) ;
if ( ! ( test_and_set_bit ( 0 , & wp - > timer ) ) )
mod_timer ( & wp - > tx_timer , jiffies + 1 ) ;
return ( len ) ;
out_free :
kfree_skb ( skb ) ;
out_unlock :
return err ;
}
/*============================================================
* wanpipe_delayed_tarnsmit
*
* Transmit bottom half handler . It dequeues packets
* from sk - > sk_write_queue and passes them to the
* driver . If the driver is busy , the packet is
* re - enqueued .
*
* Packet Sent counter is decremented on successful
* transmission .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void wanpipe_delayed_transmit ( unsigned long data )
{
struct sock * sk = ( struct sock * ) data ;
struct sk_buff * skb ;
wanpipe_opt * wp = wp_sk ( sk ) ;
struct net_device * dev = wp - > dev ;
sdla_t * card = ( sdla_t * ) wp - > card ;
if ( ! card | | ! dev ) {
clear_bit ( 0 , & wp - > timer ) ;
DBG_PRINTK ( KERN_INFO " wansock: Transmit delay, no dev or card \n " ) ;
return ;
}
if ( sk - > sk_state ! = WANSOCK_CONNECTED | | ! sock_flag ( sk , SOCK_ZAPPED ) ) {
clear_bit ( 0 , & wp - > timer ) ;
DBG_PRINTK ( KERN_INFO " wansock: Tx Timer, State not CONNECTED \n " ) ;
return ;
}
/* If driver is executing command, we must offload
* the board by not sending data . Otherwise a
* pending command will never get a free buffer
* to execute */
if ( atomic_read ( & card - > u . x . command_busy ) ) {
wp - > tx_timer . expires = jiffies + SLOW_BACKOFF ;
add_timer ( & wp - > tx_timer ) ;
DBG_PRINTK ( KERN_INFO " wansock: Tx Timer, command bys BACKOFF \n " ) ;
return ;
}
if ( test_and_set_bit ( 0 , & wanpipe_tx_critical ) ) {
printk ( KERN_INFO " WanSock: Tx timer critical %s \n " , dev - > name ) ;
wp - > tx_timer . expires = jiffies + SLOW_BACKOFF ;
add_timer ( & wp - > tx_timer ) ;
return ;
}
/* Check for a packet in the fifo and send */
if ( ( skb = skb_dequeue ( & sk - > sk_write_queue ) ) ! = NULL ) {
if ( dev - > hard_start_xmit ( skb , dev ) ! = 0 ) {
/* Driver failed to transmit, re-enqueue
* the packet and retry again later */
skb_queue_head ( & sk - > sk_write_queue , skb ) ;
clear_bit ( 0 , & wanpipe_tx_critical ) ;
return ;
} else {
/* Packet Sent successful. Check for more packets
* if more packets , re - trigger the transmit routine
* other wise exit
*/
atomic_dec ( & wp - > packet_sent ) ;
if ( skb_peek ( & sk - > sk_write_queue ) = = NULL ) {
/* If there is nothing to send, kick
* the poll routine , which will trigger
* the application to send more data */
sk - > sk_data_ready ( sk , 0 ) ;
clear_bit ( 0 , & wp - > timer ) ;
} else {
/* Reschedule as fast as possible */
wp - > tx_timer . expires = jiffies + 1 ;
add_timer ( & wp - > tx_timer ) ;
}
}
}
clear_bit ( 0 , & wanpipe_tx_critical ) ;
}
/*============================================================
* execute_command
*
* Execute x25api commands . The atomic variable
* chan - > command is used to indicate to the driver that
* command is pending for execution . The acutal command
* structure is placed into a sock mbox structure
* ( wp_sk ( sk ) - > mbox ) .
*
* The sock private structure , mbox is
* used as shared memory between sock and the driver .
* Driver uses the sock mbox to execute the command
* and return the result .
*
* For all command except PLACE CALL , the function
* waits for the result . PLACE CALL can be ether
* blocking or nonblocking . The user sets this option
* via ioctl call .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int execute_command ( struct sock * sk , unsigned char cmd , unsigned int flags )
{
wanpipe_opt * wp = wp_sk ( sk ) ;
struct net_device * dev ;
wanpipe_common_t * chan = NULL ;
int err = 0 ;
DECLARE_WAITQUEUE ( wait , current ) ;
dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ;
if ( dev = = NULL ) {
printk ( KERN_INFO " wansock: Exec failed no dev %i \n " ,
sk - > sk_bound_dev_if ) ;
return - ENODEV ;
}
dev_put ( dev ) ;
if ( ( chan = dev - > priv ) = = NULL ) {
printk ( KERN_INFO " wansock: Exec cmd failed no priv area \n " ) ;
return - ENODEV ;
}
if ( atomic_read ( & chan - > command ) ) {
printk ( KERN_INFO " wansock: ERROR: Command already running %x, %s \n " ,
atomic_read ( & chan - > command ) , dev - > name ) ;
return - EINVAL ;
}
if ( ! wp - > mbox ) {
printk ( KERN_INFO " wansock: In execute without MBOX \n " ) ;
return - EINVAL ;
}
( ( mbox_cmd_t * ) wp - > mbox ) - > cmd . command = cmd ;
( ( mbox_cmd_t * ) wp - > mbox ) - > cmd . lcn = wp - > lcn ;
( ( mbox_cmd_t * ) wp - > mbox ) - > cmd . result = 0x7F ;
if ( flags & O_NONBLOCK ) {
cmd | = 0x80 ;
atomic_set ( & chan - > command , cmd ) ;
} else {
atomic_set ( & chan - > command , cmd ) ;
}
add_wait_queue ( sk - > sk_sleep , & wait ) ;
current - > state = TASK_INTERRUPTIBLE ;
for ( ; ; ) {
if ( ( ( mbox_cmd_t * ) wp - > mbox ) - > cmd . result ! = 0x7F ) {
err = 0 ;
break ;
}
if ( signal_pending ( current ) ) {
err = - ERESTARTSYS ;
break ;
}
schedule ( ) ;
}
current - > state = TASK_RUNNING ;
remove_wait_queue ( sk - > sk_sleep , & wait ) ;
return err ;
}
/*============================================================
* wanpipe_destroy_timer
*
* Used by wanpipe_release , to delay release of
* the socket .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void wanpipe_destroy_timer ( unsigned long data )
{
struct sock * sk = ( struct sock * ) data ;
wanpipe_opt * wp = wp_sk ( sk ) ;
if ( ( ! atomic_read ( & sk - > sk_wmem_alloc ) & &
! atomic_read ( & sk - > sk_rmem_alloc ) ) | |
( + + wp - > force = = 5 ) ) {
if ( atomic_read ( & sk - > sk_wmem_alloc ) | |
atomic_read ( & sk - > sk_rmem_alloc ) )
printk ( KERN_INFO " wansock: Warning, Packet Discarded due to sock shutdown! \n " ) ;
kfree ( wp ) ;
wp_sk ( sk ) = NULL ;
if ( atomic_read ( & sk - > sk_refcnt ) ! = 1 ) {
atomic_set ( & sk - > sk_refcnt , 1 ) ;
DBG_PRINTK ( KERN_INFO " wansock: Error, wrong reference count: %i ! :delay. \n " ,
atomic_read ( & sk - > sk_refcnt ) ) ;
}
sock_put ( sk ) ;
atomic_dec ( & wanpipe_socks_nr ) ;
return ;
}
sk - > sk_timer . expires = jiffies + 5 * HZ ;
add_timer ( & sk - > sk_timer ) ;
printk ( KERN_INFO " wansock: packet sk destroy delayed \n " ) ;
}
/*============================================================
* wanpipe_unlink_driver
*
* When the socket is released , this function is
* used to remove links that bind the sock and the
* driver together .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void wanpipe_unlink_driver ( struct sock * sk )
{
struct net_device * dev ;
wanpipe_common_t * chan = NULL ;
sock_reset_flag ( sk , SOCK_ZAPPED ) ;
sk - > sk_state = WANSOCK_DISCONNECTED ;
wp_sk ( sk ) - > dev = NULL ;
dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ;
if ( ! dev ) {
printk ( KERN_INFO " wansock: No dev on release \n " ) ;
return ;
}
dev_put ( dev ) ;
if ( ( chan = dev - > priv ) = = NULL ) {
printk ( KERN_INFO " wansock: No Priv Area on release \n " ) ;
return ;
}
set_bit ( 0 , & chan - > common_critical ) ;
chan - > sk = NULL ;
chan - > func = NULL ;
chan - > mbox = NULL ;
chan - > tx_timer = NULL ;
clear_bit ( 0 , & chan - > common_critical ) ;
release_device ( dev ) ;
return ;
}
/*============================================================
* wanpipe_link_driver
*
* Upon successful bind ( ) , sock is linked to a driver
* by binding in the wanpipe_rcv ( ) bottom half handler
* to the driver function pointer , as well as sock and
* sock mailbox addresses . This way driver can pass
* data up the socket .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void wanpipe_link_driver ( struct net_device * dev , struct sock * sk )
{
wanpipe_opt * wp = wp_sk ( sk ) ;
wanpipe_common_t * chan = dev - > priv ;
if ( ! chan )
return ;
set_bit ( 0 , & chan - > common_critical ) ;
chan - > sk = sk ;
chan - > func = wanpipe_rcv ;
chan - > mbox = wp - > mbox ;
chan - > tx_timer = & wp - > tx_timer ;
wp - > dev = dev ;
sock_set_flag ( sk , SOCK_ZAPPED ) ;
clear_bit ( 0 , & chan - > common_critical ) ;
}
/*============================================================
* release_device
*
* During sock release , clear a critical bit , which
* marks the device a being taken .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void release_device ( struct net_device * dev )
{
wanpipe_common_t * chan = dev - > priv ;
clear_bit ( 0 , ( void * ) & chan - > rw_bind ) ;
}
/*============================================================
* wanpipe_release
*
* Close a PACKET socket . This is fairly simple . We
* immediately go to ' closed ' state and remove our
* protocol entry in the device list .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_release ( struct socket * sock )
{
wanpipe_opt * wp ;
struct sock * sk = sock - > sk ;
if ( ! sk )
return 0 ;
wp = wp_sk ( sk ) ;
check_write_queue ( sk ) ;
/* Kill the tx timer, if we don't kill it now, the timer
* will run after we kill the sock . Timer code will
* try to access the sock which has been killed and cause
* kernel panic */
del_timer ( & wp - > tx_timer ) ;
/*
* Unhook packet receive handler .
*/
if ( wp - > num = = htons ( X25_PROT ) & &
sk - > sk_state ! = WANSOCK_DISCONNECTED & & sock_flag ( sk , SOCK_ZAPPED ) ) {
struct net_device * dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ;
wanpipe_common_t * chan ;
if ( dev ) {
chan = dev - > priv ;
atomic_set ( & chan - > disconnect , 1 ) ;
DBG_PRINTK ( KERN_INFO " wansock: Sending Clear Indication %i \n " ,
sk - > sk_state ) ;
dev_put ( dev ) ;
}
}
set_bit ( 1 , & wanpipe_tx_critical ) ;
write_lock ( & wanpipe_sklist_lock ) ;
sk_del_node_init ( sk ) ;
write_unlock ( & wanpipe_sklist_lock ) ;
clear_bit ( 1 , & wanpipe_tx_critical ) ;
release_driver ( sk ) ;
/*
* Now the socket is dead . No more input will appear .
*/
sk - > sk_state_change ( sk ) ; /* It is useless. Just for sanity. */
sock - > sk = NULL ;
sk - > sk_socket = NULL ;
sock_set_flag ( sk , SOCK_DEAD ) ;
/* Purge queues */
skb_queue_purge ( & sk - > sk_receive_queue ) ;
skb_queue_purge ( & sk - > sk_write_queue ) ;
skb_queue_purge ( & sk - > sk_error_queue ) ;
if ( atomic_read ( & sk - > sk_rmem_alloc ) | |
atomic_read ( & sk - > sk_wmem_alloc ) ) {
del_timer ( & sk - > sk_timer ) ;
printk ( KERN_INFO " wansock: Killing in Timer R %i , W %i \n " ,
atomic_read ( & sk - > sk_rmem_alloc ) ,
atomic_read ( & sk - > sk_wmem_alloc ) ) ;
sk - > sk_timer . data = ( unsigned long ) sk ;
sk - > sk_timer . expires = jiffies + HZ ;
sk - > sk_timer . function = wanpipe_destroy_timer ;
add_timer ( & sk - > sk_timer ) ;
return 0 ;
}
kfree ( wp ) ;
wp_sk ( sk ) = NULL ;
if ( atomic_read ( & sk - > sk_refcnt ) ! = 1 ) {
DBG_PRINTK ( KERN_INFO " wansock: Error, wrong reference count: %i !:release. \n " ,
atomic_read ( & sk - > sk_refcnt ) ) ;
atomic_set ( & sk - > sk_refcnt , 1 ) ;
}
sock_put ( sk ) ;
atomic_dec ( & wanpipe_socks_nr ) ;
return 0 ;
}
/*============================================================
* check_write_queue
*
* During sock shutdown , if the sock state is
* WANSOCK_CONNECTED and there is transmit data
* pending . Wait until data is released
* before proceeding .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void check_write_queue ( struct sock * sk )
{
if ( sk - > sk_state ! = WANSOCK_CONNECTED )
return ;
if ( ! atomic_read ( & sk - > sk_wmem_alloc ) )
return ;
printk ( KERN_INFO " wansock: MAJOR ERROR, Data lost on sock release !!! \n " ) ;
}
/*============================================================
* release_driver
*
* This function is called during sock shutdown , to
* release any resources and links that bind the sock
* to the driver . It also changes the state of the
* sock to WANSOCK_DISCONNECTED
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void release_driver ( struct sock * sk )
{
wanpipe_opt * wp ;
struct sk_buff * skb = NULL ;
struct sock * deadsk = NULL ;
if ( sk - > sk_state = = WANSOCK_LISTEN | |
sk - > sk_state = = WANSOCK_BIND_LISTEN ) {
while ( ( skb = skb_dequeue ( & sk - > sk_receive_queue ) ) ! = NULL ) {
if ( ( deadsk = get_newsk_from_skb ( skb ) ) ) {
DBG_PRINTK ( KERN_INFO " wansock: RELEASE: FOUND DEAD SOCK \n " ) ;
sock_set_flag ( deadsk , SOCK_DEAD ) ;
start_cleanup_timer ( deadsk ) ;
}
kfree_skb ( skb ) ;
}
if ( sock_flag ( sk , SOCK_ZAPPED ) )
wanpipe_unlink_card ( sk ) ;
} else {
if ( sock_flag ( sk , SOCK_ZAPPED ) )
wanpipe_unlink_driver ( sk ) ;
}
sk - > sk_state = WANSOCK_DISCONNECTED ;
sk - > sk_bound_dev_if = 0 ;
sock_reset_flag ( sk , SOCK_ZAPPED ) ;
wp = wp_sk ( sk ) ;
2005-11-08 20:41:34 +03:00
if ( wp ) {
2005-04-17 02:20:36 +04:00
kfree ( wp - > mbox ) ;
wp - > mbox = NULL ;
}
}
/*============================================================
* start_cleanup_timer
*
* If new incoming call ' s are pending but the socket
* is being released , start the timer which will
* envoke the kill routines for pending socks .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void start_cleanup_timer ( struct sock * sk )
{
del_timer ( & sk - > sk_timer ) ;
sk - > sk_timer . data = ( unsigned long ) sk ;
sk - > sk_timer . expires = jiffies + HZ ;
sk - > sk_timer . function = wanpipe_kill_sock_timer ;
add_timer ( & sk - > sk_timer ) ;
}
/*============================================================
* wanpipe_kill_sock
*
* This is a function which performs actual killing
* of the sock . It releases socket resources ,
* and unlinks the sock from the driver .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void wanpipe_kill_sock_timer ( unsigned long data )
{
struct sock * sk = ( struct sock * ) data ;
struct sock * * skp ;
if ( ! sk )
return ;
/* This function can be called from interrupt. We must use
* appropriate locks */
if ( test_bit ( 1 , & wanpipe_tx_critical ) ) {
sk - > sk_timer . expires = jiffies + 10 ;
add_timer ( & sk - > sk_timer ) ;
return ;
}
write_lock ( & wanpipe_sklist_lock ) ;
sk_del_node_init ( sk ) ;
write_unlock ( & wanpipe_sklist_lock ) ;
if ( wp_sk ( sk ) - > num = = htons ( X25_PROT ) & &
sk - > sk_state ! = WANSOCK_DISCONNECTED ) {
struct net_device * dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ;
wanpipe_common_t * chan ;
if ( dev ) {
chan = dev - > priv ;
atomic_set ( & chan - > disconnect , 1 ) ;
dev_put ( dev ) ;
}
}
release_driver ( sk ) ;
sk - > sk_socket = NULL ;
/* Purge queues */
skb_queue_purge ( & sk - > sk_receive_queue ) ;
skb_queue_purge ( & sk - > sk_write_queue ) ;
skb_queue_purge ( & sk - > sk_error_queue ) ;
if ( atomic_read ( & sk - > sk_rmem_alloc ) | |
atomic_read ( & sk - > sk_wmem_alloc ) ) {
del_timer ( & sk - > sk_timer ) ;
printk ( KERN_INFO " wansock: Killing SOCK in Timer \n " ) ;
sk - > sk_timer . data = ( unsigned long ) sk ;
sk - > sk_timer . expires = jiffies + HZ ;
sk - > sk_timer . function = wanpipe_destroy_timer ;
add_timer ( & sk - > sk_timer ) ;
return ;
}
2005-11-08 20:41:34 +03:00
kfree ( wp_sk ( sk ) ) ;
wp_sk ( sk ) = NULL ;
2005-04-17 02:20:36 +04:00
if ( atomic_read ( & sk - > sk_refcnt ) ! = 1 ) {
atomic_set ( & sk - > sk_refcnt , 1 ) ;
DBG_PRINTK ( KERN_INFO " wansock: Error, wrong reference count: %i ! :timer. \n " ,
atomic_read ( & sk - > sk_refcnt ) ) ;
}
sock_put ( sk ) ;
atomic_dec ( & wanpipe_socks_nr ) ;
return ;
}
static void wanpipe_kill_sock_accept ( struct sock * sk )
{
struct sock * * skp ;
if ( ! sk )
return ;
/* This function can be called from interrupt. We must use
* appropriate locks */
write_lock ( & wanpipe_sklist_lock ) ;
sk_del_node_init ( sk ) ;
write_unlock ( & wanpipe_sklist_lock ) ;
sk - > sk_socket = NULL ;
2005-11-08 20:41:34 +03:00
kfree ( wp_sk ( sk ) ) ;
wp_sk ( sk ) = NULL ;
2005-04-17 02:20:36 +04:00
if ( atomic_read ( & sk - > sk_refcnt ) ! = 1 ) {
atomic_set ( & sk - > sk_refcnt , 1 ) ;
DBG_PRINTK ( KERN_INFO " wansock: Error, wrong reference count: %i ! :timer. \n " ,
atomic_read ( & sk - > sk_refcnt ) ) ;
}
sock_put ( sk ) ;
atomic_dec ( & wanpipe_socks_nr ) ;
return ;
}
static void wanpipe_kill_sock_irq ( struct sock * sk )
{
if ( ! sk )
return ;
sk - > sk_socket = NULL ;
2005-11-08 20:41:34 +03:00
kfree ( wp_sk ( sk ) ) ;
wp_sk ( sk ) = NULL ;
2005-04-17 02:20:36 +04:00
if ( atomic_read ( & sk - > sk_refcnt ) ! = 1 ) {
atomic_set ( & sk - > sk_refcnt , 1 ) ;
DBG_PRINTK ( KERN_INFO " wansock: Error, wrong reference count: %i !:listen. \n " ,
atomic_read ( & sk - > sk_refcnt ) ) ;
}
sock_put ( sk ) ;
atomic_dec ( & wanpipe_socks_nr ) ;
}
/*============================================================
* wanpipe_do_bind
*
* Bottom half of the binding system call .
* Once the wanpipe_bind ( ) function checks the
* legality of the call , this function binds the
* sock to the driver .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_do_bind ( struct sock * sk , struct net_device * dev ,
int protocol )
{
wanpipe_opt * wp = wp_sk ( sk ) ;
wanpipe_common_t * chan = NULL ;
int err = 0 ;
if ( sock_flag ( sk , SOCK_ZAPPED ) ) {
err = - EALREADY ;
goto bind_unlock_exit ;
}
wp - > num = protocol ;
if ( protocol = = 0 ) {
release_device ( dev ) ;
err = - EINVAL ;
goto bind_unlock_exit ;
}
if ( dev ) {
if ( dev - > flags & IFF_UP ) {
chan = dev - > priv ;
sk - > sk_state = chan - > state ;
if ( wp - > num = = htons ( X25_PROT ) & &
sk - > sk_state ! = WANSOCK_DISCONNECTED & &
sk - > sk_state ! = WANSOCK_CONNECTING ) {
DBG_PRINTK ( KERN_INFO
" wansock: Binding to Device not DISCONNECTED %i \n " ,
sk - > sk_state ) ;
release_device ( dev ) ;
err = - EAGAIN ;
goto bind_unlock_exit ;
}
wanpipe_link_driver ( dev , sk ) ;
sk - > sk_bound_dev_if = dev - > ifindex ;
/* X25 Specific option */
if ( wp - > num = = htons ( X25_PROT ) )
wp_sk ( sk ) - > svc = chan - > svc ;
} else {
sk - > sk_err = ENETDOWN ;
sk - > sk_error_report ( sk ) ;
release_device ( dev ) ;
err = - EINVAL ;
}
} else {
err = - ENODEV ;
}
bind_unlock_exit :
/* FIXME where is this lock */
return err ;
}
/*============================================================
* wanpipe_bind
*
* BIND ( ) System call , which is bound to the AF_WANPIPE
* operations structure . It checks for correct wanpipe
* card name , and cross references interface names with
* the card names . Thus , interface name must belong to
* the actual card .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_bind ( struct socket * sock , struct sockaddr * uaddr , int addr_len )
{
struct wan_sockaddr_ll * sll = ( struct wan_sockaddr_ll * ) uaddr ;
struct sock * sk = sock - > sk ;
wanpipe_opt * wp = wp_sk ( sk ) ;
struct net_device * dev = NULL ;
sdla_t * card = NULL ;
char name [ 15 ] ;
/*
* Check legality
*/
if ( addr_len < sizeof ( struct wan_sockaddr_ll ) ) {
printk ( KERN_INFO " wansock: Address length error \n " ) ;
return - EINVAL ;
}
if ( sll - > sll_family ! = AF_WANPIPE ) {
printk ( KERN_INFO " wansock: Illegal family name specified. \n " ) ;
return - EINVAL ;
}
card = wanpipe_find_card ( sll - > sll_card ) ;
if ( ! card ) {
printk ( KERN_INFO " wansock: Wanpipe card not found: %s \n " , sll - > sll_card ) ;
return - ENODEV ;
} else {
wp_sk ( sk ) - > card = ( void * ) card ;
}
if ( ! strcmp ( sll - > sll_device , " svc_listen " ) ) {
/* Bind a sock to a card structure for listening
*/
int err = 0 ;
/* This is x25 specific area if protocol doesn't
* match , return error */
if ( sll - > sll_protocol ! = htons ( X25_PROT ) )
return - EINVAL ;
err = wanpipe_link_card ( sk ) ;
if ( err < 0 )
return err ;
if ( sll - > sll_protocol )
wp - > num = sll - > sll_protocol ;
sk - > sk_state = WANSOCK_BIND_LISTEN ;
return 0 ;
} else if ( ! strcmp ( sll - > sll_device , " svc_connect " ) ) {
/* This is x25 specific area if protocol doesn't
* match , return error */
if ( sll - > sll_protocol ! = htons ( X25_PROT ) )
return - EINVAL ;
/* Find a free device
*/
dev = wanpipe_find_free_dev ( card ) ;
if ( dev = = NULL ) {
DBG_PRINTK ( KERN_INFO " wansock: No free network devices for card %s \n " ,
card - > devname ) ;
return - EINVAL ;
}
} else {
/* Bind a socket to a interface name
* This is used by PVC mostly
*/
strlcpy ( name , sll - > sll_device , sizeof ( name ) ) ;
dev = dev_get_by_name ( name ) ;
if ( dev = = NULL ) {
printk ( KERN_INFO " wansock: Failed to get Dev from name: %s, \n " ,
name ) ;
return - ENODEV ;
}
dev_put ( dev ) ;
if ( check_dev ( dev , card ) ) {
printk ( KERN_INFO " wansock: Device %s, doesn't belong to card %s \n " ,
dev - > name , card - > devname ) ;
return - EINVAL ;
}
if ( get_atomic_device ( dev ) )
return - EINVAL ;
}
return wanpipe_do_bind ( sk , dev , sll - > sll_protocol ? : wp - > num ) ;
}
/*============================================================
* get_atomic_device
*
* Sets a bit atomically which indicates that
* the interface is taken . This avoids race conditions .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static inline int get_atomic_device ( struct net_device * dev )
{
wanpipe_common_t * chan = dev - > priv ;
if ( ! test_and_set_bit ( 0 , ( void * ) & chan - > rw_bind ) ) {
return 0 ;
}
return 1 ;
}
/*============================================================
* check_dev
*
* Check that device name belongs to a particular card .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int check_dev ( struct net_device * dev , sdla_t * card )
{
struct net_device * tmp_dev ;
for ( tmp_dev = card - > wandev . dev ; tmp_dev ;
tmp_dev = * ( ( struct net_device * * ) tmp_dev - > priv ) ) {
if ( tmp_dev - > ifindex = = dev - > ifindex ) {
return 0 ;
}
}
return 1 ;
}
/*============================================================
* wanpipe_find_free_dev
*
* Find a free network interface . If found set atomic
* bit indicating that the interface is taken .
* X25API Specific .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
struct net_device * wanpipe_find_free_dev ( sdla_t * card )
{
struct net_device * dev ;
volatile wanpipe_common_t * chan ;
if ( test_and_set_bit ( 0 , & find_free_critical ) ) {
printk ( KERN_INFO " CRITICAL in Find Free \n " ) ;
}
for ( dev = card - > wandev . dev ; dev ;
dev = * ( ( struct net_device * * ) dev - > priv ) ) {
chan = dev - > priv ;
if ( ! chan )
continue ;
if ( chan - > usedby = = API & & chan - > svc ) {
if ( ! get_atomic_device ( dev ) ) {
if ( chan - > state ! = WANSOCK_DISCONNECTED ) {
release_device ( dev ) ;
} else {
clear_bit ( 0 , & find_free_critical ) ;
return dev ;
}
}
}
}
clear_bit ( 0 , & find_free_critical ) ;
return NULL ;
}
/*============================================================
* wanpipe_create
*
* SOCKET ( ) System call . It allocates a sock structure
* and adds the socket to the wanpipe_sk_list .
* Crates AF_WANPIPE socket .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_create ( struct socket * sock , int protocol )
{
struct sock * sk ;
//FIXME: This checks for root user, SECURITY ?
//if (!capable(CAP_NET_RAW))
// return -EPERM;
if ( sock - > type ! = SOCK_DGRAM & & sock - > type ! = SOCK_RAW )
return - ESOCKTNOSUPPORT ;
sock - > state = SS_UNCONNECTED ;
if ( ( sk = wanpipe_alloc_socket ( ) ) = = NULL )
return - ENOBUFS ;
sk - > sk_reuse = 1 ;
sock - > ops = & wanpipe_ops ;
sock_init_data ( sock , sk ) ;
sock_reset_flag ( sk , SOCK_ZAPPED ) ;
sk - > sk_family = PF_WANPIPE ;
wp_sk ( sk ) - > num = protocol ;
sk - > sk_state = WANSOCK_DISCONNECTED ;
sk - > sk_ack_backlog = 0 ;
sk - > sk_bound_dev_if = 0 ;
atomic_inc ( & wanpipe_socks_nr ) ;
/* We must disable interrupts because the ISR
* can also change the list */
set_bit ( 1 , & wanpipe_tx_critical ) ;
write_lock ( & wanpipe_sklist_lock ) ;
sk_add_node ( sk , & wanpipe_sklist ) ;
write_unlock ( & wanpipe_sklist_lock ) ;
clear_bit ( 1 , & wanpipe_tx_critical ) ;
return ( 0 ) ;
}
/*============================================================
* wanpipe_recvmsg
*
* Pull a packet from our receive queue and hand it
* to the user . If necessary we block .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_recvmsg ( struct kiocb * iocb , struct socket * sock ,
struct msghdr * msg , int len , int flags )
{
struct sock * sk = sock - > sk ;
struct sk_buff * skb ;
int copied , err = - ENOBUFS ;
/*
* If the address length field is there to be filled in , we fill
* it in now .
*/
msg - > msg_namelen = sizeof ( struct wan_sockaddr_ll ) ;
/*
* Call the generic datagram receiver . This handles all sorts
* of horrible races and re - entrancy so we can forget about it
* in the protocol layers .
*
* Now it will return ENETDOWN , if device have just gone down ,
* but then it will block .
*/
if ( flags & MSG_OOB ) {
skb = skb_dequeue ( & sk - > sk_error_queue ) ;
} else {
skb = skb_recv_datagram ( sk , flags , 1 , & err ) ;
}
/*
* An error occurred so return it . Because skb_recv_datagram ( )
* handles the blocking we don ' t see and worry about blocking
* retries .
*/
if ( skb = = NULL )
goto out ;
/*
* You lose any data beyond the buffer you gave . If it worries a
* user program they can ask the device for its MTU anyway .
*/
copied = skb - > len ;
if ( copied > len )
{
copied = len ;
msg - > msg_flags | = MSG_TRUNC ;
}
wanpipe_wakeup_driver ( sk ) ;
/* We can't use skb_copy_datagram here */
err = memcpy_toiovec ( msg - > msg_iov , skb - > data , copied ) ;
if ( err )
goto out_free ;
sock_recv_timestamp ( msg , sk , skb ) ;
if ( msg - > msg_name )
memcpy ( msg - > msg_name , skb - > cb , msg - > msg_namelen ) ;
/*
* Free or return the buffer as appropriate . Again this
* hides all the races and re - entrancy issues from us .
*/
err = ( flags & MSG_TRUNC ) ? skb - > len : copied ;
out_free :
skb_free_datagram ( sk , skb ) ;
out :
return err ;
}
/*============================================================
* wanpipe_wakeup_driver
*
* If socket receive buffer is full and driver cannot
* pass data up the sock , it sets a packet_block flag .
* This function check that flag and if sock receive
* queue has room it kicks the driver BH handler .
*
* This way , driver doesn ' t have to poll the sock
* receive queue .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void wanpipe_wakeup_driver ( struct sock * sk )
{
struct net_device * dev = NULL ;
wanpipe_common_t * chan = NULL ;
dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ;
if ( ! dev )
return ;
dev_put ( dev ) ;
if ( ( chan = dev - > priv ) = = NULL )
return ;
if ( atomic_read ( & chan - > receive_block ) ) {
if ( atomic_read ( & sk - > sk_rmem_alloc ) <
( ( unsigned ) sk - > sk_rcvbuf * 0.9 ) ) {
printk ( KERN_INFO " wansock: Queuing task for wanpipe \n " ) ;
atomic_set ( & chan - > receive_block , 0 ) ;
wanpipe_queue_tq ( & chan - > wanpipe_task ) ;
wanpipe_mark_bh ( ) ;
}
}
}
/*============================================================
* wanpipe_getname
*
* I don ' t know what to do with this yet .
* User can use this function to get sock address
* information . Not very useful for Sangoma ' s purposes .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_getname ( struct socket * sock , struct sockaddr * uaddr ,
int * uaddr_len , int peer )
{
struct net_device * dev ;
struct sock * sk = sock - > sk ;
struct wan_sockaddr_ll * sll = ( struct wan_sockaddr_ll * ) uaddr ;
sll - > sll_family = AF_WANPIPE ;
sll - > sll_ifindex = sk - > sk_bound_dev_if ;
sll - > sll_protocol = wp_sk ( sk ) - > num ;
dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ;
if ( dev ) {
sll - > sll_hatype = dev - > type ;
sll - > sll_halen = dev - > addr_len ;
memcpy ( sll - > sll_addr , dev - > dev_addr , dev - > addr_len ) ;
} else {
sll - > sll_hatype = 0 ; /* Bad: we have no ARPHRD_UNSPEC */
sll - > sll_halen = 0 ;
}
* uaddr_len = sizeof ( * sll ) ;
dev_put ( dev ) ;
return 0 ;
}
/*============================================================
* wanpipe_notifier
*
* If driver turns off network interface , this function
* will be envoked . Currently I treate it as a
* call disconnect . More thought should go into this
* function .
*
* FIXME : More thought should go into this function .
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_notifier ( struct notifier_block * this , unsigned long msg , void * data )
{
struct sock * sk ;
hlist_node * node ;
struct net_device * dev = ( struct net_device * ) data ;
sk_for_each ( sk , node , & wanpipe_sklist ) {
struct wanpipe_opt * po = wp_sk ( sk ) ;
if ( ! po )
continue ;
if ( dev = = NULL )
continue ;
switch ( msg ) {
case NETDEV_DOWN :
case NETDEV_UNREGISTER :
if ( dev - > ifindex = = sk - > sk_bound_dev_if ) {
printk ( KERN_INFO " wansock: Device down %s \n " , dev - > name ) ;
if ( sock_flag ( sk , SOCK_ZAPPED ) ) {
wanpipe_unlink_driver ( sk ) ;
sk - > sk_err = ENETDOWN ;
sk - > sk_error_report ( sk ) ;
}
if ( msg = = NETDEV_UNREGISTER ) {
printk ( KERN_INFO " wansock: Unregistering Device: %s \n " ,
dev - > name ) ;
wanpipe_unlink_driver ( sk ) ;
sk - > sk_bound_dev_if = 0 ;
}
}
break ;
case NETDEV_UP :
if ( dev - > ifindex = = sk - > sk_bound_dev_if & &
po - > num & & ! sock_flag ( sk , SOCK_ZAPPED ) ) {
printk ( KERN_INFO " wansock: Registering Device: %s \n " ,
dev - > name ) ;
wanpipe_link_driver ( dev , sk ) ;
}
break ;
}
}
return NOTIFY_DONE ;
}
/*============================================================
* wanpipe_ioctl
*
* Execute a user commands , and set socket options .
*
* FIXME : More thought should go into this function .
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_ioctl ( struct socket * sock , unsigned int cmd , unsigned long arg )
{
struct sock * sk = sock - > sk ;
int err ;
switch ( cmd )
{
case SIOCGSTAMP :
return sock_get_timestamp ( sk , ( struct timeval __user * ) arg ) ;
case SIOC_WANPIPE_CHECK_TX :
return atomic_read ( & sk - > sk_wmem_alloc ) ;
case SIOC_WANPIPE_SOCK_STATE :
if ( sk - > sk_state = = WANSOCK_CONNECTED )
return 0 ;
return 1 ;
case SIOC_WANPIPE_GET_CALL_DATA :
return get_ioctl_cmd ( sk , ( void * ) arg ) ;
case SIOC_WANPIPE_SET_CALL_DATA :
return set_ioctl_cmd ( sk , ( void * ) arg ) ;
case SIOC_WANPIPE_ACCEPT_CALL :
case SIOC_WANPIPE_CLEAR_CALL :
case SIOC_WANPIPE_RESET_CALL :
if ( ( err = set_ioctl_cmd ( sk , ( void * ) arg ) ) < 0 )
return err ;
err = wanpipe_exec_cmd ( sk , cmd , 0 ) ;
get_ioctl_cmd ( sk , ( void * ) arg ) ;
return err ;
case SIOC_WANPIPE_DEBUG :
return wanpipe_debug ( sk , ( void * ) arg ) ;
case SIOC_WANPIPE_SET_NONBLOCK :
if ( sk - > sk_state ! = WANSOCK_DISCONNECTED )
return - EINVAL ;
sock - > file - > f_flags | = O_NONBLOCK ;
return 0 ;
# ifdef CONFIG_INET
case SIOCADDRT :
case SIOCDELRT :
case SIOCDARP :
case SIOCGARP :
case SIOCSARP :
case SIOCDRARP :
case SIOCGRARP :
case SIOCSRARP :
case SIOCGIFADDR :
case SIOCSIFADDR :
case SIOCGIFBRDADDR :
case SIOCSIFBRDADDR :
case SIOCGIFNETMASK :
case SIOCSIFNETMASK :
case SIOCGIFDSTADDR :
case SIOCSIFDSTADDR :
case SIOCSIFFLAGS :
return inet_dgram_ops . ioctl ( sock , cmd , arg ) ;
# endif
default :
2006-01-04 01:18:33 +03:00
return - ENOIOCTLCMD ;
2005-04-17 02:20:36 +04:00
}
/*NOTREACHED*/
}
/*============================================================
* wanpipe_debug
*
* This function will pass up information about all
* active sockets .
*
* FIXME : More thought should go into this function .
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_debug ( struct sock * origsk , void * arg )
{
struct sock * sk ;
struct hlist_node * node ;
struct net_device * dev = NULL ;
wanpipe_common_t * chan = NULL ;
int cnt = 0 , err = 0 ;
wan_debug_t * dbg_data = ( wan_debug_t * ) arg ;
sk_for_each ( sk , node , & wanpipe_sklist ) {
wanpipe_opt * wp = wp_sk ( sk ) ;
if ( sk = = origsk ) {
continue ;
}
if ( ( err = put_user ( 1 , & dbg_data - > debug [ cnt ] . free ) ) )
return err ;
if ( ( err = put_user ( sk - > sk_state ,
& dbg_data - > debug [ cnt ] . state_sk ) ) )
return err ;
if ( ( err = put_user ( sk - > sk_rcvbuf ,
& dbg_data - > debug [ cnt ] . rcvbuf ) ) )
return err ;
if ( ( err = put_user ( atomic_read ( & sk - > sk_rmem_alloc ) ,
& dbg_data - > debug [ cnt ] . rmem ) ) )
return err ;
if ( ( err = put_user ( atomic_read ( & sk - > sk_wmem_alloc ) ,
& dbg_data - > debug [ cnt ] . wmem ) ) )
return err ;
if ( ( err = put_user ( sk - > sk_sndbuf ,
& dbg_data - > debug [ cnt ] . sndbuf ) ) )
return err ;
if ( ( err = put_user ( sk_count , & dbg_data - > debug [ cnt ] . sk_count ) ) )
return err ;
if ( ( err = put_user ( wp - > poll_cnt , & dbg_data - > debug [ cnt ] . poll_cnt ) ) )
return err ;
if ( ( err = put_user ( sk - > sk_bound_dev_if ,
& dbg_data - > debug [ cnt ] . bound ) ) )
return err ;
if ( sk - > sk_bound_dev_if ) {
dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ;
if ( ! dev )
continue ;
chan = dev - > priv ;
dev_put ( dev ) ;
if ( ( err = put_user ( chan - > state , & dbg_data - > debug [ cnt ] . d_state ) ) )
return err ;
if ( ( err = put_user ( chan - > svc , & dbg_data - > debug [ cnt ] . svc ) ) )
return err ;
if ( ( err = put_user ( atomic_read ( & chan - > command ) ,
& dbg_data - > debug [ cnt ] . command ) ) )
return err ;
if ( wp ) {
sdla_t * card = ( sdla_t * ) wp - > card ;
if ( card ) {
if ( ( err = put_user ( atomic_read ( & card - > u . x . command_busy ) ,
& dbg_data - > debug [ cnt ] . cmd_busy ) ) )
return err ;
}
if ( ( err = put_user ( wp - > lcn ,
& dbg_data - > debug [ cnt ] . lcn ) ) )
return err ;
if ( wp - > mbox ) {
if ( ( err = put_user ( 1 , & dbg_data - > debug [ cnt ] . mbox ) ) )
return err ;
}
}
if ( ( err = put_user ( atomic_read ( & chan - > receive_block ) ,
& dbg_data - > debug [ cnt ] . rblock ) ) )
return err ;
if ( copy_to_user ( dbg_data - > debug [ cnt ] . name , dev - > name , strlen ( dev - > name ) ) )
return - EFAULT ;
}
if ( + + cnt = = MAX_NUM_DEBUG )
break ;
}
return 0 ;
}
/*============================================================
* get_ioctl_cmd
*
* Pass up the contents of socket MBOX to the user .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int get_ioctl_cmd ( struct sock * sk , void * arg )
{
x25api_t * usr_data = ( x25api_t * ) arg ;
mbox_cmd_t * mbox_ptr ;
int err ;
if ( usr_data = = NULL )
return - EINVAL ;
if ( ! wp_sk ( sk ) - > mbox ) {
return - EINVAL ;
}
mbox_ptr = ( mbox_cmd_t * ) wp_sk ( sk ) - > mbox ;
if ( ( err = put_user ( mbox_ptr - > cmd . qdm , & usr_data - > hdr . qdm ) ) )
return err ;
if ( ( err = put_user ( mbox_ptr - > cmd . cause , & usr_data - > hdr . cause ) ) )
return err ;
if ( ( err = put_user ( mbox_ptr - > cmd . diagn , & usr_data - > hdr . diagn ) ) )
return err ;
if ( ( err = put_user ( mbox_ptr - > cmd . length , & usr_data - > hdr . length ) ) )
return err ;
if ( ( err = put_user ( mbox_ptr - > cmd . result , & usr_data - > hdr . result ) ) )
return err ;
if ( ( err = put_user ( mbox_ptr - > cmd . lcn , & usr_data - > hdr . lcn ) ) )
return err ;
if ( mbox_ptr - > cmd . length > 0 ) {
if ( mbox_ptr - > cmd . length > X25_MAX_DATA )
return - EINVAL ;
if ( copy_to_user ( usr_data - > data , mbox_ptr - > data , mbox_ptr - > cmd . length ) ) {
printk ( KERN_INFO " wansock: Copy failed !!! \n " ) ;
return - EFAULT ;
}
}
return 0 ;
}
/*============================================================
* set_ioctl_cmd
*
* Before command can be execute , socket MBOX must
* be created , and initialized with user data .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int set_ioctl_cmd ( struct sock * sk , void * arg )
{
x25api_t * usr_data = ( x25api_t * ) arg ;
mbox_cmd_t * mbox_ptr ;
int err ;
if ( ! wp_sk ( sk ) - > mbox ) {
void * mbox_ptr ;
struct net_device * dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ;
if ( ! dev )
return - ENODEV ;
dev_put ( dev ) ;
2006-07-22 01:51:30 +04:00
if ( ( mbox_ptr = kzalloc ( sizeof ( mbox_cmd_t ) , GFP_ATOMIC ) ) = = NULL )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
wp_sk ( sk ) - > mbox = mbox_ptr ;
wanpipe_link_driver ( dev , sk ) ;
}
mbox_ptr = ( mbox_cmd_t * ) wp_sk ( sk ) - > mbox ;
memset ( mbox_ptr , 0 , sizeof ( mbox_cmd_t ) ) ;
if ( usr_data = = NULL ) {
return 0 ;
}
if ( ( err = get_user ( mbox_ptr - > cmd . qdm , & usr_data - > hdr . qdm ) ) )
return err ;
if ( ( err = get_user ( mbox_ptr - > cmd . cause , & usr_data - > hdr . cause ) ) )
return err ;
if ( ( err = get_user ( mbox_ptr - > cmd . diagn , & usr_data - > hdr . diagn ) ) )
return err ;
if ( ( err = get_user ( mbox_ptr - > cmd . length , & usr_data - > hdr . length ) ) )
return err ;
if ( ( err = get_user ( mbox_ptr - > cmd . result , & usr_data - > hdr . result ) ) )
return err ;
if ( mbox_ptr - > cmd . length > 0 ) {
if ( mbox_ptr - > cmd . length > X25_MAX_DATA )
return - EINVAL ;
if ( copy_from_user ( mbox_ptr - > data , usr_data - > data , mbox_ptr - > cmd . length ) ) {
printk ( KERN_INFO " Copy failed \n " ) ;
return - EFAULT ;
}
}
return 0 ;
}
/*======================================================================
* wanpipe_poll
*
* Datagram poll : Again totally generic . This also handles
* sequenced packet sockets providing the socket receive queue
* is only ever holding data ready to receive .
*
* Note : when you _don ' t_ use this routine for this protocol ,
* and you use a different write policy from sock_writeable ( )
* then please supply your own write_space callback .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
unsigned int wanpipe_poll ( struct file * file , struct socket * sock , poll_table * wait )
{
struct sock * sk = sock - > sk ;
unsigned int mask ;
+ + wp_sk ( sk ) - > poll_cnt ;
poll_wait ( file , sk - > sk_sleep , wait ) ;
mask = 0 ;
/* exceptional events? */
if ( sk - > sk_err | | ! skb_queue_empty ( & sk - > sk_error_queue ) ) {
mask | = POLLPRI ;
return mask ;
}
if ( sk - > sk_shutdown & RCV_SHUTDOWN )
mask | = POLLHUP ;
/* readable? */
if ( ! skb_queue_empty ( & sk - > sk_receive_queue ) ) {
mask | = POLLIN | POLLRDNORM ;
}
/* connection hasn't started yet */
if ( sk - > sk_state = = WANSOCK_CONNECTING ) {
return mask ;
}
if ( sk - > sk_state = = WANSOCK_DISCONNECTED ) {
mask = POLLPRI ;
return mask ;
}
/* This check blocks the user process if there is
* a packet already queued in the socket write queue .
* This option is only for X25API protocol , for other
* protocol like chdlc enable streaming mode ,
* where multiple packets can be pending in the socket
* transmit queue */
if ( wp_sk ( sk ) - > num = = htons ( X25_PROT ) ) {
if ( atomic_read ( & wp_sk ( sk ) - > packet_sent ) )
return mask ;
}
/* writable? */
if ( sock_writeable ( sk ) ) {
mask | = POLLOUT | POLLWRNORM | POLLWRBAND ;
} else {
set_bit ( SOCK_ASYNC_NOSPACE , & sk - > sk_socket - > flags ) ;
}
return mask ;
}
/*======================================================================
* wanpipe_listen
*
* X25API Specific function . Set a socket into LISTENING MODE .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_listen ( struct socket * sock , int backlog )
{
struct sock * sk = sock - > sk ;
/* This is x25 specific area if protocol doesn't
* match , return error */
if ( wp_sk ( sk ) - > num ! = htons ( X25_PROT ) )
return - EINVAL ;
if ( sk - > sk_state = = WANSOCK_BIND_LISTEN ) {
sk - > sk_max_ack_backlog = backlog ;
sk - > sk_state = WANSOCK_LISTEN ;
return 0 ;
} else {
printk ( KERN_INFO " wansock: Listening sock was not binded \n " ) ;
}
return - EINVAL ;
}
/*======================================================================
* wanpipe_link_card
*
* Connects the listening socket to the driver
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_link_card ( struct sock * sk )
{
sdla_t * card = ( sdla_t * ) wp_sk ( sk ) - > card ;
if ( ! card )
return - ENOMEM ;
if ( ( card - > sk ! = NULL ) | | ( card - > func ! = NULL ) ) {
printk ( KERN_INFO " wansock: Listening queue is already established \n " ) ;
return - EINVAL ;
}
card - > sk = sk ;
card - > func = wanpipe_listen_rcv ;
sock_set_flag ( sk , SOCK_ZAPPED ) ;
return 0 ;
}
/*======================================================================
* wanpipe_listen
*
* X25API Specific function . Disconnect listening socket from
* the driver .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void wanpipe_unlink_card ( struct sock * sk )
{
sdla_t * card = ( sdla_t * ) wp_sk ( sk ) - > card ;
if ( card ) {
card - > sk = NULL ;
card - > func = NULL ;
}
}
/*======================================================================
* wanpipe_exec_cmd
*
* Ioctl function calls this function to execute user command .
* Connect ( ) sytem call also calls this function to execute
* place call . This function blocks until command is executed .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_exec_cmd ( struct sock * sk , int cmd , unsigned int flags )
{
int err = - EINVAL ;
wanpipe_opt * wp = wp_sk ( sk ) ;
mbox_cmd_t * mbox_ptr = ( mbox_cmd_t * ) wp - > mbox ;
if ( ! mbox_ptr ) {
printk ( KERN_INFO " NO MBOX PTR !!!!! \n " ) ;
return - EINVAL ;
}
/* This is x25 specific area if protocol doesn't
* match , return error */
if ( wp - > num ! = htons ( X25_PROT ) )
return - EINVAL ;
switch ( cmd ) {
case SIOC_WANPIPE_ACCEPT_CALL :
if ( sk - > sk_state ! = WANSOCK_CONNECTING ) {
err = - EHOSTDOWN ;
break ;
}
err = execute_command ( sk , X25_ACCEPT_CALL , 0 ) ;
if ( err < 0 )
break ;
/* Update. Mar6 2000.
* Do not set the sock lcn number here , since
* it is done in wanpipe_listen_rcv ( ) .
*/
if ( sk - > sk_state = = WANSOCK_CONNECTED ) {
wp - > lcn = ( ( mbox_cmd_t * ) wp - > mbox ) - > cmd . lcn ;
DBG_PRINTK ( KERN_INFO " \n wansock: Accept OK %i \n " ,
wp - > lcn ) ;
err = 0 ;
} else {
DBG_PRINTK ( KERN_INFO " \n wansock: Accept Failed %i \n " ,
wp - > lcn ) ;
wp - > lcn = 0 ;
err = - ECONNREFUSED ;
}
break ;
case SIOC_WANPIPE_CLEAR_CALL :
if ( sk - > sk_state = = WANSOCK_DISCONNECTED ) {
err = - EINVAL ;
break ;
}
/* Check if data buffers are pending for transmission,
* if so , check whether user wants to wait until data
* is transmitted , or clear a call and drop packets */
if ( atomic_read ( & sk - > sk_wmem_alloc ) | |
check_driver_busy ( sk ) ) {
mbox_cmd_t * mbox = wp - > mbox ;
if ( mbox - > cmd . qdm & 0x80 ) {
mbox - > cmd . result = 0x35 ;
err = - EAGAIN ;
break ;
}
}
sk - > sk_state = WANSOCK_DISCONNECTING ;
err = execute_command ( sk , X25_CLEAR_CALL , 0 ) ;
if ( err < 0 )
break ;
err = - ECONNREFUSED ;
if ( sk - > sk_state = = WANSOCK_DISCONNECTED ) {
DBG_PRINTK ( KERN_INFO " \n wansock: CLEAR OK %i \n " ,
wp - > lcn ) ;
wp - > lcn = 0 ;
err = 0 ;
}
break ;
case SIOC_WANPIPE_RESET_CALL :
if ( sk - > sk_state ! = WANSOCK_CONNECTED ) {
err = - EINVAL ;
break ;
}
/* Check if data buffers are pending for transmission,
* if so , check whether user wants to wait until data
* is transmitted , or reset a call and drop packets */
if ( atomic_read ( & sk - > sk_wmem_alloc ) | |
check_driver_busy ( sk ) ) {
mbox_cmd_t * mbox = wp - > mbox ;
if ( mbox - > cmd . qdm & 0x80 ) {
mbox - > cmd . result = 0x35 ;
err = - EAGAIN ;
break ;
}
}
err = execute_command ( sk , X25_RESET , 0 ) ;
if ( err < 0 )
break ;
err = mbox_ptr - > cmd . result ;
break ;
case X25_PLACE_CALL :
err = execute_command ( sk , X25_PLACE_CALL , flags ) ;
if ( err < 0 )
break ;
if ( sk - > sk_state = = WANSOCK_CONNECTED ) {
wp - > lcn = ( ( mbox_cmd_t * ) wp - > mbox ) - > cmd . lcn ;
DBG_PRINTK ( KERN_INFO " \n wansock: PLACE CALL OK %i \n " ,
wp - > lcn ) ;
err = 0 ;
} else if ( sk - > sk_state = = WANSOCK_CONNECTING & &
( flags & O_NONBLOCK ) ) {
wp - > lcn = ( ( mbox_cmd_t * ) wp - > mbox ) - > cmd . lcn ;
DBG_PRINTK ( KERN_INFO " \n wansock: Place Call OK: Waiting %i \n " ,
wp - > lcn ) ;
err = 0 ;
} else {
DBG_PRINTK ( KERN_INFO " \n wansock: Place call Failed \n " ) ;
err = - ECONNREFUSED ;
}
break ;
default :
return - EINVAL ;
}
return err ;
}
static int check_driver_busy ( struct sock * sk )
{
struct net_device * dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ;
wanpipe_common_t * chan ;
if ( ! dev )
return 0 ;
dev_put ( dev ) ;
if ( ( chan = dev - > priv ) = = NULL )
return 0 ;
return atomic_read ( & chan - > driver_busy ) ;
}
/*======================================================================
* wanpipe_accept
*
* ACCEPT ( ) System call . X25API Specific function .
* For each incoming call , create a new socket and
* return it to the user .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_accept ( struct socket * sock , struct socket * newsock , int flags )
{
struct sock * sk ;
struct sock * newsk ;
struct sk_buff * skb ;
DECLARE_WAITQUEUE ( wait , current ) ;
int err = 0 ;
if ( newsock - > sk ! = NULL ) {
wanpipe_kill_sock_accept ( newsock - > sk ) ;
newsock - > sk = NULL ;
}
if ( ( sk = sock - > sk ) = = NULL )
return - EINVAL ;
if ( sk - > sk_type ! = SOCK_RAW )
return - EOPNOTSUPP ;
if ( sk - > sk_state ! = WANSOCK_LISTEN )
return - EINVAL ;
if ( wp_sk ( sk ) - > num ! = htons ( X25_PROT ) )
return - EINVAL ;
add_wait_queue ( sk - > sk_sleep , & wait ) ;
current - > state = TASK_INTERRUPTIBLE ;
for ( ; ; ) {
skb = skb_dequeue ( & sk - > sk_receive_queue ) ;
if ( skb ) {
err = 0 ;
break ;
}
if ( signal_pending ( current ) ) {
err = - ERESTARTSYS ;
break ;
}
schedule ( ) ;
}
current - > state = TASK_RUNNING ;
remove_wait_queue ( sk - > sk_sleep , & wait ) ;
if ( err ! = 0 )
return err ;
newsk = get_newsk_from_skb ( skb ) ;
if ( ! newsk ) {
return - EINVAL ;
}
set_bit ( 1 , & wanpipe_tx_critical ) ;
write_lock ( & wanpipe_sklist_lock ) ;
sk_add_node ( newsk , & wanpipe_sklist ) ;
write_unlock ( & wanpipe_sklist_lock ) ;
clear_bit ( 1 , & wanpipe_tx_critical ) ;
newsk - > sk_socket = newsock ;
newsk - > sk_sleep = & newsock - > wait ;
/* Now attach up the new socket */
sk - > sk_ack_backlog - - ;
newsock - > sk = newsk ;
kfree_skb ( skb ) ;
DBG_PRINTK ( KERN_INFO " \n wansock: ACCEPT Got LCN %i \n " ,
wp_sk ( newsk ) - > lcn ) ;
return 0 ;
}
/*======================================================================
* get_newsk_from_skb
*
* Accept ( ) uses this function to get the address of the new
* socket structure .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
struct sock * get_newsk_from_skb ( struct sk_buff * skb )
{
struct net_device * dev = skb - > dev ;
wanpipe_common_t * chan ;
if ( ! dev ) {
return NULL ;
}
if ( ( chan = dev - > priv ) = = NULL ) {
return NULL ;
}
if ( ! chan - > sk ) {
return NULL ;
}
return ( struct sock * ) chan - > sk ;
}
/*======================================================================
* wanpipe_connect
*
* CONNECT ( ) System Call . X25API specific function
* Check the state of the sock , and execute PLACE_CALL command .
* Connect can ether block or return without waiting for connection ,
* if specified by user .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static int wanpipe_connect ( struct socket * sock , struct sockaddr * uaddr , int addr_len , int flags )
{
struct sock * sk = sock - > sk ;
struct wan_sockaddr_ll * addr = ( struct wan_sockaddr_ll * ) uaddr ;
struct net_device * dev ;
int err ;
if ( wp_sk ( sk ) - > num ! = htons ( X25_PROT ) )
return - EINVAL ;
if ( sk - > sk_state = = WANSOCK_CONNECTED )
return - EISCONN ; /* No reconnect on a seqpacket socket */
if ( sk - > sk_state ! = WAN_DISCONNECTED ) {
printk ( KERN_INFO " wansock: Trying to connect on channel NON DISCONNECT \n " ) ;
return - ECONNREFUSED ;
}
sk - > sk_state = WANSOCK_DISCONNECTED ;
sock - > state = SS_UNCONNECTED ;
if ( addr_len ! = sizeof ( struct wan_sockaddr_ll ) )
return - EINVAL ;
if ( addr - > sll_family ! = AF_WANPIPE )
return - EINVAL ;
if ( ( dev = dev_get_by_index ( sk - > sk_bound_dev_if ) ) = = NULL )
return - ENETUNREACH ;
dev_put ( dev ) ;
if ( ! sock_flag ( sk , SOCK_ZAPPED ) ) /* Must bind first - autobinding does not work */
return - EINVAL ;
sock - > state = SS_CONNECTING ;
sk - > sk_state = WANSOCK_CONNECTING ;
if ( ! wp_sk ( sk ) - > mbox ) {
if ( wp_sk ( sk ) - > svc )
return - EINVAL ;
else {
int err ;
if ( ( err = set_ioctl_cmd ( sk , NULL ) ) < 0 )
return err ;
}
}
if ( ( err = wanpipe_exec_cmd ( sk , X25_PLACE_CALL , flags ) ) ! = 0 ) {
sock - > state = SS_UNCONNECTED ;
sk - > sk_state = WANSOCK_CONNECTED ;
return err ;
}
if ( sk - > sk_state ! = WANSOCK_CONNECTED & & ( flags & O_NONBLOCK ) ) {
return 0 ;
}
if ( sk - > sk_state ! = WANSOCK_CONNECTED ) {
sock - > state = SS_UNCONNECTED ;
return - ECONNREFUSED ;
}
sock - > state = SS_CONNECTED ;
return 0 ;
}
2005-12-22 23:49:22 +03:00
const struct proto_ops wanpipe_ops = {
2005-04-17 02:20:36 +04:00
. family = PF_WANPIPE ,
. owner = THIS_MODULE ,
. release = wanpipe_release ,
. bind = wanpipe_bind ,
. connect = wanpipe_connect ,
. socketpair = sock_no_socketpair ,
. accept = wanpipe_accept ,
. getname = wanpipe_getname ,
. poll = wanpipe_poll ,
. ioctl = wanpipe_ioctl ,
. listen = wanpipe_listen ,
. shutdown = sock_no_shutdown ,
. setsockopt = sock_no_setsockopt ,
. getsockopt = sock_no_getsockopt ,
. sendmsg = wanpipe_sendmsg ,
. recvmsg = wanpipe_recvmsg
} ;
static struct net_proto_family wanpipe_family_ops = {
. family = PF_WANPIPE ,
. create = wanpipe_create ,
. owner = THIS_MODULE ,
} ;
struct notifier_block wanpipe_netdev_notifier = {
. notifier_call = wanpipe_notifier ,
} ;
# ifdef MODULE
void cleanup_module ( void )
{
printk ( KERN_INFO " wansock: Cleaning up \n " ) ;
unregister_netdevice_notifier ( & wanpipe_netdev_notifier ) ;
sock_unregister ( PF_WANPIPE ) ;
proto_unregister ( & wanpipe_proto ) ;
}
int init_module ( void )
{
int rc ;
printk ( KERN_INFO " wansock: Registering Socket \n " ) ;
rc = proto_register ( & wanpipe_proto , 0 ) ;
if ( rc ! = 0 )
goto out ;
sock_register ( & wanpipe_family_ops ) ;
register_netdevice_notifier ( & wanpipe_netdev_notifier ) ;
out :
return rc ;
}
# endif
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS_NETPROTO ( PF_WANPIPE ) ;