2005-04-17 02:20:36 +04:00
/*********************************************************************
2007-02-09 17:24:53 +03:00
*
2005-04-17 02:20:36 +04:00
* Filename : irttp . c
* Version : 1.2
* Description : Tiny Transport Protocol ( TTP ) implementation
* Status : Stable
* Author : Dag Brattli < dagb @ cs . uit . no >
* Created at : Sun Aug 31 20 : 14 : 31 1997
* Modified at : Wed Jan 5 11 : 31 : 27 2000
* Modified by : Dag Brattli < dagb @ cs . uit . no >
2007-02-09 17:24:53 +03:00
*
* Copyright ( c ) 1998 - 2000 Dag Brattli < dagb @ cs . uit . no > ,
2005-04-17 02:20:36 +04:00
* All Rights Reserved .
* Copyright ( c ) 2000 - 2003 Jean Tourrilhes < jt @ hpl . hp . com >
2007-02-09 17:24:53 +03:00
*
* 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
2005-04-17 02:20:36 +04:00
* the License , or ( at your option ) any later version .
*
2007-10-20 01:21:04 +04:00
* Neither Dag Brattli nor University of Tromsø admit liability nor
2007-02-09 17:24:53 +03:00
* provide warranty for any of this software . This material is
2005-04-17 02:20:36 +04:00
* provided " AS-IS " and at no charge .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/skbuff.h>
# include <linux/init.h>
2006-12-04 07:15:30 +03:00
# include <linux/fs.h>
2005-04-17 02:20:36 +04:00
# include <linux/seq_file.h>
# include <asm/byteorder.h>
# include <asm/unaligned.h>
# include <net/irda/irda.h>
# include <net/irda/irlap.h>
# include <net/irda/irlmp.h>
# include <net/irda/parameters.h>
# include <net/irda/irttp.h>
2005-09-25 03:55:17 +04:00
static struct irttp_cb * irttp ;
2005-04-17 02:20:36 +04:00
static void __irttp_close_tsap ( struct tsap_cb * self ) ;
2007-02-09 17:24:53 +03:00
static int irttp_data_indication ( void * instance , void * sap ,
2005-04-17 02:20:36 +04:00
struct sk_buff * skb ) ;
2007-02-09 17:24:53 +03:00
static int irttp_udata_indication ( void * instance , void * sap ,
2005-04-17 02:20:36 +04:00
struct sk_buff * skb ) ;
2007-02-09 17:24:53 +03:00
static void irttp_disconnect_indication ( void * instance , void * sap ,
2005-04-17 02:20:36 +04:00
LM_REASON reason , struct sk_buff * ) ;
2007-02-09 17:24:53 +03:00
static void irttp_connect_indication ( void * instance , void * sap ,
2005-04-17 02:20:36 +04:00
struct qos_info * qos , __u32 max_sdu_size ,
__u8 header_size , struct sk_buff * skb ) ;
2007-02-09 17:24:53 +03:00
static void irttp_connect_confirm ( void * instance , void * sap ,
struct qos_info * qos , __u32 max_sdu_size ,
2005-04-17 02:20:36 +04:00
__u8 header_size , struct sk_buff * skb ) ;
static void irttp_run_tx_queue ( struct tsap_cb * self ) ;
static void irttp_run_rx_queue ( struct tsap_cb * self ) ;
static void irttp_flush_queues ( struct tsap_cb * self ) ;
static void irttp_fragment_skb ( struct tsap_cb * self , struct sk_buff * skb ) ;
static struct sk_buff * irttp_reassemble_skb ( struct tsap_cb * self ) ;
static void irttp_todo_expired ( unsigned long data ) ;
2007-02-09 17:24:53 +03:00
static int irttp_param_max_sdu_size ( void * instance , irda_param_t * param ,
2005-04-17 02:20:36 +04:00
int get ) ;
static void irttp_flow_indication ( void * instance , void * sap , LOCAL_FLOW flow ) ;
static void irttp_status_indication ( void * instance ,
LINK_STATUS link , LOCK_STATUS lock ) ;
/* Information for parsing parameters in IrTTP */
static pi_minor_info_t pi_minor_call_table [ ] = {
{ NULL , 0 } , /* 0x00 */
{ irttp_param_max_sdu_size , PV_INTEGER | PV_BIG_ENDIAN } /* 0x01 */
} ;
static pi_major_info_t pi_major_call_table [ ] = { { pi_minor_call_table , 2 } } ;
static pi_param_info_t param_info = { pi_major_call_table , 1 , 0x0f , 4 } ;
/************************ GLOBAL PROCEDURES ************************/
/*
* Function irttp_init ( void )
*
* Initialize the IrTTP layer . Called by module initialization code
*
*/
int __init irttp_init ( void )
{
2006-07-22 01:51:30 +04:00
irttp = kzalloc ( sizeof ( struct irttp_cb ) , GFP_KERNEL ) ;
2005-09-25 03:55:17 +04:00
if ( irttp = = NULL )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
irttp - > magic = TTP_MAGIC ;
irttp - > tsaps = hashbin_new ( HB_LOCK ) ;
if ( ! irttp - > tsaps ) {
IRDA_ERROR ( " %s: can't allocate IrTTP hashbin! \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-09-25 03:54:50 +04:00
kfree ( irttp ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
return 0 ;
}
/*
* Function irttp_cleanup ( void )
*
* Called by module destruction / cleanup code
*
*/
2007-07-18 13:16:30 +04:00
void irttp_cleanup ( void )
2005-04-17 02:20:36 +04:00
{
/* Check for main structure */
IRDA_ASSERT ( irttp - > magic = = TTP_MAGIC , return ; ) ;
/*
* Delete hashbin and close all TSAP instances in it
*/
hashbin_delete ( irttp - > tsaps , ( FREE_FUNC ) __irttp_close_tsap ) ;
irttp - > magic = 0 ;
/* De-allocate main structure */
kfree ( irttp ) ;
irttp = NULL ;
}
/*************************** SUBROUTINES ***************************/
/*
* Function irttp_start_todo_timer ( self , timeout )
*
* Start todo timer .
*
* Made it more effient and unsensitive to race conditions - Jean II
*/
static inline void irttp_start_todo_timer ( struct tsap_cb * self , int timeout )
{
/* Set new value for timer */
mod_timer ( & self - > todo_timer , jiffies + timeout ) ;
}
/*
* Function irttp_todo_expired ( data )
*
* Todo timer has expired !
*
* One of the restriction of the timer is that it is run only on the timer
* interrupt which run every 10 ms . This mean that even if you set the timer
* with a delay of 0 , it may take up to 10 ms before it ' s run .
* So , to minimise latency and keep cache fresh , we try to avoid using
* it as much as possible .
* Note : we can ' t use tasklets , because they can ' t be asynchronously
* killed ( need user context ) , and we can ' t guarantee that here . . .
* Jean II
*/
static void irttp_todo_expired ( unsigned long data )
{
struct tsap_cb * self = ( struct tsap_cb * ) data ;
/* Check that we still exist */
if ( ! self | | self - > magic ! = TTP_TSAP_MAGIC )
return ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s(instance=%p) \n " , __func__ , self ) ;
2005-04-17 02:20:36 +04:00
/* Try to make some progress, especially on Tx side - Jean II */
irttp_run_rx_queue ( self ) ;
irttp_run_tx_queue ( self ) ;
/* Check if time for disconnect */
if ( test_bit ( 0 , & self - > disconnect_pend ) ) {
/* Check if it's possible to disconnect yet */
if ( skb_queue_empty ( & self - > tx_queue ) ) {
/* Make sure disconnect is not pending anymore */
clear_bit ( 0 , & self - > disconnect_pend ) ; /* FALSE */
/* Note : self->disconnect_skb may be NULL */
irttp_disconnect_request ( self , self - > disconnect_skb ,
P_NORMAL ) ;
self - > disconnect_skb = NULL ;
} else {
/* Try again later */
irttp_start_todo_timer ( self , HZ / 10 ) ;
/* No reason to try and close now */
return ;
}
}
/* Check if it's closing time */
if ( self - > close_pend )
/* Finish cleanup */
irttp_close_tsap ( self ) ;
}
/*
* Function irttp_flush_queues ( self )
*
* Flushes ( removes all frames ) in transitt - buffer ( tx_list )
*/
void irttp_flush_queues ( struct tsap_cb * self )
{
struct sk_buff * skb ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
/* Deallocate frames waiting to be sent */
while ( ( skb = skb_dequeue ( & self - > tx_queue ) ) ! = NULL )
dev_kfree_skb ( skb ) ;
/* Deallocate received frames */
while ( ( skb = skb_dequeue ( & self - > rx_queue ) ) ! = NULL )
dev_kfree_skb ( skb ) ;
/* Deallocate received fragments */
while ( ( skb = skb_dequeue ( & self - > rx_fragments ) ) ! = NULL )
dev_kfree_skb ( skb ) ;
}
/*
* Function irttp_reassemble ( self )
*
* Makes a new ( continuous ) skb of all the fragments in the fragment
* queue
*
*/
static struct sk_buff * irttp_reassemble_skb ( struct tsap_cb * self )
{
struct sk_buff * skb , * frag ;
int n = 0 ; /* Fragment index */
IRDA_ASSERT ( self ! = NULL , return NULL ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return NULL ; ) ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 2 , " %s(), self->rx_sdu_size=%d \n " , __func__ ,
2005-04-17 02:20:36 +04:00
self - > rx_sdu_size ) ;
skb = dev_alloc_skb ( TTP_HEADER + self - > rx_sdu_size ) ;
if ( ! skb )
return NULL ;
/*
* Need to reserve space for TTP header in case this skb needs to
* be requeued in case delivery failes
*/
skb_reserve ( skb , TTP_HEADER ) ;
skb_put ( skb , self - > rx_sdu_size ) ;
/*
* Copy all fragments to a new buffer
*/
while ( ( frag = skb_dequeue ( & self - > rx_fragments ) ) ! = NULL ) {
2007-03-31 18:55:19 +04:00
skb_copy_to_linear_data_offset ( skb , n , frag - > data , frag - > len ) ;
2005-04-17 02:20:36 +04:00
n + = frag - > len ;
dev_kfree_skb ( frag ) ;
}
IRDA_DEBUG ( 2 ,
" %s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d \n " ,
2008-03-06 07:47:47 +03:00
__func__ , n , self - > rx_sdu_size , self - > rx_max_sdu_size ) ;
2005-04-17 02:20:36 +04:00
/* Note : irttp_run_rx_queue() calculate self->rx_sdu_size
* by summing the size of all fragments , so we should always
* have n = = self - > rx_sdu_size , except in cases where we
* droped the last fragment ( when self - > rx_sdu_size exceed
* self - > rx_max_sdu_size ) , where n < self - > rx_sdu_size .
* Jean II */
IRDA_ASSERT ( n < = self - > rx_sdu_size , n = self - > rx_sdu_size ; ) ;
/* Set the new length */
skb_trim ( skb , n ) ;
self - > rx_sdu_size = 0 ;
return skb ;
}
/*
* Function irttp_fragment_skb ( skb )
*
* Fragments a frame and queues all the fragments for transmission
*
*/
static inline void irttp_fragment_skb ( struct tsap_cb * self ,
struct sk_buff * skb )
{
struct sk_buff * frag ;
__u8 * frame ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 2 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
IRDA_ASSERT ( skb ! = NULL , return ; ) ;
/*
* Split frame into a number of segments
*/
while ( skb - > len > self - > max_seg_size ) {
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 2 , " %s(), fragmenting ... \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Make new segment */
2006-07-22 01:50:41 +04:00
frag = alloc_skb ( self - > max_seg_size + self - > max_header_size ,
GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! frag )
return ;
skb_reserve ( frag , self - > max_header_size ) ;
/* Copy data from the original skb into this fragment. */
2007-03-28 01:55:52 +04:00
skb_copy_from_linear_data ( skb , skb_put ( frag , self - > max_seg_size ) ,
self - > max_seg_size ) ;
2005-04-17 02:20:36 +04:00
/* Insert TTP header, with the more bit set */
frame = skb_push ( frag , TTP_HEADER ) ;
frame [ 0 ] = TTP_MORE ;
/* Hide the copied data from the original skb */
skb_pull ( skb , self - > max_seg_size ) ;
/* Queue fragment */
skb_queue_tail ( & self - > tx_queue , frag ) ;
}
/* Queue what is left of the original skb */
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 2 , " %s(), queuing last segment \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
frame = skb_push ( skb , TTP_HEADER ) ;
frame [ 0 ] = 0x00 ; /* Clear more bit */
/* Queue fragment */
skb_queue_tail ( & self - > tx_queue , skb ) ;
}
/*
* Function irttp_param_max_sdu_size ( self , param )
*
* Handle the MaxSduSize parameter in the connect frames , this function
* will be called both when this parameter needs to be inserted into , and
* extracted from the connect frames
*/
static int irttp_param_max_sdu_size ( void * instance , irda_param_t * param ,
int get )
{
struct tsap_cb * self ;
self = ( struct tsap_cb * ) instance ;
IRDA_ASSERT ( self ! = NULL , return - 1 ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return - 1 ; ) ;
if ( get )
param - > pv . i = self - > tx_max_sdu_size ;
else
self - > tx_max_sdu_size = param - > pv . i ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 1 , " %s(), MaxSduSize=%d \n " , __func__ , param - > pv . i ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*************************** CLIENT CALLS ***************************/
/************************** LMP CALLBACKS **************************/
/* Everything is happily mixed up. Waiting for next clean up - Jean II */
2007-07-03 09:56:57 +04:00
/*
* Initialization , that has to be done on new tsap
* instance allocation and on duplication
*/
static void irttp_init_tsap ( struct tsap_cb * tsap )
{
spin_lock_init ( & tsap - > lock ) ;
init_timer ( & tsap - > todo_timer ) ;
skb_queue_head_init ( & tsap - > rx_queue ) ;
skb_queue_head_init ( & tsap - > tx_queue ) ;
skb_queue_head_init ( & tsap - > rx_fragments ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Function irttp_open_tsap ( stsap , notify )
*
* Create TSAP connection endpoint ,
*/
struct tsap_cb * irttp_open_tsap ( __u8 stsap_sel , int credit , notify_t * notify )
{
struct tsap_cb * self ;
struct lsap_cb * lsap ;
notify_t ttp_notify ;
IRDA_ASSERT ( irttp - > magic = = TTP_MAGIC , return NULL ; ) ;
/* The IrLMP spec (IrLMP 1.1 p10) says that we have the right to
* use only 0x01 - 0x6F . Of course , we can use LSAP_ANY as well .
* JeanII */
if ( ( stsap_sel ! = LSAP_ANY ) & &
( ( stsap_sel < 0x01 ) | | ( stsap_sel > = 0x70 ) ) ) {
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 0 , " %s(), invalid tsap! \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2006-07-22 01:51:30 +04:00
self = kzalloc ( sizeof ( struct tsap_cb ) , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( self = = NULL ) {
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 0 , " %s(), unable to kmalloc! \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2007-07-03 09:56:57 +04:00
/* Initialize internal objects */
irttp_init_tsap ( self ) ;
2005-04-17 02:20:36 +04:00
/* Initialise todo timer */
self - > todo_timer . data = ( unsigned long ) self ;
self - > todo_timer . function = & irttp_todo_expired ;
/* Initialize callbacks for IrLMP to use */
irda_notify_init ( & ttp_notify ) ;
ttp_notify . connect_confirm = irttp_connect_confirm ;
ttp_notify . connect_indication = irttp_connect_indication ;
ttp_notify . disconnect_indication = irttp_disconnect_indication ;
ttp_notify . data_indication = irttp_data_indication ;
ttp_notify . udata_indication = irttp_udata_indication ;
ttp_notify . flow_indication = irttp_flow_indication ;
if ( notify - > status_indication ! = NULL )
ttp_notify . status_indication = irttp_status_indication ;
ttp_notify . instance = self ;
strncpy ( ttp_notify . name , notify - > name , NOTIFY_MAX_NAME ) ;
self - > magic = TTP_TSAP_MAGIC ;
self - > connected = FALSE ;
/*
* Create LSAP at IrLMP layer
*/
lsap = irlmp_open_lsap ( stsap_sel , & ttp_notify , 0 ) ;
if ( lsap = = NULL ) {
2008-03-06 07:47:47 +03:00
IRDA_WARNING ( " %s: unable to allocate LSAP!! \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
/*
* If user specified LSAP_ANY as source TSAP selector , then IrLMP
* will replace it with whatever source selector which is free , so
* the stsap_sel we have might not be valid anymore
*/
self - > stsap_sel = lsap - > slsap_sel ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s(), stsap_sel=%02x \n " , __func__ , self - > stsap_sel ) ;
2005-04-17 02:20:36 +04:00
self - > notify = * notify ;
self - > lsap = lsap ;
hashbin_insert ( irttp - > tsaps , ( irda_queue_t * ) self , ( long ) self , NULL ) ;
if ( credit > TTP_RX_MAX_CREDIT )
self - > initial_credit = TTP_RX_MAX_CREDIT ;
else
self - > initial_credit = credit ;
return self ;
}
EXPORT_SYMBOL ( irttp_open_tsap ) ;
/*
* Function irttp_close ( handle )
*
* Remove an instance of a TSAP . This function should only deal with the
* deallocation of the TSAP , and resetting of the TSAPs values ;
*
*/
static void __irttp_close_tsap ( struct tsap_cb * self )
{
/* First make sure we're connected. */
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
irttp_flush_queues ( self ) ;
del_timer ( & self - > todo_timer ) ;
/* This one won't be cleaned up if we are disconnect_pend + close_pend
* and we receive a disconnect_indication */
if ( self - > disconnect_skb )
dev_kfree_skb ( self - > disconnect_skb ) ;
self - > connected = FALSE ;
self - > magic = ~ TTP_TSAP_MAGIC ;
kfree ( self ) ;
}
/*
* Function irttp_close ( self )
*
* Remove TSAP from list of all TSAPs and then deallocate all resources
* associated with this TSAP
*
* Note : because we * free * the tsap structure , it is the responsibility
* of the caller to make sure we are called only once and to deal with
* possible race conditions . - Jean II
*/
int irttp_close_tsap ( struct tsap_cb * self )
{
struct tsap_cb * tsap ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
IRDA_ASSERT ( self ! = NULL , return - 1 ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return - 1 ; ) ;
/* Make sure tsap has been disconnected */
if ( self - > connected ) {
/* Check if disconnect is not pending */
if ( ! test_bit ( 0 , & self - > disconnect_pend ) ) {
IRDA_WARNING ( " %s: TSAP still connected! \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
irttp_disconnect_request ( self , NULL , P_NORMAL ) ;
}
self - > close_pend = TRUE ;
irttp_start_todo_timer ( self , HZ / 10 ) ;
return 0 ; /* Will be back! */
}
tsap = hashbin_remove ( irttp - > tsaps , ( long ) self , NULL ) ;
IRDA_ASSERT ( tsap = = self , return - 1 ; ) ;
/* Close corresponding LSAP */
if ( self - > lsap ) {
irlmp_close_lsap ( self - > lsap ) ;
self - > lsap = NULL ;
}
__irttp_close_tsap ( self ) ;
return 0 ;
}
EXPORT_SYMBOL ( irttp_close_tsap ) ;
/*
* Function irttp_udata_request ( self , skb )
*
* Send unreliable data on this TSAP
*
*/
int irttp_udata_request ( struct tsap_cb * self , struct sk_buff * skb )
{
IRDA_ASSERT ( self ! = NULL , return - 1 ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return - 1 ; ) ;
IRDA_ASSERT ( skb ! = NULL , return - 1 ; ) ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Check that nothing bad happens */
if ( ( skb - > len = = 0 ) | | ( ! self - > connected ) ) {
IRDA_DEBUG ( 1 , " %s(), No data, or not connected \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
goto err ;
}
if ( skb - > len > self - > max_seg_size ) {
2007-04-21 09:12:48 +04:00
IRDA_DEBUG ( 1 , " %s(), UData is too large for IrLAP! \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
goto err ;
}
irlmp_udata_request ( self - > lsap , skb ) ;
self - > stats . tx_packets + + ;
return 0 ;
err :
dev_kfree_skb ( skb ) ;
return - 1 ;
}
EXPORT_SYMBOL ( irttp_udata_request ) ;
/*
* Function irttp_data_request ( handle , skb )
*
* Queue frame for transmission . If SAR is enabled , fragement the frame
* and queue the fragments for transmission
*/
int irttp_data_request ( struct tsap_cb * self , struct sk_buff * skb )
{
__u8 * frame ;
int ret ;
IRDA_ASSERT ( self ! = NULL , return - 1 ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return - 1 ; ) ;
IRDA_ASSERT ( skb ! = NULL , return - 1 ; ) ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 2 , " %s() : queue len = %d \n " , __func__ ,
2005-04-17 02:20:36 +04:00
skb_queue_len ( & self - > tx_queue ) ) ;
/* Check that nothing bad happens */
if ( ( skb - > len = = 0 ) | | ( ! self - > connected ) ) {
2008-03-06 07:47:47 +03:00
IRDA_WARNING ( " %s: No data, or not connected \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
ret = - ENOTCONN ;
goto err ;
}
/*
* Check if SAR is disabled , and the frame is larger than what fits
* inside an IrLAP frame
*/
if ( ( self - > tx_max_sdu_size = = 0 ) & & ( skb - > len > self - > max_seg_size ) ) {
2007-04-21 09:12:48 +04:00
IRDA_ERROR ( " %s: SAR disabled, and data is too large for IrLAP! \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
ret = - EMSGSIZE ;
goto err ;
}
/*
* Check if SAR is enabled , and the frame is larger than the
* TxMaxSduSize
*/
if ( ( self - > tx_max_sdu_size ! = 0 ) & &
( self - > tx_max_sdu_size ! = TTP_SAR_UNBOUND ) & &
( skb - > len > self - > tx_max_sdu_size ) )
{
IRDA_ERROR ( " %s: SAR enabled, but data is larger than TxMaxSduSize! \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
ret = - EMSGSIZE ;
goto err ;
}
/*
* Check if transmit queue is full
*/
if ( skb_queue_len ( & self - > tx_queue ) > = TTP_TX_MAX_QUEUE ) {
/*
* Give it a chance to empty itself
*/
irttp_run_tx_queue ( self ) ;
/* Drop packet. This error code should trigger the caller
* to resend the data in the client code - Jean II */
ret = - ENOBUFS ;
goto err ;
}
/* Queue frame, or queue frame segments */
if ( ( self - > tx_max_sdu_size = = 0 ) | | ( skb - > len < self - > max_seg_size ) ) {
/* Queue frame */
IRDA_ASSERT ( skb_headroom ( skb ) > = TTP_HEADER , return - 1 ; ) ;
frame = skb_push ( skb , TTP_HEADER ) ;
frame [ 0 ] = 0x00 ; /* Clear more bit */
skb_queue_tail ( & self - > tx_queue , skb ) ;
} else {
/*
* Fragment the frame , this function will also queue the
* fragments , we don ' t care about the fact the transmit
* queue may be overfilled by all the segments for a little
* while
*/
irttp_fragment_skb ( self , skb ) ;
}
/* Check if we can accept more data from client */
if ( ( ! self - > tx_sdu_busy ) & &
( skb_queue_len ( & self - > tx_queue ) > TTP_TX_HIGH_THRESHOLD ) ) {
/* Tx queue filling up, so stop client. */
if ( self - > notify . flow_indication ) {
self - > notify . flow_indication ( self - > notify . instance ,
self , FLOW_STOP ) ;
}
/* self->tx_sdu_busy is the state of the client.
* Update state after notifying client to avoid
* race condition with irttp_flow_indication ( ) .
* If the queue empty itself after our test but before
* we set the flag , we will fix ourselves below in
* irttp_run_tx_queue ( ) .
* Jean II */
self - > tx_sdu_busy = TRUE ;
}
/* Try to make some progress */
irttp_run_tx_queue ( self ) ;
return 0 ;
err :
dev_kfree_skb ( skb ) ;
return ret ;
}
EXPORT_SYMBOL ( irttp_data_request ) ;
/*
* Function irttp_run_tx_queue ( self )
*
* Transmit packets queued for transmission ( if possible )
*
*/
static void irttp_run_tx_queue ( struct tsap_cb * self )
{
struct sk_buff * skb ;
unsigned long flags ;
int n ;
IRDA_DEBUG ( 2 , " %s() : send_credit = %d, queue_len = %d \n " ,
2008-03-06 07:47:47 +03:00
__func__ ,
2005-04-17 02:20:36 +04:00
self - > send_credit , skb_queue_len ( & self - > tx_queue ) ) ;
/* Get exclusive access to the tx queue, otherwise don't touch it */
if ( irda_lock ( & self - > tx_queue_lock ) = = FALSE )
return ;
/* Try to send out frames as long as we have credits
* and as long as LAP is not full . If LAP is full , it will
* poll us through irttp_flow_indication ( ) - Jean II */
while ( ( self - > send_credit > 0 ) & &
( ! irlmp_lap_tx_queue_full ( self - > lsap ) ) & &
( skb = skb_dequeue ( & self - > tx_queue ) ) )
{
/*
* Since we can transmit and receive frames concurrently ,
* the code below is a critical region and we must assure that
* nobody messes with the credits while we update them .
*/
spin_lock_irqsave ( & self - > lock , flags ) ;
n = self - > avail_credit ;
self - > avail_credit = 0 ;
/* Only room for 127 credits in frame */
if ( n > 127 ) {
self - > avail_credit = n - 127 ;
n = 127 ;
}
self - > remote_credit + = n ;
self - > send_credit - - ;
spin_unlock_irqrestore ( & self - > lock , flags ) ;
/*
* More bit must be set by the data_request ( ) or fragment ( )
* functions
*/
skb - > data [ 0 ] | = ( n & 0x7f ) ;
/* Detach from socket.
* The current skb has a reference to the socket that sent
* it ( skb - > sk ) . When we pass it to IrLMP , the skb will be
* stored in in IrLAP ( self - > wx_list ) . When we are within
* IrLAP , we lose the notion of socket , so we should not
* have a reference to a socket . So , we drop it here .
*
* Why does it matter ?
* When the skb is freed ( kfree_skb ) , if it is associated
* with a socket , it release buffer space on the socket
* ( through sock_wfree ( ) and sock_def_write_space ( ) ) .
* If the socket no longer exist , we may crash . Hard .
* When we close a socket , we make sure that associated packets
* in IrTTP are freed . However , we have no way to cancel
* the packet that we have passed to IrLAP . So , if a packet
* remains in IrLAP ( retry on the link or else ) after we
* close the socket , we are dead !
* Jean II */
if ( skb - > sk ! = NULL ) {
/* IrSOCK application, IrOBEX, ... */
skb_orphan ( skb ) ;
}
/* IrCOMM over IrTTP, IrLAN, ... */
/* Pass the skb to IrLMP - done */
irlmp_data_request ( self - > lsap , skb ) ;
self - > stats . tx_packets + + ;
}
/* Check if we can accept more frames from client.
* We don ' t want to wait until the todo timer to do that , and we
* can ' t use tasklets ( grr . . . ) , so we are obliged to give control
* to client . That ' s ok , this test will be true not too often
* ( max once per LAP window ) and we are called from places
* where we can spend a bit of time doing stuff . - Jean II */
if ( ( self - > tx_sdu_busy ) & &
( skb_queue_len ( & self - > tx_queue ) < TTP_TX_LOW_THRESHOLD ) & &
( ! self - > close_pend ) )
{
if ( self - > notify . flow_indication )
self - > notify . flow_indication ( self - > notify . instance ,
self , FLOW_START ) ;
/* self->tx_sdu_busy is the state of the client.
* We don ' t really have a race here , but it ' s always safer
* to update our state after the client - Jean II */
self - > tx_sdu_busy = FALSE ;
}
/* Reset lock */
self - > tx_queue_lock = 0 ;
}
/*
* Function irttp_give_credit ( self )
*
* Send a dataless flowdata TTP - PDU and give available credit to peer
* TSAP
*/
static inline void irttp_give_credit ( struct tsap_cb * self )
{
struct sk_buff * tx_skb = NULL ;
unsigned long flags ;
int n ;
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
IRDA_DEBUG ( 4 , " %s() send=%d,avail=%d,remote=%d \n " ,
2008-03-06 07:47:47 +03:00
__func__ ,
2005-04-17 02:20:36 +04:00
self - > send_credit , self - > avail_credit , self - > remote_credit ) ;
/* Give credit to peer */
2006-09-28 07:06:44 +04:00
tx_skb = alloc_skb ( TTP_MAX_HEADER , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! tx_skb )
return ;
/* Reserve space for LMP, and LAP header */
2006-09-28 07:06:44 +04:00
skb_reserve ( tx_skb , LMP_MAX_HEADER ) ;
2005-04-17 02:20:36 +04:00
/*
* Since we can transmit and receive frames concurrently ,
* the code below is a critical region and we must assure that
* nobody messes with the credits while we update them .
*/
spin_lock_irqsave ( & self - > lock , flags ) ;
n = self - > avail_credit ;
self - > avail_credit = 0 ;
/* Only space for 127 credits in frame */
if ( n > 127 ) {
self - > avail_credit = n - 127 ;
n = 127 ;
}
self - > remote_credit + = n ;
spin_unlock_irqrestore ( & self - > lock , flags ) ;
skb_put ( tx_skb , 1 ) ;
tx_skb - > data [ 0 ] = ( __u8 ) ( n & 0x7f ) ;
irlmp_data_request ( self - > lsap , tx_skb ) ;
self - > stats . tx_packets + + ;
}
/*
* Function irttp_udata_indication ( instance , sap , skb )
*
* Received some unit - data ( unreliable )
*
*/
static int irttp_udata_indication ( void * instance , void * sap ,
struct sk_buff * skb )
{
struct tsap_cb * self ;
int err ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
self = ( struct tsap_cb * ) instance ;
IRDA_ASSERT ( self ! = NULL , return - 1 ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return - 1 ; ) ;
IRDA_ASSERT ( skb ! = NULL , return - 1 ; ) ;
self - > stats . rx_packets + + ;
/* Just pass data to layer above */
if ( self - > notify . udata_indication ) {
err = self - > notify . udata_indication ( self - > notify . instance ,
self , skb ) ;
/* Same comment as in irttp_do_data_indication() */
2007-02-09 17:24:53 +03:00
if ( ! err )
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Either no handler, or handler returns an error */
dev_kfree_skb ( skb ) ;
return 0 ;
}
/*
* Function irttp_data_indication ( instance , sap , skb )
*
* Receive segment from IrLMP .
*
*/
static int irttp_data_indication ( void * instance , void * sap ,
struct sk_buff * skb )
{
struct tsap_cb * self ;
unsigned long flags ;
int n ;
self = ( struct tsap_cb * ) instance ;
n = skb - > data [ 0 ] & 0x7f ; /* Extract the credits */
self - > stats . rx_packets + + ;
/* Deal with inbound credit
* Since we can transmit and receive frames concurrently ,
* the code below is a critical region and we must assure that
* nobody messes with the credits while we update them .
*/
spin_lock_irqsave ( & self - > lock , flags ) ;
self - > send_credit + = n ;
if ( skb - > len > 1 )
self - > remote_credit - - ;
spin_unlock_irqrestore ( & self - > lock , flags ) ;
/*
* Data or dataless packet ? Dataless frames contains only the
* TTP_HEADER .
*/
if ( skb - > len > 1 ) {
/*
* We don ' t remove the TTP header , since we must preserve the
* more bit , so the defragment routing knows what to do
*/
skb_queue_tail ( & self - > rx_queue , skb ) ;
} else {
/* Dataless flowdata TTP-PDU */
dev_kfree_skb ( skb ) ;
}
/* Push data to the higher layer.
* We do it synchronously because running the todo timer for each
* receive packet would be too much overhead and latency .
* By passing control to the higher layer , we run the risk that
* it may take time or grab a lock . Most often , the higher layer
* will only put packet in a queue .
* Anyway , packets are only dripping through the IrDA , so we can
* have time before the next packet .
* Further , we are run from NET_BH , so the worse that can happen is
* us missing the optimal time to send back the PF bit in LAP .
* Jean II */
irttp_run_rx_queue ( self ) ;
/* We now give credits to peer in irttp_run_rx_queue().
* We need to send credit * NOW * , otherwise we are going
* to miss the next Tx window . The todo timer may take
* a while before it ' s run . . . - Jean II */
/*
* If the peer device has given us some credits and we didn ' t have
2007-02-09 17:24:53 +03:00
* anyone from before , then we need to shedule the tx queue .
2005-04-17 02:20:36 +04:00
* We need to do that because our Tx have stopped ( so we may not
* get any LAP flow indication ) and the user may be stopped as
* well . - Jean II
*/
if ( self - > send_credit = = n ) {
/* Restart pushing stuff to LAP */
irttp_run_tx_queue ( self ) ;
/* Note : we don't want to schedule the todo timer
* because it has horrible latency . No tasklets
* because the tasklet API is broken . - Jean II */
}
return 0 ;
}
/*
* Function irttp_status_indication ( self , reason )
*
* Status_indication , just pass to the higher layer . . .
*
*/
static void irttp_status_indication ( void * instance ,
LINK_STATUS link , LOCK_STATUS lock )
{
struct tsap_cb * self ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
self = ( struct tsap_cb * ) instance ;
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
/* Check if client has already closed the TSAP and gone away */
if ( self - > close_pend )
return ;
/*
* Inform service user if he has requested it
*/
if ( self - > notify . status_indication ! = NULL )
self - > notify . status_indication ( self - > notify . instance ,
link , lock ) ;
else
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 2 , " %s(), no handler \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Function irttp_flow_indication ( self , reason )
*
* Flow_indication : IrLAP tells us to send more data .
*
*/
static void irttp_flow_indication ( void * instance , void * sap , LOCAL_FLOW flow )
{
struct tsap_cb * self ;
self = ( struct tsap_cb * ) instance ;
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s(instance=%p) \n " , __func__ , self ) ;
2005-04-17 02:20:36 +04:00
/* We are "polled" directly from LAP, and the LAP want to fill
* its Tx window . We want to do our best to send it data , so that
* we maximise the window . On the other hand , we want to limit the
* amount of work here so that LAP doesn ' t hang forever waiting
* for packets . - Jean II */
/* Try to send some packets. Currently, LAP calls us every time
* there is one free slot , so we will send only one packet .
* This allow the scheduler to do its round robin - Jean II */
irttp_run_tx_queue ( self ) ;
/* Note regarding the interraction with higher layer.
* irttp_run_tx_queue ( ) may call the client when its queue
* start to empty , via notify . flow_indication ( ) . Initially .
* I wanted this to happen in a tasklet , to avoid client
* grabbing the CPU , but we can ' t use tasklets safely . And timer
* is definitely too slow .
* This will happen only once per LAP window , and usually at
* the third packet ( unless window is smaller ) . LAP is still
* doing mtt and sending first packet so it ' s sort of OK
* to do that . Jean II */
/* If we need to send disconnect. try to do it now */
if ( self - > disconnect_pend )
irttp_start_todo_timer ( self , 0 ) ;
}
/*
* Function irttp_flow_request ( self , command )
*
* This function could be used by the upper layers to tell IrTTP to stop
* delivering frames if the receive queues are starting to get full , or
* to tell IrTTP to start delivering frames again .
*/
void irttp_flow_request ( struct tsap_cb * self , LOCAL_FLOW flow )
{
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 1 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
switch ( flow ) {
case FLOW_STOP :
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 1 , " %s(), flow stop \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
self - > rx_sdu_busy = TRUE ;
break ;
case FLOW_START :
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 1 , " %s(), flow start \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
self - > rx_sdu_busy = FALSE ;
/* Client say he can accept more data, try to free our
* queues ASAP - Jean II */
irttp_run_rx_queue ( self ) ;
break ;
default :
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 1 , " %s(), Unknown flow command! \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
}
EXPORT_SYMBOL ( irttp_flow_request ) ;
/*
* Function irttp_connect_request ( self , dtsap_sel , daddr , qos )
*
* Try to connect to remote destination TSAP selector
*
*/
int irttp_connect_request ( struct tsap_cb * self , __u8 dtsap_sel ,
__u32 saddr , __u32 daddr ,
struct qos_info * qos , __u32 max_sdu_size ,
struct sk_buff * userdata )
{
struct sk_buff * tx_skb ;
__u8 * frame ;
__u8 n ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s(), max_sdu_size=%d \n " , __func__ , max_sdu_size ) ;
2005-04-17 02:20:36 +04:00
IRDA_ASSERT ( self ! = NULL , return - EBADR ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return - EBADR ; ) ;
if ( self - > connected ) {
if ( userdata )
dev_kfree_skb ( userdata ) ;
return - EISCONN ;
}
/* Any userdata supplied? */
if ( userdata = = NULL ) {
2006-09-28 07:06:44 +04:00
tx_skb = alloc_skb ( TTP_MAX_HEADER + TTP_SAR_HEADER ,
GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! tx_skb )
return - ENOMEM ;
/* Reserve space for MUX_CONTROL and LAP header */
2006-12-07 07:08:45 +03:00
skb_reserve ( tx_skb , TTP_MAX_HEADER + TTP_SAR_HEADER ) ;
2005-04-17 02:20:36 +04:00
} else {
tx_skb = userdata ;
/*
* Check that the client has reserved enough space for
* headers
*/
IRDA_ASSERT ( skb_headroom ( userdata ) > = TTP_MAX_HEADER ,
{ dev_kfree_skb ( userdata ) ; return - 1 ; } ) ;
}
/* Initialize connection parameters */
self - > connected = FALSE ;
self - > avail_credit = 0 ;
self - > rx_max_sdu_size = max_sdu_size ;
self - > rx_sdu_size = 0 ;
self - > rx_sdu_busy = FALSE ;
self - > dtsap_sel = dtsap_sel ;
n = self - > initial_credit ;
self - > remote_credit = 0 ;
self - > send_credit = 0 ;
/*
* Give away max 127 credits for now
*/
if ( n > 127 ) {
self - > avail_credit = n - 127 ;
n = 127 ;
}
self - > remote_credit = n ;
/* SAR enabled? */
if ( max_sdu_size > 0 ) {
IRDA_ASSERT ( skb_headroom ( tx_skb ) > = ( TTP_MAX_HEADER + TTP_SAR_HEADER ) ,
{ dev_kfree_skb ( tx_skb ) ; return - 1 ; } ) ;
/* Insert SAR parameters */
frame = skb_push ( tx_skb , TTP_HEADER + TTP_SAR_HEADER ) ;
frame [ 0 ] = TTP_PARAMETERS | n ;
frame [ 1 ] = 0x04 ; /* Length */
frame [ 2 ] = 0x01 ; /* MaxSduSize */
frame [ 3 ] = 0x02 ; /* Value length */
put_unaligned ( cpu_to_be16 ( ( __u16 ) max_sdu_size ) ,
2006-11-15 07:47:46 +03:00
( __be16 * ) ( frame + 4 ) ) ;
2005-04-17 02:20:36 +04:00
} else {
/* Insert plain TTP header */
frame = skb_push ( tx_skb , TTP_HEADER ) ;
/* Insert initial credit in frame */
frame [ 0 ] = n & 0x7f ;
}
/* Connect with IrLMP. No QoS parameters for now */
return irlmp_connect_request ( self - > lsap , dtsap_sel , saddr , daddr , qos ,
tx_skb ) ;
}
EXPORT_SYMBOL ( irttp_connect_request ) ;
/*
* Function irttp_connect_confirm ( handle , qos , skb )
*
* Sevice user confirms TSAP connection with peer .
*
*/
static void irttp_connect_confirm ( void * instance , void * sap ,
struct qos_info * qos , __u32 max_seg_size ,
__u8 max_header_size , struct sk_buff * skb )
{
struct tsap_cb * self ;
int parameters ;
int ret ;
__u8 plen ;
__u8 n ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
self = ( struct tsap_cb * ) instance ;
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
IRDA_ASSERT ( skb ! = NULL , return ; ) ;
self - > max_seg_size = max_seg_size - TTP_HEADER ;
self - > max_header_size = max_header_size + TTP_HEADER ;
/*
* Check if we have got some QoS parameters back ! This should be the
* negotiated QoS for the link .
*/
if ( qos ) {
IRDA_DEBUG ( 4 , " IrTTP, Negotiated BAUD_RATE: %02x \n " ,
qos - > baud_rate . bits ) ;
IRDA_DEBUG ( 4 , " IrTTP, Negotiated BAUD_RATE: %d bps. \n " ,
qos - > baud_rate . value ) ;
}
n = skb - > data [ 0 ] & 0x7f ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s(), Initial send_credit=%d \n " , __func__ , n ) ;
2005-04-17 02:20:36 +04:00
self - > send_credit = n ;
self - > tx_max_sdu_size = 0 ;
self - > connected = TRUE ;
parameters = skb - > data [ 0 ] & 0x80 ;
IRDA_ASSERT ( skb - > len > = TTP_HEADER , return ; ) ;
skb_pull ( skb , TTP_HEADER ) ;
if ( parameters ) {
plen = skb - > data [ 0 ] ;
ret = irda_param_extract_all ( self , skb - > data + 1 ,
IRDA_MIN ( skb - > len - 1 , plen ) ,
& param_info ) ;
/* Any errors in the parameter list? */
if ( ret < 0 ) {
IRDA_WARNING ( " %s: error extracting parameters \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
dev_kfree_skb ( skb ) ;
/* Do not accept this connection attempt */
return ;
}
/* Remove parameters */
skb_pull ( skb , IRDA_MIN ( skb - > len , plen + 1 ) ) ;
}
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s() send=%d,avail=%d,remote=%d \n " , __func__ ,
2005-04-17 02:20:36 +04:00
self - > send_credit , self - > avail_credit , self - > remote_credit ) ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 2 , " %s(), MaxSduSize=%d \n " , __func__ ,
2005-04-17 02:20:36 +04:00
self - > tx_max_sdu_size ) ;
if ( self - > notify . connect_confirm ) {
self - > notify . connect_confirm ( self - > notify . instance , self , qos ,
self - > tx_max_sdu_size ,
self - > max_header_size , skb ) ;
} else
dev_kfree_skb ( skb ) ;
}
/*
* Function irttp_connect_indication ( handle , skb )
*
* Some other device is connecting to this TSAP
*
*/
void irttp_connect_indication ( void * instance , void * sap , struct qos_info * qos ,
__u32 max_seg_size , __u8 max_header_size ,
struct sk_buff * skb )
{
struct tsap_cb * self ;
struct lsap_cb * lsap ;
int parameters ;
int ret ;
__u8 plen ;
__u8 n ;
self = ( struct tsap_cb * ) instance ;
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
IRDA_ASSERT ( skb ! = NULL , return ; ) ;
lsap = ( struct lsap_cb * ) sap ;
self - > max_seg_size = max_seg_size - TTP_HEADER ;
self - > max_header_size = max_header_size + TTP_HEADER ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s(), TSAP sel=%02x \n " , __func__ , self - > stsap_sel ) ;
2005-04-17 02:20:36 +04:00
/* Need to update dtsap_sel if its equal to LSAP_ANY */
self - > dtsap_sel = lsap - > dlsap_sel ;
n = skb - > data [ 0 ] & 0x7f ;
self - > send_credit = n ;
self - > tx_max_sdu_size = 0 ;
parameters = skb - > data [ 0 ] & 0x80 ;
IRDA_ASSERT ( skb - > len > = TTP_HEADER , return ; ) ;
skb_pull ( skb , TTP_HEADER ) ;
if ( parameters ) {
plen = skb - > data [ 0 ] ;
ret = irda_param_extract_all ( self , skb - > data + 1 ,
IRDA_MIN ( skb - > len - 1 , plen ) ,
& param_info ) ;
/* Any errors in the parameter list? */
if ( ret < 0 ) {
IRDA_WARNING ( " %s: error extracting parameters \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
dev_kfree_skb ( skb ) ;
/* Do not accept this connection attempt */
return ;
}
/* Remove parameters */
skb_pull ( skb , IRDA_MIN ( skb - > len , plen + 1 ) ) ;
}
if ( self - > notify . connect_indication ) {
self - > notify . connect_indication ( self - > notify . instance , self ,
qos , self - > tx_max_sdu_size ,
self - > max_header_size , skb ) ;
} else
dev_kfree_skb ( skb ) ;
}
/*
* Function irttp_connect_response ( handle , userdata )
*
* Service user is accepting the connection , just pass it down to
* IrLMP !
*
*/
int irttp_connect_response ( struct tsap_cb * self , __u32 max_sdu_size ,
struct sk_buff * userdata )
{
struct sk_buff * tx_skb ;
__u8 * frame ;
int ret ;
__u8 n ;
IRDA_ASSERT ( self ! = NULL , return - 1 ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return - 1 ; ) ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s(), Source TSAP selector=%02x \n " , __func__ ,
2005-04-17 02:20:36 +04:00
self - > stsap_sel ) ;
/* Any userdata supplied? */
if ( userdata = = NULL ) {
2006-09-28 07:06:44 +04:00
tx_skb = alloc_skb ( TTP_MAX_HEADER + TTP_SAR_HEADER ,
GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! tx_skb )
return - ENOMEM ;
/* Reserve space for MUX_CONTROL and LAP header */
2006-12-07 07:08:45 +03:00
skb_reserve ( tx_skb , TTP_MAX_HEADER + TTP_SAR_HEADER ) ;
2005-04-17 02:20:36 +04:00
} else {
tx_skb = userdata ;
/*
* Check that the client has reserved enough space for
* headers
*/
IRDA_ASSERT ( skb_headroom ( userdata ) > = TTP_MAX_HEADER ,
{ dev_kfree_skb ( userdata ) ; return - 1 ; } ) ;
}
self - > avail_credit = 0 ;
self - > remote_credit = 0 ;
self - > rx_max_sdu_size = max_sdu_size ;
self - > rx_sdu_size = 0 ;
self - > rx_sdu_busy = FALSE ;
n = self - > initial_credit ;
/* Frame has only space for max 127 credits (7 bits) */
if ( n > 127 ) {
self - > avail_credit = n - 127 ;
n = 127 ;
}
self - > remote_credit = n ;
self - > connected = TRUE ;
/* SAR enabled? */
if ( max_sdu_size > 0 ) {
IRDA_ASSERT ( skb_headroom ( tx_skb ) > = ( TTP_MAX_HEADER + TTP_SAR_HEADER ) ,
{ dev_kfree_skb ( tx_skb ) ; return - 1 ; } ) ;
/* Insert TTP header with SAR parameters */
frame = skb_push ( tx_skb , TTP_HEADER + TTP_SAR_HEADER ) ;
frame [ 0 ] = TTP_PARAMETERS | n ;
frame [ 1 ] = 0x04 ; /* Length */
/* irda_param_insert(self, IRTTP_MAX_SDU_SIZE, frame+1, */
/* TTP_SAR_HEADER, ¶m_info) */
frame [ 2 ] = 0x01 ; /* MaxSduSize */
frame [ 3 ] = 0x02 ; /* Value length */
put_unaligned ( cpu_to_be16 ( ( __u16 ) max_sdu_size ) ,
2006-11-15 07:47:46 +03:00
( __be16 * ) ( frame + 4 ) ) ;
2005-04-17 02:20:36 +04:00
} else {
/* Insert TTP header */
frame = skb_push ( tx_skb , TTP_HEADER ) ;
frame [ 0 ] = n & 0x7f ;
}
ret = irlmp_connect_response ( self - > lsap , tx_skb ) ;
return ret ;
}
EXPORT_SYMBOL ( irttp_connect_response ) ;
/*
* Function irttp_dup ( self , instance )
*
* Duplicate TSAP , can be used by servers to confirm a connection on a
* new TSAP so it can keep listening on the old one .
*/
struct tsap_cb * irttp_dup ( struct tsap_cb * orig , void * instance )
{
struct tsap_cb * new ;
unsigned long flags ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 1 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Protect our access to the old tsap instance */
spin_lock_irqsave ( & irttp - > tsaps - > hb_spinlock , flags ) ;
/* Find the old instance */
if ( ! hashbin_find ( irttp - > tsaps , ( long ) orig , NULL ) ) {
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 0 , " %s(), unable to find TSAP \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & irttp - > tsaps - > hb_spinlock , flags ) ;
return NULL ;
}
/* Allocate a new instance */
new = kmalloc ( sizeof ( struct tsap_cb ) , GFP_ATOMIC ) ;
if ( ! new ) {
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 0 , " %s(), unable to kmalloc \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & irttp - > tsaps - > hb_spinlock , flags ) ;
return NULL ;
}
/* Dup */
memcpy ( new , orig , sizeof ( struct tsap_cb ) ) ;
/* We don't need the old instance any more */
spin_unlock_irqrestore ( & irttp - > tsaps - > hb_spinlock , flags ) ;
/* Try to dup the LSAP (may fail if we were too slow) */
new - > lsap = irlmp_dup ( orig - > lsap , new ) ;
if ( ! new - > lsap ) {
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 0 , " %s(), dup failed! \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
kfree ( new ) ;
return NULL ;
}
/* Not everything should be copied */
new - > notify . instance = instance ;
2007-07-03 09:56:57 +04:00
/* Initialize internal objects */
irttp_init_tsap ( new ) ;
2005-04-17 02:20:36 +04:00
/* This is locked */
hashbin_insert ( irttp - > tsaps , ( irda_queue_t * ) new , ( long ) new , NULL ) ;
return new ;
}
EXPORT_SYMBOL ( irttp_dup ) ;
/*
* Function irttp_disconnect_request ( self )
*
* Close this connection please ! If priority is high , the queued data
* segments , if any , will be deallocated first
*
*/
int irttp_disconnect_request ( struct tsap_cb * self , struct sk_buff * userdata ,
int priority )
{
int ret ;
IRDA_ASSERT ( self ! = NULL , return - 1 ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return - 1 ; ) ;
/* Already disconnected? */
if ( ! self - > connected ) {
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s(), already disconnected! \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
if ( userdata )
dev_kfree_skb ( userdata ) ;
return - 1 ;
}
/* Disconnect already pending ?
* We need to use an atomic operation to prevent reentry . This
* function may be called from various context , like user , timer
* for following a disconnect_indication ( ) ( i . e . net_bh ) .
* Jean II */
if ( test_and_set_bit ( 0 , & self - > disconnect_pend ) ) {
IRDA_DEBUG ( 0 , " %s(), disconnect already pending \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
if ( userdata )
dev_kfree_skb ( userdata ) ;
/* Try to make some progress */
irttp_run_tx_queue ( self ) ;
return - 1 ;
}
/*
* Check if there is still data segments in the transmit queue
*/
2005-07-09 01:57:23 +04:00
if ( ! skb_queue_empty ( & self - > tx_queue ) ) {
2005-04-17 02:20:36 +04:00
if ( priority = = P_HIGH ) {
/*
* No need to send the queued data , if we are
* disconnecting right now since the data will
* not have any usable connection to be sent on
*/
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 1 , " %s(): High priority!!() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
irttp_flush_queues ( self ) ;
} else if ( priority = = P_NORMAL ) {
/*
* Must delay disconnect until after all data segments
* have been sent and the tx_queue is empty
*/
/* We'll reuse this one later for the disconnect */
self - > disconnect_skb = userdata ; /* May be NULL */
irttp_run_tx_queue ( self ) ;
irttp_start_todo_timer ( self , HZ / 10 ) ;
return - 1 ;
}
}
/* Note : we don't need to check if self->rx_queue is full and the
* state of self - > rx_sdu_busy because the disconnect response will
* be sent at the LMP level ( so even if the peer has its Tx queue
* full of data ) . - Jean II */
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 1 , " %s(), Disconnecting ... \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
self - > connected = FALSE ;
if ( ! userdata ) {
struct sk_buff * tx_skb ;
2006-09-28 07:06:44 +04:00
tx_skb = alloc_skb ( LMP_MAX_HEADER , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! tx_skb )
return - ENOMEM ;
/*
* Reserve space for MUX and LAP header
*/
2006-09-28 07:06:44 +04:00
skb_reserve ( tx_skb , LMP_MAX_HEADER ) ;
2005-04-17 02:20:36 +04:00
userdata = tx_skb ;
}
ret = irlmp_disconnect_request ( self - > lsap , userdata ) ;
/* The disconnect is no longer pending */
clear_bit ( 0 , & self - > disconnect_pend ) ; /* FALSE */
return ret ;
}
EXPORT_SYMBOL ( irttp_disconnect_request ) ;
/*
* Function irttp_disconnect_indication ( self , reason )
*
* Disconnect indication , TSAP disconnected by peer ?
*
*/
void irttp_disconnect_indication ( void * instance , void * sap , LM_REASON reason ,
struct sk_buff * skb )
{
struct tsap_cb * self ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 4 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
self = ( struct tsap_cb * ) instance ;
IRDA_ASSERT ( self ! = NULL , return ; ) ;
IRDA_ASSERT ( self - > magic = = TTP_TSAP_MAGIC , return ; ) ;
/* Prevent higher layer to send more data */
self - > connected = FALSE ;
/* Check if client has already tried to close the TSAP */
if ( self - > close_pend ) {
/* In this case, the higher layer is probably gone. Don't
* bother it and clean up the remains - Jean II */
if ( skb )
dev_kfree_skb ( skb ) ;
irttp_close_tsap ( self ) ;
return ;
}
/* If we are here, we assume that is the higher layer is still
* waiting for the disconnect notification and able to process it ,
* even if he tried to disconnect . Otherwise , it would have already
* attempted to close the tsap and self - > close_pend would be TRUE .
* Jean II */
/* No need to notify the client if has already tried to disconnect */
if ( self - > notify . disconnect_indication )
self - > notify . disconnect_indication ( self - > notify . instance , self ,
reason , skb ) ;
else
if ( skb )
dev_kfree_skb ( skb ) ;
}
/*
* Function irttp_do_data_indication ( self , skb )
*
* Try to deliver reassembled skb to layer above , and requeue it if that
* for some reason should fail . We mark rx sdu as busy to apply back
* pressure is necessary .
*/
static void irttp_do_data_indication ( struct tsap_cb * self , struct sk_buff * skb )
{
int err ;
/* Check if client has already closed the TSAP and gone away */
if ( self - > close_pend ) {
dev_kfree_skb ( skb ) ;
return ;
}
err = self - > notify . data_indication ( self - > notify . instance , self , skb ) ;
/* Usually the layer above will notify that it's input queue is
* starting to get filled by using the flow request , but this may
* be difficult , so it can instead just refuse to eat it and just
* give an error back
*/
if ( err ) {
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 0 , " %s() requeueing skb! \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Make sure we take a break */
self - > rx_sdu_busy = TRUE ;
/* Need to push the header in again */
skb_push ( skb , TTP_HEADER ) ;
skb - > data [ 0 ] = 0x00 ; /* Make sure MORE bit is cleared */
/* Put skb back on queue */
skb_queue_head ( & self - > rx_queue , skb ) ;
}
}
/*
* Function irttp_run_rx_queue ( self )
*
* Check if we have any frames to be transmitted , or if we have any
* available credit to give away .
*/
void irttp_run_rx_queue ( struct tsap_cb * self )
{
struct sk_buff * skb ;
int more = 0 ;
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 2 , " %s() send=%d,avail=%d,remote=%d \n " , __func__ ,
2005-04-17 02:20:36 +04:00
self - > send_credit , self - > avail_credit , self - > remote_credit ) ;
/* Get exclusive access to the rx queue, otherwise don't touch it */
if ( irda_lock ( & self - > rx_queue_lock ) = = FALSE )
return ;
/*
* Reassemble all frames in receive queue and deliver them
*/
while ( ! self - > rx_sdu_busy & & ( skb = skb_dequeue ( & self - > rx_queue ) ) ) {
/* This bit will tell us if it's the last fragment or not */
more = skb - > data [ 0 ] & 0x80 ;
/* Remove TTP header */
skb_pull ( skb , TTP_HEADER ) ;
/* Add the length of the remaining data */
self - > rx_sdu_size + = skb - > len ;
/*
* If SAR is disabled , or user has requested no reassembly
* of received fragments then we just deliver them
* immediately . This can be requested by clients that
* implements byte streams without any message boundaries
*/
if ( self - > rx_max_sdu_size = = TTP_SAR_DISABLE ) {
irttp_do_data_indication ( self , skb ) ;
self - > rx_sdu_size = 0 ;
continue ;
}
/* Check if this is a fragment, and not the last fragment */
if ( more ) {
/*
* Queue the fragment if we still are within the
* limits of the maximum size of the rx_sdu
*/
if ( self - > rx_sdu_size < = self - > rx_max_sdu_size ) {
IRDA_DEBUG ( 4 , " %s(), queueing frag \n " ,
2008-03-06 07:47:47 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
skb_queue_tail ( & self - > rx_fragments , skb ) ;
} else {
/* Free the part of the SDU that is too big */
dev_kfree_skb ( skb ) ;
}
continue ;
}
/*
* This is the last fragment , so time to reassemble !
*/
if ( ( self - > rx_sdu_size < = self - > rx_max_sdu_size ) | |
( self - > rx_max_sdu_size = = TTP_SAR_UNBOUND ) )
{
/*
* A little optimizing . Only queue the fragment if
* there are other fragments . Since if this is the
* last and only fragment , there is no need to
* reassemble : - )
*/
if ( ! skb_queue_empty ( & self - > rx_fragments ) ) {
skb_queue_tail ( & self - > rx_fragments ,
skb ) ;
skb = irttp_reassemble_skb ( self ) ;
}
/* Now we can deliver the reassembled skb */
irttp_do_data_indication ( self , skb ) ;
} else {
2008-03-06 07:47:47 +03:00
IRDA_DEBUG ( 1 , " %s(), Truncated frame \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Free the part of the SDU that is too big */
dev_kfree_skb ( skb ) ;
/* Deliver only the valid but truncated part of SDU */
skb = irttp_reassemble_skb ( self ) ;
irttp_do_data_indication ( self , skb ) ;
}
self - > rx_sdu_size = 0 ;
}
/*
* It ' s not trivial to keep track of how many credits are available
* by incrementing at each packet , because delivery may fail
* ( irttp_do_data_indication ( ) may requeue the frame ) and because
* we need to take care of fragmentation .
* We want the other side to send up to initial_credit packets .
* We have some frames in our queues , and we have already allowed it
* to send remote_credit .
* No need to spinlock , write is atomic and self correcting . . .
* Jean II
*/
self - > avail_credit = ( self - > initial_credit -
( self - > remote_credit +
skb_queue_len ( & self - > rx_queue ) +
skb_queue_len ( & self - > rx_fragments ) ) ) ;
/* Do we have too much credits to send to peer ? */
if ( ( self - > remote_credit < = TTP_RX_MIN_CREDIT ) & &
( self - > avail_credit > 0 ) ) {
/* Send explicit credit frame */
irttp_give_credit ( self ) ;
/* Note : do *NOT* check if tx_queue is non-empty, that
* will produce deadlocks . I repeat : send a credit frame
* even if we have something to send in our Tx queue .
* If we have credits , it means that our Tx queue is blocked .
*
* Let ' s suppose the peer can ' t keep up with our Tx . He will
* flow control us by not sending us any credits , and we
* will stop Tx and start accumulating credits here .
* Up to the point where the peer will stop its Tx queue ,
* for lack of credits .
* Let ' s assume the peer application is single threaded .
* It will block on Tx and never consume any Rx buffer .
* Deadlock . Guaranteed . - Jean II
*/
}
/* Reset lock */
self - > rx_queue_lock = 0 ;
}
# ifdef CONFIG_PROC_FS
struct irttp_iter_state {
int id ;
} ;
static void * irttp_seq_start ( struct seq_file * seq , loff_t * pos )
{
struct irttp_iter_state * iter = seq - > private ;
struct tsap_cb * self ;
/* Protect our access to the tsap list */
spin_lock_irq ( & irttp - > tsaps - > hb_spinlock ) ;
iter - > id = 0 ;
2007-02-09 17:24:53 +03:00
for ( self = ( struct tsap_cb * ) hashbin_get_first ( irttp - > tsaps ) ;
2005-04-17 02:20:36 +04:00
self ! = NULL ;
self = ( struct tsap_cb * ) hashbin_get_next ( irttp - > tsaps ) ) {
if ( iter - > id = = * pos )
break ;
+ + iter - > id ;
}
2007-02-09 17:24:53 +03:00
2005-04-17 02:20:36 +04:00
return self ;
}
static void * irttp_seq_next ( struct seq_file * seq , void * v , loff_t * pos )
{
struct irttp_iter_state * iter = seq - > private ;
+ + * pos ;
+ + iter - > id ;
return ( void * ) hashbin_get_next ( irttp - > tsaps ) ;
}
static void irttp_seq_stop ( struct seq_file * seq , void * v )
{
spin_unlock_irq ( & irttp - > tsaps - > hb_spinlock ) ;
}
static int irttp_seq_show ( struct seq_file * seq , void * v )
{
const struct irttp_iter_state * iter = seq - > private ;
const struct tsap_cb * self = v ;
seq_printf ( seq , " TSAP %d, " , iter - > id ) ;
seq_printf ( seq , " stsap_sel: %02x, " ,
self - > stsap_sel ) ;
seq_printf ( seq , " dtsap_sel: %02x \n " ,
self - > dtsap_sel ) ;
seq_printf ( seq , " connected: %s, " ,
self - > connected ? " TRUE " : " FALSE " ) ;
seq_printf ( seq , " avail credit: %d, " ,
self - > avail_credit ) ;
seq_printf ( seq , " remote credit: %d, " ,
self - > remote_credit ) ;
seq_printf ( seq , " send credit: %d \n " ,
self - > send_credit ) ;
seq_printf ( seq , " tx packets: %ld, " ,
self - > stats . tx_packets ) ;
seq_printf ( seq , " rx packets: %ld, " ,
self - > stats . rx_packets ) ;
seq_printf ( seq , " tx_queue len: %d " ,
skb_queue_len ( & self - > tx_queue ) ) ;
seq_printf ( seq , " rx_queue len: %d \n " ,
skb_queue_len ( & self - > rx_queue ) ) ;
seq_printf ( seq , " tx_sdu_busy: %s, " ,
self - > tx_sdu_busy ? " TRUE " : " FALSE " ) ;
seq_printf ( seq , " rx_sdu_busy: %s \n " ,
self - > rx_sdu_busy ? " TRUE " : " FALSE " ) ;
seq_printf ( seq , " max_seg_size: %d, " ,
self - > max_seg_size ) ;
seq_printf ( seq , " tx_max_sdu_size: %d, " ,
self - > tx_max_sdu_size ) ;
seq_printf ( seq , " rx_max_sdu_size: %d \n " ,
self - > rx_max_sdu_size ) ;
seq_printf ( seq , " Used by (%s) \n \n " ,
self - > notify . name ) ;
return 0 ;
}
2007-07-11 10:07:31 +04:00
static const struct seq_operations irttp_seq_ops = {
2005-04-17 02:20:36 +04:00
. start = irttp_seq_start ,
. next = irttp_seq_next ,
. stop = irttp_seq_stop ,
. show = irttp_seq_show ,
} ;
static int irttp_seq_open ( struct inode * inode , struct file * file )
{
2007-10-10 13:30:45 +04:00
return seq_open_private ( file , & irttp_seq_ops ,
sizeof ( struct irttp_iter_state ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:36 +03:00
const struct file_operations irttp_seq_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = irttp_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release_private ,
} ;
# endif /* PROC_FS */