diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
commit | db7d4daea91e105e3859cf461d7e53b9b77454b2 (patch) | |
tree | 9bb65b95440af09e8aca63abe56970dd3360cc57 /net/irda/irttp.c | |
parent | 9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff) |
Merge with Linux 2.2.8.
Diffstat (limited to 'net/irda/irttp.c')
-rw-r--r-- | net/irda/irttp.c | 1142 |
1 files changed, 620 insertions, 522 deletions
diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 3da804e7d..bf0624eee 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: irttp.c - * Version: 0.4 + * Version: 1.2 * Description: Tiny Transport Protocol (TTP) implementation * Status: Experimental. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Sun Aug 31 20:14:31 1997 - * Modified at: Tue Jan 19 23:56:58 1999 + * Modified at: Sat Apr 10 10:32:21 1999 * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, @@ -28,33 +28,35 @@ #include <linux/init.h> #include <asm/byteorder.h> +#include <asm/unaligned.h> #include <net/irda/irda.h> +#include <net/irda/irmod.h> #include <net/irda/irlmp.h> #include <net/irda/irttp.h> struct irttp_cb *irttp = NULL; -static void __irttp_close_tsap( struct tsap_cb *self); +static void __irttp_close_tsap(struct tsap_cb *self); -static void irttp_data_indication( void *instance, void *sap, - struct sk_buff *skb); -static void irttp_udata_indication( void *instance, void *sap, - struct sk_buff *skb); -static void irttp_disconnect_indication( void *instance, void *sap, - LM_REASON reason, - struct sk_buff *); -static void irttp_connect_indication( void *instance, void *sap, - struct qos_info *qos, int max_sdu_size, - struct sk_buff *skb); +static int irttp_data_indication(void *instance, void *sap, + struct sk_buff *skb); +static int irttp_udata_indication(void *instance, void *sap, + struct sk_buff *skb); +static void irttp_disconnect_indication(void *instance, void *sap, + LM_REASON reason, + struct sk_buff *); +static void irttp_connect_indication(void *instance, void *sap, + struct qos_info *qos, __u32 max_sdu_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_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_start_todo_timer( struct tsap_cb *self, int timeout); +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_start_todo_timer(struct tsap_cb *self, int timeout); /* * Function irttp_init (void) @@ -64,21 +66,19 @@ static void irttp_start_todo_timer( struct tsap_cb *self, int timeout); */ __initfunc(int irttp_init(void)) { - DEBUG( 4, "--> irttp_init\n"); - /* Initialize the irttp structure. */ - if ( irttp == NULL) { - irttp = kmalloc( sizeof(struct irttp_cb), GFP_KERNEL); - if ( irttp == NULL) + if (irttp == NULL) { + irttp = kmalloc(sizeof(struct irttp_cb), GFP_KERNEL); + if (irttp == NULL) return -ENOMEM; } - memset( irttp, 0, sizeof(struct irttp_cb)); - + memset(irttp, 0, sizeof(struct irttp_cb)); + irttp->magic = TTP_MAGIC; - irttp->tsaps = hashbin_new( HB_LOCAL); - if ( !irttp->tsaps) { - printk( KERN_WARNING "IrDA: Can't allocate IrTTP hashbin!\n"); + irttp->tsaps = hashbin_new(HB_LOCAL); + if (!irttp->tsaps) { + printk(KERN_WARNING "IrDA: Can't allocate IrTTP hashbin!\n"); return -ENOMEM; } @@ -91,69 +91,73 @@ __initfunc(int irttp_init(void)) * Called by module destruction/cleanup code * */ +#ifdef MODULE void irttp_cleanup(void) { - DEBUG( 4, "irttp_cleanup\n"); - /* Check for main structure */ - ASSERT( irttp != NULL, return;); - ASSERT( irttp->magic == TTP_MAGIC, return;); + ASSERT(irttp != NULL, return;); + ASSERT(irttp->magic == TTP_MAGIC, return;); /* * Delete hashbin and close all TSAP instances in it */ - hashbin_delete( irttp->tsaps, (FREE_FUNC) __irttp_close_tsap); + hashbin_delete(irttp->tsaps, (FREE_FUNC) __irttp_close_tsap); - irttp->magic = ~TTP_MAGIC; + irttp->magic = 0; /* De-allocate main structure */ - kfree( irttp); + kfree(irttp); irttp = NULL; } +#endif /* * Function irttp_open_tsap (stsap, notify) * * Create TSAP connection endpoint, */ -struct tsap_cb *irttp_open_tsap( __u8 stsap_sel, int credit, - struct notify_t *notify) +struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, + struct notify_t *notify) { struct notify_t ttp_notify; struct tsap_cb *self; struct lsap_cb *lsap; - ASSERT( irttp != NULL, return NULL;); - ASSERT( irttp->magic == TTP_MAGIC, return NULL;); + ASSERT(irttp != NULL, return NULL;); + ASSERT(irttp->magic == TTP_MAGIC, return NULL;); - self = kmalloc( sizeof(struct tsap_cb), GFP_ATOMIC); - if ( self == NULL) { - printk( KERN_ERR "IrTTP: Can't allocate memory for " - "TSAP control block!\n"); + self = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC); + if (self == NULL) { + DEBUG(0, __FUNCTION__ "(), unable to kmalloc!\n"); return NULL; } - memset( self, 0, sizeof(struct tsap_cb)); + memset(self, 0, sizeof(struct tsap_cb)); - init_timer( &self->todo_timer); + init_timer(&self->todo_timer); /* Initialize callbacks for IrLMP to use */ - - irda_notify_init( &ttp_notify); + 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.instance = self; - strncpy( ttp_notify.name, notify->name, NOTIFY_MAX_NAME); + strncpy(ttp_notify.name, notify->name, NOTIFY_MAX_NAME); + self->magic = TTP_TSAP_MAGIC; + self->connected = FALSE; + + skb_queue_head_init(&self->rx_queue); + skb_queue_head_init(&self->tx_queue); + skb_queue_head_init(&self->rx_fragments); /* * Create LSAP at IrLMP layer */ - lsap = irlmp_open_lsap( stsap_sel, &ttp_notify); - if ( lsap == NULL) { - printk( KERN_ERR "IrTTP, Unable to get LSAP!!\n"); + lsap = irlmp_open_lsap(stsap_sel, &ttp_notify); + if (lsap == NULL) { + printk(KERN_ERR "IrTTP, Unable to get LSAP!!\n"); return NULL; } @@ -163,27 +167,19 @@ struct tsap_cb *irttp_open_tsap( __u8 stsap_sel, int credit, * the stsap_sel we have might not be valid anymore */ self->stsap_sel = lsap->slsap_sel; - DEBUG( 4, __FUNCTION__ "(), stsap_sel=%02x\n", self->stsap_sel); + DEBUG(4, __FUNCTION__ "(), stsap_sel=%02x\n", self->stsap_sel); self->notify = *notify; self->lsap = lsap; - self->magic = TTP_TSAP_MAGIC; - skb_queue_head_init( &self->rx_queue); - skb_queue_head_init( &self->tx_queue); - skb_queue_head_init( &self->rx_fragments); + hashbin_insert(irttp->tsaps, (QUEUE *) self, (int) self, NULL); - /* - * Insert ourself into the hashbin - */ - hashbin_insert( irttp->tsaps, (QUEUE *) self, self->stsap_sel, NULL); - - if ( credit > TTP_MAX_QUEUE) + if (credit > TTP_MAX_QUEUE) self->initial_credit = TTP_MAX_QUEUE; else self->initial_credit = credit; - - return self; + + return self; } /* @@ -193,27 +189,20 @@ struct tsap_cb *irttp_open_tsap( __u8 stsap_sel, int credit, * deallocation of the TSAP, and resetting of the TSAPs values; * */ -static void __irttp_close_tsap( struct tsap_cb *self) +static void __irttp_close_tsap(struct tsap_cb *self) { - DEBUG( 4, __FUNCTION__ "()\n"); - /* First make sure we're connected. */ - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - irttp_flush_queues( self); + irttp_flush_queues(self); - del_timer( &self->todo_timer); + del_timer(&self->todo_timer); self->connected = FALSE; self->magic = ~TTP_TSAP_MAGIC; - /* - * Deallocate structure - */ - kfree( self); - - DEBUG( 4, "irttp_close_tsap() -->\n"); + kfree(self); } /* @@ -223,24 +212,41 @@ static void __irttp_close_tsap( struct tsap_cb *self) * associated with this TSAP * */ -void irttp_close_tsap( struct tsap_cb *self) +int irttp_close_tsap(struct tsap_cb *self) { struct tsap_cb *tsap; - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + DEBUG(4, __FUNCTION__ "()\n"); - tsap = hashbin_remove( irttp->tsaps, self->stsap_sel, NULL); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); - ASSERT( tsap == self, return;); + /* Make sure tsap has been disconnected */ + if (self->connected) { + /* Check if disconnect is not pending */ + if (!self->disconnect_pend) { + DEBUG(0, __FUNCTION__ "(), TSAP still connected!\n"); + irttp_disconnect_request(self, NULL, P_NORMAL); + } + self->close_pend = TRUE; + irttp_start_todo_timer(self, 100); + + return 0; /* Will be back! */ + } + + tsap = hashbin_remove(irttp->tsaps, (int) self, NULL); + + ASSERT(tsap == self, return -1;); /* Close corresponding LSAP */ - if ( self->lsap) { - irlmp_close_lsap( self->lsap); + if (self->lsap) { + irlmp_close_lsap(self->lsap); self->lsap = NULL; } - __irttp_close_tsap( self); + __irttp_close_tsap(self); + + return 0; } /* @@ -249,26 +255,26 @@ void irttp_close_tsap( struct tsap_cb *self) * Send unreliable data on this TSAP * */ -int irttp_udata_request( struct tsap_cb *self, struct sk_buff *skb) +int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) { - ASSERT( self != NULL, return -1;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return -1;); - ASSERT( skb != NULL, return -1;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + ASSERT(skb != NULL, return -1;); - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* Check that nothing bad happens */ - if (( skb->len == 0) || ( !self->connected)) { - DEBUG( 0, __FUNCTION__ "(), No data, or not connected\n"); + if ((skb->len == 0) || (!self->connected)) { + DEBUG(1, __FUNCTION__ "(), No data, or not connected\n"); return -1; } - if ( skb->len > self->max_seg_size) { - DEBUG( 0, __FUNCTION__ "(), UData is to large for IrLAP!\n"); + if (skb->len > self->max_seg_size) { + DEBUG(1, __FUNCTION__ "(), UData is to large for IrLAP!\n"); return -1; } - irlmp_udata_request( self->lsap, skb); + irlmp_udata_request(self->lsap, skb); self->stats.tx_packets++; return 0; @@ -280,66 +286,62 @@ int irttp_udata_request( struct tsap_cb *self, struct sk_buff *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) +int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) { __u8 *frame; - DEBUG( 4, __FUNCTION__ "()\n"); - - ASSERT( self != NULL, return -1;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return -1;); - ASSERT( skb != NULL, return -1;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + ASSERT(skb != NULL, return -1;); /* Check that nothing bad happens */ - if (( skb->len == 0) || ( !self->connected)) { - DEBUG( 4, __FUNCTION__ "(), No data, or not connected\n"); - return -1; + if ((skb->len == 0) || (!self->connected)) { + DEBUG(4, __FUNCTION__ "(), No data, or not connected\n"); + return -ENOTCONN; } /* * 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)) - { - DEBUG( 0, __FUNCTION__ + if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) { + DEBUG(1, __FUNCTION__ "(), SAR disabled, and data is to large for IrLAP!\n"); - return -1; + return -EMSGSIZE; } /* * Check if SAR is enabled, and the frame is larger than the * TxMaxSduSize */ - if (( self->tx_max_sdu_size != 0) && + if ((self->tx_max_sdu_size != 0) && + (self->tx_max_sdu_size != SAR_UNBOUND) && (skb->len > self->tx_max_sdu_size)) { - DEBUG( 0, __FUNCTION__ "(), SAR enabled, " + DEBUG(1, __FUNCTION__ "(), SAR enabled, " "but data is larger than TxMaxSduSize!\n"); - return -1; + return -EMSGSIZE; } /* * Check if transmit queue is full */ - if ( skb_queue_len( &self->tx_queue) >= TTP_MAX_QUEUE) { + if (skb_queue_len(&self->tx_queue) >= TTP_MAX_QUEUE) { /* * Give it a chance to empty itself */ - irttp_run_tx_queue( self); + irttp_run_tx_queue(self); - return -1; + return -ENOBUFS; } /* Queue frame, or queue frame segments */ - if (( self->tx_max_sdu_size == 0) || - ( skb->len < self->max_seg_size)) { + if ((self->tx_max_sdu_size == 0) || (skb->len < self->max_seg_size)) { /* Queue frame */ - frame = skb_push( skb, TTP_HEADER); + frame = skb_push(skb, TTP_HEADER); frame[0] = 0x00; /* Clear more bit */ - DEBUG( 4, __FUNCTION__ "(), queueing original skb\n"); - skb_queue_tail( &self->tx_queue, skb); + DEBUG(4, __FUNCTION__ "(), queueing original skb\n"); + skb_queue_tail(&self->tx_queue, skb); } else { /* * Fragment the frame, this function will also queue the @@ -347,117 +349,103 @@ int irttp_data_request( struct tsap_cb *self, struct sk_buff *skb) * queue may be overfilled by all the segments for a little * while */ - irttp_fragment_skb( self, skb); + 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) > HIGH_THRESHOLD)) { + if ((!self->tx_sdu_busy) && + (skb_queue_len(&self->tx_queue) > HIGH_THRESHOLD)) { /* Tx queue filling up, so stop client */ self->tx_sdu_busy = TRUE; - if ( self->notify.flow_indication) { - self->notify.flow_indication( self->notify.instance, - self, - FLOW_STOP); + if (self->notify.flow_indication) { + self->notify.flow_indication( + self->notify.instance, self, FLOW_STOP); } } /* Try to make some progress */ - irttp_run_tx_queue( self); + irttp_run_tx_queue(self); return 0; } /* - * Function irttp_xmit (self) + * Function irttp_run_tx_queue (self) * * If possible, transmit a frame queued for transmission. * */ -static void irttp_run_tx_queue( struct tsap_cb *self) +static void irttp_run_tx_queue(struct tsap_cb *self) { struct sk_buff *skb = NULL; unsigned long flags; __u8 *frame; int n; - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); - - if ( irda_lock( &self->tx_queue_lock) == FALSE) + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + + if (irda_lock(&self->tx_queue_lock) == FALSE) return; - while (( self->send_credit > 0) && !skb_queue_empty( &self->tx_queue)){ - - skb = skb_dequeue( &self->tx_queue); - ASSERT( skb != NULL, return;); + while ((self->send_credit > 0) && !skb_queue_empty(&self->tx_queue)) { + skb = skb_dequeue(&self->tx_queue); + ASSERT(skb != NULL, return;); /* Make room for TTP header */ - ASSERT( skb_headroom( skb) >= TTP_HEADER, return;); + ASSERT(skb_headroom(skb) >= TTP_HEADER, return;); /* * 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. */ - save_flags( flags); - cli(); + spin_lock_irqsave(&self->lock, flags); n = self->avail_credit; self->avail_credit = 0; - /* Only space for 127 credits in frame */ - if ( n > 127) { + /* Only room for 127 credits in frame */ + if (n > 127) { self->avail_credit = n-127; n = 127; } self->remote_credit += n; self->send_credit--; - restore_flags(flags); + spin_unlock_irqrestore(&self->lock, flags); - DEBUG( 4, "irttp_xmit: Giving away %d credits\n", n); - /* * More bit must be set by the data_request() or fragment() * functions */ frame = skb->data; - DEBUG( 4, __FUNCTION__ "(), More=%s\n", frame[0] & 0x80 ? + DEBUG(4, __FUNCTION__ "(), More=%s\n", frame[0] & 0x80 ? "TRUE" : "FALSE" ); frame[0] |= (__u8) (n & 0x7f); - irlmp_data_request( self->lsap, skb); + irlmp_data_request(self->lsap, skb); self->stats.tx_packets++; /* Check if we can accept more frames from client */ - if (( self->tx_sdu_busy) && - ( skb_queue_len( &self->tx_queue) < LOW_THRESHOLD)) { + if ((self->tx_sdu_busy) && + (skb_queue_len(&self->tx_queue) < LOW_THRESHOLD)) + { self->tx_sdu_busy = FALSE; - if ( self->notify.flow_indication) - self->notify.flow_indication( self->notify.instance, - self, - FLOW_START); + if (self->notify.flow_indication) + self->notify.flow_indication( + self->notify.instance, self, + FLOW_START); } } /* Reset lock */ self->tx_queue_lock = 0; - - /* Check if there is any disconnect request pending */ - if ( self->disconnect_pend) { - if ( self->disconnect_skb) { - irttp_disconnect_request( self, self->disconnect_skb, - P_NORMAL); - self->disconnect_skb = NULL; - } else - irttp_disconnect_request( self, NULL, P_NORMAL); - } } /* @@ -466,80 +454,78 @@ static void irttp_run_tx_queue( struct tsap_cb *self) * Send a dataless flowdata TTP-PDU and give available credit to peer * TSAP */ -void irttp_give_credit( struct tsap_cb *self) +void irttp_give_credit(struct tsap_cb *self) { struct sk_buff *tx_skb = NULL; unsigned long flags; int n; - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - DEBUG( 4, "irttp_give_credit() send=%d,avail=%d,remote=%d\n", + DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", self->send_credit, self->avail_credit, self->remote_credit); /* Give credit to peer */ - tx_skb = dev_alloc_skb( 64); - if ( tx_skb == NULL) { - DEBUG( 0, "irttp_give_credit: " - "Could not allocate an sk_buff of length %d\n", 64); + tx_skb = dev_alloc_skb(64); + if (!tx_skb) return; - } /* Reserve space for LMP, and LAP header */ - skb_reserve( tx_skb, LMP_HEADER+LAP_HEADER); + skb_reserve(tx_skb, LMP_HEADER+LAP_HEADER); /* * 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. */ - save_flags( flags); - cli(); + spin_lock_irqsave(&self->lock, flags); n = self->avail_credit; self->avail_credit = 0; /* Only space for 127 credits in frame */ - if ( n > 127) { + if (n > 127) { self->avail_credit = n - 127; n = 127; } self->remote_credit += n; - restore_flags(flags); + spin_unlock_irqrestore(&self->lock, flags); - skb_put( tx_skb, 1); - tx_skb->data[0] = (__u8) ( n & 0x7f); + skb_put(tx_skb, 1); + tx_skb->data[0] = (__u8) (n & 0x7f); - irlmp_data_request( self->lsap, tx_skb); + irlmp_data_request(self->lsap, tx_skb); self->stats.tx_packets++; } /* * Function irttp_udata_indication (instance, sap, skb) * - * + * Received some unit-data (unreliable) * */ -void irttp_udata_indication( void *instance, void *sap, struct sk_buff *skb) +static int irttp_udata_indication(void *instance, void *sap, + struct sk_buff *skb) { struct tsap_cb *self; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); self = (struct tsap_cb *) instance; - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); - ASSERT( skb != NULL, return;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + ASSERT(skb != NULL, return -1;); /* Just pass data to layer above */ - if ( self->notify.udata_indication) { - self->notify.udata_indication( self->notify.instance, self, - skb); + if (self->notify.udata_indication) { + self->notify.udata_indication(self->notify.instance, self, skb); } self->stats.rx_packets++; + + return 0; } /* @@ -548,7 +534,8 @@ void irttp_udata_indication( void *instance, void *sap, struct sk_buff *skb) * Receive segment from IrLMP. * */ -void irttp_data_indication( void *instance, void *sap, struct sk_buff *skb) +static int irttp_data_indication(void *instance, void *sap, + struct sk_buff *skb) { struct tsap_cb *self; int more; @@ -557,17 +544,17 @@ void irttp_data_indication( void *instance, void *sap, struct sk_buff *skb) self = (struct tsap_cb *) instance; - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); - ASSERT( skb != NULL, return;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); + ASSERT(skb != NULL, return -1;); frame = skb->data; n = frame[0] & 0x7f; /* Extract the credits */ more = frame[0] & 0x80; - DEBUG( 4, __FUNCTION__"(), got %d credits, TSAP sel=%02x\n", - n, self->stsap_sel); + DEBUG(3, __FUNCTION__"(), got %d credits, TSAP sel=%02x\n", + n, self->stsap_sel); self->stats.rx_packets++; @@ -575,7 +562,7 @@ void irttp_data_indication( void *instance, void *sap, struct sk_buff *skb) * Data or dataless frame? Dataless frames only contain the * TTP_HEADER */ - if ( skb->len == 1) { + if (skb->len == 1) { /* Dataless flowdata TTP-PDU */ self->send_credit += n; } else { @@ -587,27 +574,28 @@ void irttp_data_indication( void *instance, void *sap, struct sk_buff *skb) * 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); + skb_queue_tail(&self->rx_queue, skb); } - irttp_run_rx_queue( self); + irttp_run_rx_queue(self); /* * Give avay some credits to peer? */ - if (( skb_queue_empty( &self->tx_queue)) && - ( self->remote_credit < LOW_THRESHOLD) && - ( self->avail_credit > 0)) + if ((skb_queue_empty(&self->tx_queue)) && + (self->remote_credit < LOW_THRESHOLD) && + (self->avail_credit > 0)) { /* Schedule to start immediately after this thread */ - irttp_start_todo_timer( self, 0); + irttp_start_todo_timer(self, 0); } /* If peer has given us some credites and we didn't have anyone * from before, the we need to shedule the tx queue? */ - if ( self->send_credit == n) - irttp_start_todo_timer( self, 0); + if (self->send_credit == n) + irttp_start_todo_timer(self, 0); + return 0; } /* @@ -617,26 +605,26 @@ void irttp_data_indication( void *instance, void *sap, struct sk_buff *skb) * 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) +void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow) { - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(1, __FUNCTION__ "()\n"); - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - switch ( flow) { + switch (flow) { case FLOW_STOP: - DEBUG( 0, __FUNCTION__ "(), flow stop\n"); + DEBUG(1, __FUNCTION__ "(), flow stop\n"); self->rx_sdu_busy = TRUE; break; case FLOW_START: - DEBUG( 0, __FUNCTION__ "(), flow start\n"); + DEBUG(1, __FUNCTION__ "(), flow start\n"); self->rx_sdu_busy = FALSE; - irttp_run_rx_queue( self); + irttp_run_rx_queue(self); break; default: - DEBUG( 0, __FUNCTION__ "(), Unknown flow command!\n"); + DEBUG(1, __FUNCTION__ "(), Unknown flow command!\n"); } } @@ -646,38 +634,36 @@ void irttp_flow_request( struct tsap_cb *self, LOCAL_FLOW flow) * Try to connect to remote destination TSAP selector * */ -void irttp_connect_request( struct tsap_cb *self, __u8 dtsap_sel, __u32 daddr, - struct qos_info *qos, int max_sdu_size, - struct sk_buff *userdata) +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 *skb; __u8 *frame; __u8 n; - DEBUG( 4, __FUNCTION__ "(), max_sdu_size=%d\n", max_sdu_size); + DEBUG(4, __FUNCTION__ "(), max_sdu_size=%d\n", max_sdu_size); - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); /* Any userdata supplied? */ - if ( userdata == NULL) { - skb = dev_alloc_skb( 64); - if (skb == NULL) { - DEBUG( 0, __FUNCTION__ "Could not allocate an " - "sk_buff of length %d\n", 64); - return; - } + if (userdata == NULL) { + skb = dev_alloc_skb(64); + if (!skb) + return -ENOMEM; /* Reserve space for MUX_CONTROL and LAP header */ - skb_reserve( skb, (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER)); + skb_reserve(skb, (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER)); } else { skb = userdata; /* * Check that the client has reserved enough space for * headers */ - ASSERT( skb_headroom( userdata) >= - (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER), return;); + ASSERT(skb_headroom(userdata) >= + (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER), return -1;); } /* Initialize connection parameters */ @@ -696,7 +682,7 @@ void irttp_connect_request( struct tsap_cb *self, __u8 dtsap_sel, __u32 daddr, /* * Give away max 127 credits for now */ - if ( n > 127) { + if (n > 127) { self->avail_credit=n-127; n = 127; } @@ -704,29 +690,32 @@ void irttp_connect_request( struct tsap_cb *self, __u8 dtsap_sel, __u32 daddr, self->remote_credit = n; /* SAR enabled? */ - if ( max_sdu_size > 0) { - ASSERT( skb_headroom( skb) >= + if (max_sdu_size > 0) { + ASSERT(skb_headroom(skb) >= (TTP_HEADER_WITH_SAR+LMP_CONTROL_HEADER+LAP_HEADER), - return;); + return -1;); /* Insert SAR parameters */ - frame = skb_push( skb, TTP_HEADER_WITH_SAR); + frame = skb_push(skb, TTP_HEADER_WITH_SAR); frame[0] = TTP_PARAMETERS | n; frame[1] = 0x04; /* Length */ frame[2] = 0x01; /* MaxSduSize */ frame[3] = 0x02; /* Value length */ - *((__u16 *) (frame+4))= htons( max_sdu_size); /* Big endian! */ + + put_unaligned(cpu_to_be16((__u16) max_sdu_size), + (__u16 *)(frame+4)); } else { /* Insert plain TTP header */ - frame = skb_push( skb, TTP_HEADER); + frame = skb_push(skb, TTP_HEADER); /* Insert initial credit in frame */ frame[0] = n & 0x7f; } /* Connect with IrLMP. No QoS parameters for now */ - irlmp_connect_request( self->lsap, dtsap_sel, daddr, qos, skb); + return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos, + skb); } /* @@ -735,24 +724,22 @@ void irttp_connect_request( struct tsap_cb *self, __u8 dtsap_sel, __u32 daddr, * Sevice user confirms TSAP connection with peer. * */ -void irttp_connect_confirm( void *instance, void *sap, struct qos_info *qos, - int max_seg_size, struct sk_buff *skb) +void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos, + __u32 max_seg_size, struct sk_buff *skb) { struct tsap_cb *self; + int parameters; __u8 *frame; + __u8 plen, pi, pl; __u8 n; - int parameters; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); self = (struct tsap_cb *) instance; - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); - ASSERT( skb != NULL, return;); - - /* FIXME: just remove this when we know its working */ - ASSERT( max_seg_size == qos->data_size.value, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(skb != NULL, return;); self->max_seg_size = max_seg_size-LMP_HEADER-LAP_HEADER; @@ -760,40 +747,59 @@ void irttp_connect_confirm( void *instance, void *sap, struct qos_info *qos, * Check if we have got some QoS parameters back! This should be the * negotiated QoS for the link. */ - if ( qos) { - DEBUG( 4, "IrTTP, Negotiated BAUD_RATE: %02x\n", + if (qos) { + DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %02x\n", qos->baud_rate.bits); - DEBUG( 4, "IrTTP, Negotiated BAUD_RATE: %d bps.\n", + DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %d bps.\n", qos->baud_rate.value); } frame = skb->data; n = frame[0] & 0x7f; - DEBUG( 4, __FUNCTION__ "(), Initial send_credit=%d\n", n); + DEBUG(4, __FUNCTION__ "(), Initial send_credit=%d\n", n); self->send_credit = n; self->tx_max_sdu_size = 0; self->connected = TRUE; parameters = frame[0] & 0x80; - if ( parameters) { - DEBUG( 4, __FUNCTION__ "(), Contains parameters!\n"); - - self->tx_max_sdu_size = ntohs(*(__u16 *)(frame+4)); - DEBUG( 4, __FUNCTION__ "(), RxMaxSduSize=%d\n", - self->tx_max_sdu_size); + if (parameters) { + plen = frame[1]; + pi = frame[2]; + pl = frame[3]; + + switch (pl) { + case 1: + self->tx_max_sdu_size = *(frame+4); + break; + case 2: + self->tx_max_sdu_size = + be16_to_cpu(get_unaligned((__u16 *)(frame+4))); + break; + case 4: + self->tx_max_sdu_size = + be32_to_cpu(get_unaligned((__u32 *)(frame+4))); + break; + default: + printk(KERN_ERR __FUNCTION__ + "() illegal value length for max_sdu_size!\n"); + self->tx_max_sdu_size = 0; + }; + + DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n", + self->tx_max_sdu_size); } - DEBUG( 4, "irttp_connect_confirm() send=%d,avail=%d,remote=%d\n", - self->send_credit, self->avail_credit, self->remote_credit); + DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", + self->send_credit, self->avail_credit, self->remote_credit); - skb_pull( skb, TTP_HEADER); + skb_pull(skb, TTP_HEADER); - if ( self->notify.connect_confirm) { - self->notify.connect_confirm( self->notify.instance, self, - qos, self->tx_max_sdu_size, - skb); + if (self->notify.connect_confirm) { + self->notify.connect_confirm(self->notify.instance, self, + qos, self->tx_max_sdu_size, + skb); } } @@ -803,32 +809,31 @@ void irttp_connect_confirm( void *instance, void *sap, struct qos_info *qos, * Some other device is connecting to this TSAP * */ -void irttp_connect_indication( void *instance, void *sap, - struct qos_info *qos, int max_seg_size, - struct sk_buff *skb) +void irttp_connect_indication(void *instance, void *sap, + struct qos_info *qos, __u32 max_seg_size, + struct sk_buff *skb) { struct tsap_cb *self; - __u8 *frame; + struct lsap_cb *lsap; int parameters; - int n; + __u8 *frame; + __u8 plen, pi, pl; + __u8 n; self = (struct tsap_cb *) instance; - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); - ASSERT( skb != NULL, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(skb != NULL, return;); - /* FIXME: just remove this when we know its working */ - ASSERT( max_seg_size == qos->data_size.value, return;); + lsap = (struct lsap_cb *) sap; self->max_seg_size = max_seg_size-LMP_HEADER-LAP_HEADER; - DEBUG( 4, "irttp_connect_indication(), TSAP sel=%02x\n", - self->stsap_sel); + DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel); - /* FIXME: Need to update dtsap_sel if its equal to LSAP_ANY */ -/* if ( self->dtsap_sel == LSAP_ANY) */ -/* self->dtsap_sel = lsap->dlsap_sel; */ + /* Need to update dtsap_sel if its equal to LSAP_ANY */ + self->dtsap_sel = lsap->dlsap_sel; frame = skb->data; n = frame[0] & 0x7f; @@ -837,22 +842,43 @@ void irttp_connect_indication( void *instance, void *sap, self->tx_max_sdu_size = 0; parameters = frame[0] & 0x80; - if ( parameters) { - DEBUG( 4, __FUNCTION__ "(), Contains parameters!\n"); - - self->tx_max_sdu_size = ntohs(*(__u16 *)(frame+4)); - DEBUG( 4, __FUNCTION__ "(), MaxSduSize=%d\n", - self->tx_max_sdu_size); + if (parameters) { + DEBUG(3, __FUNCTION__ "(), Contains parameters!\n"); + plen = frame[1]; + pi = frame[2]; + pl = frame[3]; + + switch (pl) { + case 1: + self->tx_max_sdu_size = *(frame+4); + break; + case 2: + self->tx_max_sdu_size = + be16_to_cpu(get_unaligned((__u16 *)(frame+4))); + break; + case 4: + self->tx_max_sdu_size = + be32_to_cpu(get_unaligned((__u32 *)(frame+4))); + break; + default: + printk(KERN_ERR __FUNCTION__ + "() illegal value length for max_sdu_size!\n"); + self->tx_max_sdu_size = 0; + }; + + + DEBUG(3, __FUNCTION__ "(), MaxSduSize=%d\n", + self->tx_max_sdu_size); } - DEBUG( 4, "irttp_connect_indication: initial send_credit=%d\n", n); + DEBUG(4, __FUNCTION__ "(), initial send_credit=%d\n", n); - skb_pull( skb, 1); + skb_pull(skb, 1); /* Remove TTP header */ - if ( self->notify.connect_indication) { - self->notify.connect_indication( self->notify.instance, self, - qos, self->rx_max_sdu_size, - skb); + if (self->notify.connect_indication) { + self->notify.connect_indication(self->notify.instance, self, + qos, self->rx_max_sdu_size, + skb); } } @@ -863,37 +889,34 @@ void irttp_connect_indication( void *instance, void *sap, * IrLMP! * */ -void irttp_connect_response( struct tsap_cb *self, int max_sdu_size, - struct sk_buff *userdata) +void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, + struct sk_buff *userdata) { struct sk_buff *skb; __u8 *frame; __u8 n; - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - DEBUG( 4, __FUNCTION__ "(), Source TSAP selector=%02x\n", - self->stsap_sel); + DEBUG(4, __FUNCTION__ "(), Source TSAP selector=%02x\n", + self->stsap_sel); /* Any userdata supplied? */ - if ( userdata == NULL) { - skb = dev_alloc_skb( 64); - if (skb == NULL) { - DEBUG( 0, __FUNCTION__ "Could not allocate an " - "sk_buff of length %d\n", 64); + if (userdata == NULL) { + skb = dev_alloc_skb(64); + if (!skb) return; - } /* Reserve space for MUX_CONTROL and LAP header */ - skb_reserve( skb, (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER)); + skb_reserve(skb, (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER)); } else { skb = userdata; /* * Check that the client has reserved enough space for * headers */ - ASSERT( skb_headroom( skb) >= + ASSERT(skb_headroom(skb) >= (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER), return;); } @@ -906,7 +929,7 @@ void irttp_connect_response( struct tsap_cb *self, int max_sdu_size, n = self->initial_credit; /* Frame has only space for max 127 credits (7 bits) */ - if ( n > 127) { + if (n > 127) { self->avail_credit = n - 127; n = 127; } @@ -915,117 +938,152 @@ void irttp_connect_response( struct tsap_cb *self, int max_sdu_size, self->connected = TRUE; /* SAR enabled? */ - if ( max_sdu_size > 0) { - ASSERT( skb_headroom( skb) >= - (TTP_HEADER_WITH_SAR+LMP_CONTROL_HEADER+LAP_HEADER), - return;); + if (max_sdu_size > 0) { + ASSERT(skb_headroom(skb) >= + (TTP_HEADER_WITH_SAR+LMP_CONTROL_HEADER+LAP_HEADER), + return;); /* Insert TTP header with SAR parameters */ - frame = skb_push( skb, TTP_HEADER_WITH_SAR); + frame = skb_push(skb, TTP_HEADER_WITH_SAR); frame[0] = TTP_PARAMETERS | n; frame[1] = 0x04; /* Length */ frame[2] = 0x01; /* MaxSduSize */ frame[3] = 0x02; /* Value length */ - *((__u16 *) (frame+4))= htons( max_sdu_size); + + put_unaligned(cpu_to_be16((__u16) max_sdu_size), + (__u16 *)(frame+4)); } else { /* Insert TTP header */ - frame = skb_push( skb, TTP_HEADER); + frame = skb_push(skb, TTP_HEADER); frame[0] = n & 0x7f; } - irlmp_connect_response( self->lsap, skb); + irlmp_connect_response(self->lsap, skb); +} + +/* + * 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; + + DEBUG(1, __FUNCTION__ "()\n"); + + if (!hashbin_find(irttp->tsaps, (int) orig, NULL)) { + DEBUG(0, __FUNCTION__ "(), unable to find TSAP\n"); + return NULL; + } + new = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC); + if (!new) { + DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n"); + return NULL; + } + /* Dup */ + memcpy(new, orig, sizeof(struct tsap_cb)); + new->notify.instance = instance; + new->lsap = irlmp_dup(orig->lsap, new); + + /* Not everything should be copied */ + init_timer(&new->todo_timer); + + skb_queue_head_init(&new->rx_queue); + skb_queue_head_init(&new->tx_queue); + skb_queue_head_init(&new->rx_fragments); + + hashbin_insert(irttp->tsaps, (QUEUE *) new, (int) new, NULL); + + return new; } /* - * Function irttp_disconnect_request ( self) + * Function irttp_disconnect_request (self) * * Close this connection please! If priority is high, the queued data * segments, if any, will be deallocated first * */ -void irttp_disconnect_request( struct tsap_cb *self, struct sk_buff *userdata, - int priority) +void irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, + int priority) { struct sk_buff *skb; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(2, __FUNCTION__ "()\n"); - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); /* Already disconnected? */ - if ( !self->connected) { - DEBUG( 4, __FUNCTION__ "(), already disconnected!\n"); + if (!self->connected) { + DEBUG(4, __FUNCTION__ "(), already disconnected!\n"); return; } /* Disconnect already pending? */ - if ( self->disconnect_pend) { - DEBUG( 0, __FUNCTION__ "(), disconnect already pending\n"); - if ( userdata) { - dev_kfree_skb( userdata); + if (self->disconnect_pend) { + DEBUG(1, __FUNCTION__ "(), disconnect already pending\n"); + if (userdata) { + dev_kfree_skb(userdata); } /* Try to make some progress */ - irttp_run_rx_queue( self); + irttp_run_rx_queue(self); return; } /* * Check if there is still data segments in the transmit queue */ - if ( skb_queue_len( &self->tx_queue) > 0) { - if ( priority == P_HIGH) { - DEBUG( 0, __FUNCTION__ "High priority!!()\n" ); + if (skb_queue_len(&self->tx_queue) > 0) { + if (priority == P_HIGH) { + DEBUG(1, __FUNCTION__ "High priority!!()\n" ); /* * 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 */ - irttp_flush_queues( self); - } else if ( priority == P_NORMAL) { + irttp_flush_queues(self); + } else if (priority == P_NORMAL) { /* * Must delay disconnect til after all data segments * have been sent an the tx_queue is empty */ - if ( userdata) + if (userdata) self->disconnect_skb = userdata; else self->disconnect_skb = NULL; self->disconnect_pend = TRUE; - irttp_run_tx_queue( self); - /* - * irttp_xmit will call us again when the tx_queue - * is empty - */ + irttp_run_tx_queue(self); + + irttp_start_todo_timer(self, 100); return; } } - DEBUG( 0, __FUNCTION__ "(), Disconnecting ...\n"); + DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n"); self->connected = FALSE; - if ( !userdata) { - skb = dev_alloc_skb( 64); - if (skb == NULL) { - DEBUG( 0, __FUNCTION__ "(), Could not allocate an " - "sk_buff of length %d\n", 64); + if (!userdata) { + skb = dev_alloc_skb(64); + if (!skb) return; - } - + /* * Reserve space for MUX and LAP header */ - skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER); - + skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER); + userdata = skb; } - irlmp_disconnect_request( self->lsap, userdata); + irlmp_disconnect_request(self->lsap, userdata); } /* @@ -1034,26 +1092,58 @@ void irttp_disconnect_request( struct tsap_cb *self, struct sk_buff *userdata, * Disconnect indication, TSAP disconnected by peer? * */ -void irttp_disconnect_indication( void *instance, void *sap, LM_REASON reason, - struct sk_buff *userdata) +void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason, + struct sk_buff *userdata) { struct tsap_cb *self; - DEBUG( 4, "irttp_disconnect_indication()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - self = ( struct tsap_cb *) instance; + self = (struct tsap_cb *) instance; - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); self->connected = FALSE; - /* - * Use callback to notify layer above + if (!self->notify.disconnect_indication) + return; + + self->notify.disconnect_indication(self->notify.instance, self, reason, + userdata); +} + +/* + * Function irttp_do_data_indication (self, skb) + * + * Try to deliver reassebled 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. + */ +void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb) +{ + int err; + + 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 ( self->notify.disconnect_indication) - self->notify.disconnect_indication( self->notify.instance, - self, reason, userdata); + if (err == -ENOMEM) { + DEBUG(0, __FUNCTION__ "() requeueing skb!\n"); + + /* 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); + } } /* @@ -1062,43 +1152,27 @@ void irttp_disconnect_indication( void *instance, void *sap, LM_REASON reason, * 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) +void irttp_run_rx_queue(struct tsap_cb *self) { struct sk_buff *skb; - __u8 *frame; int more = 0; - void *instance; - - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); - - instance = self->notify.instance; - ASSERT( instance != NULL, return;); - DEBUG( 4, "irttp_do_events() send=%d,avail=%d,remote=%d\n", + DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", self->send_credit, self->avail_credit, self->remote_credit); - if ( irda_lock( &self->rx_queue_lock) == FALSE) + if (irda_lock(&self->rx_queue_lock) == FALSE) return; /* - * Process receive queue + * Reassemble all frames in receive queue and deliver them */ - while (( !skb_queue_empty( &self->rx_queue)) && !self->rx_sdu_busy) { - - skb = skb_dequeue( &self->rx_queue); - if ( !skb) - break; /* Should not happend, but ... */ - + while (!self->rx_sdu_busy && (skb = skb_dequeue(&self->rx_queue))) { self->avail_credit++; - frame = skb->data; - more = frame[0] & 0x80; - DEBUG( 4, __FUNCTION__ "(), More=%s\n", more ? "TRUE" : - "FALSE"); + more = skb->data[0] & 0x80; /* Remove TTP header */ - skb_pull( skb, TTP_HEADER); + skb_pull(skb, TTP_HEADER); /* Add the length of the remaining data */ self->rx_sdu_size += skb->len; @@ -1109,57 +1183,61 @@ void irttp_run_rx_queue( struct tsap_cb *self) * immediately. This can be requested by clients that * implements byte streams without any message boundaries */ - if ((self->no_defrag) || (self->rx_max_sdu_size == 0)) { - self->notify.data_indication( instance, self, skb); + if (self->rx_max_sdu_size == 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) { + 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) { - DEBUG( 4, __FUNCTION__ - "(), queueing fragment\n"); - - skb_queue_tail( &self->rx_fragments, skb); + if (self->rx_sdu_size <= self->rx_max_sdu_size) { + DEBUG(4, __FUNCTION__ "(), queueing frag\n"); + skb_queue_tail(&self->rx_fragments, skb); } else { - DEBUG( 0, __FUNCTION__ "(), Error!\n"); + /* Free the part of the SDU that is too big */ + dev_kfree_skb(skb); } - } else { - /* - * This is the last fragment, so time to reassemble! + 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 == 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 ( self->rx_sdu_size <= self->rx_max_sdu_size) { - - /* A little optimizing. Only queue the - * fragment if there is other fragments. Since - * if this is the last and only fragment, - * there is no need to reassemble - */ - if ( !skb_queue_empty( &self->rx_fragments)) { - - DEBUG( 4, __FUNCTION__ - "(), queueing fragment\n"); - skb_queue_tail( &self->rx_fragments, - skb); - - skb = irttp_reassemble_skb( self); - } - self->notify.data_indication( instance, self, - skb); - } else { - DEBUG( 0, __FUNCTION__ - "(), Truncated frame\n"); - self->notify.data_indication( - self->notify.instance, self, skb); + if (!skb_queue_empty(&self->rx_fragments)) { + skb_queue_tail(&self->rx_fragments, + skb); + + skb = irttp_reassemble_skb(self); } - self->rx_sdu_size = 0; + + /* Now we can deliver the reassembled skb */ + irttp_do_data_indication(self, skb); + } else { + DEBUG(1, __FUNCTION__ "(), Truncated frame\n"); + + /* 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; } /* Reset lock */ self->rx_queue_lock = 0; @@ -1170,28 +1248,26 @@ void irttp_run_rx_queue( struct tsap_cb *self) * * Flushes (removes all frames) in transitt-buffer (tx_list) */ -void irttp_flush_queues( struct tsap_cb *self) +void irttp_flush_queues(struct tsap_cb *self) { struct sk_buff* skb; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(self != NULL, return;); + 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); - } + 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); - } + 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); } /* @@ -1201,40 +1277,43 @@ void irttp_flush_queues( struct tsap_cb *self) * queue * */ -static struct sk_buff *irttp_reassemble_skb( struct tsap_cb *self) +static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self) { struct sk_buff *skb, *frag; int n = 0; /* Fragment index */ + + ASSERT(self != NULL, return NULL;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;); - ASSERT( self != NULL, return NULL;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return NULL;); - - DEBUG( 4, __FUNCTION__ "(), self->rx_sdu_size=%d\n", - self->rx_sdu_size); + DEBUG(4, __FUNCTION__ "(), self->rx_sdu_size=%d\n", + self->rx_sdu_size); - skb = dev_alloc_skb( self->rx_sdu_size); - if ( !skb) { - DEBUG( 0, __FUNCTION__ "(), unable to allocate skb\n"); + skb = dev_alloc_skb(self->rx_sdu_size); + if (!skb) return NULL; - } - skb_put( skb, self->rx_sdu_size); + /* + * 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) { - memcpy( skb->data+n, frag->data, frag->len); + while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) { + memcpy(skb->data+n, frag->data, frag->len); n += frag->len; - dev_kfree_skb( frag); + dev_kfree_skb(frag); } - DEBUG( 4, __FUNCTION__ "(), frame len=%d\n", n); + DEBUG(4, __FUNCTION__ "(), frame len=%d\n", n); /* Set the new length */ - DEBUG( 4, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size); - ASSERT( n <= self->rx_sdu_size, return NULL;); - skb_trim( skb, n); + DEBUG(4, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size); + ASSERT(n <= self->rx_sdu_size, return NULL;); + skb_trim(skb, n); self->rx_sdu_size = 0; @@ -1247,60 +1326,57 @@ static struct sk_buff *irttp_reassemble_skb( struct tsap_cb *self) * Fragments a frame and queues all the fragments for transmission * */ -static void irttp_fragment_skb( struct tsap_cb *self, struct sk_buff *skb) +static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb) { struct sk_buff *frag; __u8 *frame; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); - ASSERT( skb != NULL, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(skb != NULL, return;); /* * Split frame into a number of segments */ - while ( skb->len > 0) { + while (skb->len > 0) { /* * Instead of making the last segment, we just * queue what is left of the original skb */ - if ( skb->len < self->max_seg_size) { - DEBUG( 4, __FUNCTION__ + if (skb->len < self->max_seg_size) { + DEBUG(4, __FUNCTION__ "(), queuing last segment\n"); - frame = skb_push( skb, TTP_HEADER); + frame = skb_push(skb, TTP_HEADER); frame[0] = 0x00; /* Clear more bit */ - skb_queue_tail( &self->tx_queue, skb); + skb_queue_tail(&self->tx_queue, skb); return; } /* Make new segment */ - frag = dev_alloc_skb( self->max_seg_size+ - TTP_HEADER+LMP_HEADER+ - LAP_HEADER); - if ( frag == NULL) { - DEBUG( 0, __FUNCTION__ - "(), Couldn't allocate skbuff!\n"); + frag = dev_alloc_skb(self->max_seg_size+ + TTP_HEADER+LMP_HEADER+ + LAP_HEADER); + if (!frag) return; - } - skb_reserve( frag, LMP_HEADER+LAP_HEADER); + skb_reserve(frag, LMP_HEADER+LAP_HEADER); /* * Copy data from the original skb into this fragment. We * first insert the TTP header with the more bit set */ - frame = skb_put( frag, self->max_seg_size+TTP_HEADER); + frame = skb_put(frag, self->max_seg_size+TTP_HEADER); frame[0] = TTP_MORE; - memcpy( frag->data+1, skb->data, self->max_seg_size); + memcpy(frag->data+1, skb->data, self->max_seg_size); /* Hide the copied data from the original skb */ - skb_pull( skb, self->max_seg_size); + skb_pull(skb, self->max_seg_size); - skb_queue_tail( &self->tx_queue, frag); + skb_queue_tail(&self->tx_queue, frag); } } @@ -1310,31 +1386,54 @@ static void irttp_fragment_skb( struct tsap_cb *self, struct sk_buff *skb) * Todo timer has expired! * */ -static void irttp_todo_expired( unsigned long data) +static void irttp_todo_expired(unsigned long data) { - struct tsap_cb *self = ( struct tsap_cb *) data; + struct tsap_cb *self = (struct tsap_cb *) data; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* Check that we still exist */ - if ( !self || self->magic != TTP_TSAP_MAGIC) { + if (!self || self->magic != TTP_TSAP_MAGIC) { return; } - irttp_run_rx_queue( self); - irttp_run_tx_queue( self); + irttp_run_rx_queue(self); + irttp_run_tx_queue(self); /* Give avay some credits to peer? */ - if (( skb_queue_empty( &self->tx_queue)) && - ( self->remote_credit < LOW_THRESHOLD) && - ( self->avail_credit > 0)) + if ((skb_queue_empty(&self->tx_queue)) && + (self->remote_credit < LOW_THRESHOLD) && + (self->avail_credit > 0)) { - DEBUG( 4, "irttp_do_events: sending credit!\n"); - irttp_give_credit( self); + DEBUG(4, __FUNCTION__ "(), sending credit!\n"); + irttp_give_credit(self); } - - /* Rearm! */ - /* irttp_start_todo_timer( self, 50); */ + + /* Check if time for disconnect */ + if (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 */ + self->disconnect_pend = FALSE; + if (self->disconnect_skb) { + irttp_disconnect_request( + self, self->disconnect_skb, P_NORMAL); + self->disconnect_skb = NULL; + } else + irttp_disconnect_request(self, NULL, P_NORMAL); + } else { + /* Try again later */ + irttp_start_todo_timer(self, 100); + + /* No reason to try and close now */ + return; + } + } + + /* Check if it's closing time */ + if (self->close_pend) + irttp_close_tsap(self); } /* @@ -1343,18 +1442,18 @@ static void irttp_todo_expired( unsigned long data) * Start todo timer. * */ -static void irttp_start_todo_timer( struct tsap_cb *self, int timeout) +static void irttp_start_todo_timer(struct tsap_cb *self, int timeout) { - ASSERT( self != NULL, return;); - ASSERT( self->magic == TTP_TSAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - del_timer( &self->todo_timer); + del_timer(&self->todo_timer); self->todo_timer.data = (unsigned long) self; self->todo_timer.function = &irttp_todo_expired; self->todo_timer.expires = jiffies + timeout; - add_timer( &self->todo_timer); + add_timer(&self->todo_timer); } #ifdef CONFIG_PROC_FS @@ -1363,65 +1462,64 @@ static void irttp_start_todo_timer( struct tsap_cb *self, int timeout) * * Give some info to the /proc file system */ -int irttp_proc_read( char *buf, char **start, off_t offset, int len, - int unused) +int irttp_proc_read(char *buf, char **start, off_t offset, int len, int unused) { struct tsap_cb *self; unsigned long flags; int i = 0; - ASSERT( irttp != NULL, return 0;); + ASSERT(irttp != NULL, return 0;); len = 0; save_flags(flags); cli(); - self = ( struct tsap_cb *) hashbin_get_first( irttp->tsaps); - while ( self != NULL) { - if ( !self || self->magic != TTP_TSAP_MAGIC) { - DEBUG( 0, "irttp_proc_read: bad ptr self\n"); + self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps); + while (self != NULL) { + if (!self || self->magic != TTP_TSAP_MAGIC) { + DEBUG(1, "irttp_proc_read: bad ptr self\n"); return len; } - len += sprintf( buf+len, "TSAP %d, ", i++); - len += sprintf( buf+len, "stsap_sel: %02x, ", + len += sprintf(buf+len, "TSAP %d, ", i++); + len += sprintf(buf+len, "stsap_sel: %02x, ", self->stsap_sel); - len += sprintf( buf+len, "dtsap_sel: %02x\n", + len += sprintf(buf+len, "dtsap_sel: %02x\n", self->dtsap_sel); - len += sprintf( buf+len, " connected: %s, ", + len += sprintf(buf+len, " connected: %s, ", self->connected? "TRUE":"FALSE"); - len += sprintf( buf+len, "avail credit: %d, ", + len += sprintf(buf+len, "avail credit: %d, ", self->avail_credit); - len += sprintf( buf+len, "remote credit: %d, ", + len += sprintf(buf+len, "remote credit: %d, ", self->remote_credit); - len += sprintf( buf+len, "send credit: %d\n", + len += sprintf(buf+len, "send credit: %d\n", self->send_credit); - len += sprintf( buf+len, " tx packets: %d, ", + len += sprintf(buf+len, " tx packets: %d, ", self->stats.tx_packets); - len += sprintf( buf+len, "rx packets: %d, ", + len += sprintf(buf+len, "rx packets: %d, ", self->stats.rx_packets); - len += sprintf( buf+len, "tx_queue len: %d ", - skb_queue_len( &self->tx_queue)); - len += sprintf( buf+len, "rx_queue len: %d\n", - skb_queue_len( &self->rx_queue)); - len += sprintf( buf+len, " tx_sdu_busy: %s, ", + len += sprintf(buf+len, "tx_queue len: %d ", + skb_queue_len(&self->tx_queue)); + len += sprintf(buf+len, "rx_queue len: %d\n", + skb_queue_len(&self->rx_queue)); + len += sprintf(buf+len, " tx_sdu_busy: %s, ", self->tx_sdu_busy? "TRUE":"FALSE"); - len += sprintf( buf+len, "rx_sdu_busy: %s\n", + len += sprintf(buf+len, "rx_sdu_busy: %s\n", self->rx_sdu_busy? "TRUE":"FALSE"); - len += sprintf( buf+len, " max_seg_size: %d, ", + len += sprintf(buf+len, " max_seg_size: %d, ", self->max_seg_size); - len += sprintf( buf+len, "tx_max_sdu_size: %d, ", + len += sprintf(buf+len, "tx_max_sdu_size: %d, ", self->tx_max_sdu_size); - len += sprintf( buf+len, "rx_max_sdu_size: %d\n", + len += sprintf(buf+len, "rx_max_sdu_size: %d\n", self->rx_max_sdu_size); - len += sprintf( buf+len, " Used by (%s)\n", + len += sprintf(buf+len, " Used by (%s)\n", self->notify.name); - len += sprintf( buf+len, "\n"); + len += sprintf(buf+len, "\n"); - self = ( struct tsap_cb *) hashbin_get_next( irttp->tsaps); + self = (struct tsap_cb *) hashbin_get_next(irttp->tsaps); } restore_flags(flags); |