2005-04-17 02:20:36 +04:00
/*
* X .25 Packet Layer release 002
*
* This is ALPHA test software . This code may break your machine ,
* randomly fail to work with new releases , misbehave and / or generally
2007-02-09 17:25:27 +03:00
* screw up . It might even work .
2005-04-17 02:20:36 +04:00
*
* This code REQUIRES 2.1 .15 or higher
*
* This module :
* This module 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 .
*
* History
* X .25 001 Jonathan Naylor Started coding .
* X .25 002 Jonathan Naylor New timer architecture .
* Centralised disconnection processing .
*/
# include <linux/errno.h>
# include <linux/jiffies.h>
# include <linux/timer.h>
# include <net/sock.h>
2005-08-10 07:08:28 +04:00
# include <net/tcp_states.h>
2005-04-17 02:20:36 +04:00
# include <net/x25.h>
static void x25_heartbeat_expiry ( unsigned long ) ;
static void x25_timer_expiry ( unsigned long ) ;
void x25_init_timers ( struct sock * sk )
{
struct x25_sock * x25 = x25_sk ( sk ) ;
2008-01-24 08:20:07 +03:00
setup_timer ( & x25 - > timer , x25_timer_expiry , ( unsigned long ) sk ) ;
2005-04-17 02:20:36 +04:00
/* initialized by sock_init_data */
sk - > sk_timer . data = ( unsigned long ) sk ;
sk - > sk_timer . function = & x25_heartbeat_expiry ;
}
void x25_start_heartbeat ( struct sock * sk )
{
mod_timer ( & sk - > sk_timer , jiffies + 5 * HZ ) ;
}
void x25_stop_heartbeat ( struct sock * sk )
{
del_timer ( & sk - > sk_timer ) ;
}
void x25_start_t2timer ( struct sock * sk )
{
struct x25_sock * x25 = x25_sk ( sk ) ;
mod_timer ( & x25 - > timer , jiffies + x25 - > t2 ) ;
}
void x25_start_t21timer ( struct sock * sk )
{
struct x25_sock * x25 = x25_sk ( sk ) ;
mod_timer ( & x25 - > timer , jiffies + x25 - > t21 ) ;
}
void x25_start_t22timer ( struct sock * sk )
{
struct x25_sock * x25 = x25_sk ( sk ) ;
mod_timer ( & x25 - > timer , jiffies + x25 - > t22 ) ;
}
void x25_start_t23timer ( struct sock * sk )
{
struct x25_sock * x25 = x25_sk ( sk ) ;
mod_timer ( & x25 - > timer , jiffies + x25 - > t23 ) ;
}
void x25_stop_timer ( struct sock * sk )
{
del_timer ( & x25_sk ( sk ) - > timer ) ;
}
unsigned long x25_display_timer ( struct sock * sk )
{
struct x25_sock * x25 = x25_sk ( sk ) ;
if ( ! timer_pending ( & x25 - > timer ) )
return 0 ;
return x25 - > timer . expires - jiffies ;
}
static void x25_heartbeat_expiry ( unsigned long param )
{
struct sock * sk = ( struct sock * ) param ;
2007-02-09 17:25:27 +03:00
bh_lock_sock ( sk ) ;
if ( sock_owned_by_user ( sk ) ) /* can currently only occur in state 3 */
2005-04-17 02:20:36 +04:00
goto restart_heartbeat ;
switch ( x25_sk ( sk ) - > state ) {
case X25_STATE_0 :
/*
* Magic here : If we listen ( ) and a new link dies
* before it is accepted ( ) it isn ' t ' dead ' so doesn ' t
* get removed .
*/
if ( sock_flag ( sk , SOCK_DESTROY ) | |
( sk - > sk_state = = TCP_LISTEN & &
sock_flag ( sk , SOCK_DEAD ) ) ) {
2006-04-28 23:00:17 +04:00
bh_unlock_sock ( sk ) ;
2005-04-17 02:20:36 +04:00
x25_destroy_socket ( sk ) ;
2006-04-28 23:00:17 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
break ;
case X25_STATE_3 :
/*
* Check for the state of the receive buffer .
*/
x25_check_rbuf ( sk ) ;
break ;
}
restart_heartbeat :
x25_start_heartbeat ( sk ) ;
bh_unlock_sock ( sk ) ;
}
/*
* Timer has expired , it may have been T2 , T21 , T22 , or T23 . We can tell
* by the state machine state .
*/
static inline void x25_do_timer_expiry ( struct sock * sk )
{
struct x25_sock * x25 = x25_sk ( sk ) ;
switch ( x25 - > state ) {
case X25_STATE_3 : /* T2 */
if ( x25 - > condition & X25_COND_ACK_PENDING ) {
x25 - > condition & = ~ X25_COND_ACK_PENDING ;
x25_enquiry_response ( sk ) ;
}
break ;
case X25_STATE_1 : /* T21 */
case X25_STATE_4 : /* T22 */
x25_write_internal ( sk , X25_CLEAR_REQUEST ) ;
x25 - > state = X25_STATE_2 ;
x25_start_t23timer ( sk ) ;
break ;
case X25_STATE_2 : /* T23 */
x25_disconnect ( sk , ETIMEDOUT , 0 , 0 ) ;
break ;
}
}
static void x25_timer_expiry ( unsigned long param )
{
struct sock * sk = ( struct sock * ) param ;
bh_lock_sock ( sk ) ;
if ( sock_owned_by_user ( sk ) ) { /* can currently only occur in state 3 */
if ( x25_sk ( sk ) - > state = = X25_STATE_3 )
x25_start_t2timer ( sk ) ;
} else
x25_do_timer_expiry ( sk ) ;
bh_unlock_sock ( sk ) ;
}