summaryrefslogtreecommitdiffstats
path: root/net/irda/ircomm/ircomm_common.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /net/irda/ircomm/ircomm_common.c
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'net/irda/ircomm/ircomm_common.c')
-rw-r--r--net/irda/ircomm/ircomm_common.c1489
1 files changed, 1056 insertions, 433 deletions
diff --git a/net/irda/ircomm/ircomm_common.c b/net/irda/ircomm/ircomm_common.c
index cfda567ce..bc8758e1e 100644
--- a/net/irda/ircomm/ircomm_common.c
+++ b/net/irda/ircomm/ircomm_common.c
@@ -33,25 +33,29 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
-#include <net/irda/irmod.h>
+#include <net/irda/irda.h>
#include <net/irda/irlmp.h>
#include <net/irda/iriap.h>
#include <net/irda/irttp.h>
+#include <net/irda/irias_object.h>
#include <net/irda/ircomm_common.h>
-#if 0
-static char *rcsid = "$Id: ircomm_common.c,v 1.13 1998/10/13 12:59:05 takahide Exp $";
-#endif
-static char *version = "IrCOMM_common, $Revision: 1.13 $ $Date: 1998/10/13 12:59:05 $ (Takahide Higuchi)";
-
+static char *revision_date = "Sun Apr 18 00:40:19 1999";
-
-static void ircomm_state_discovery( struct ircomm_cb *self,
- IRCOMM_EVENT event, struct sk_buff *skb );
static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb );
+
+static void ircomm_state_discoverywait( struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb );
+
+static void ircomm_state_queryparamwait( struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb );
+
+static void ircomm_state_querylsapwait( struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb );
+
static void ircomm_state_waiti( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb );
static void ircomm_state_waitr( struct ircomm_cb *self, IRCOMM_EVENT event,
@@ -60,15 +64,43 @@ static void ircomm_state_conn( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb );
static void ircomm_do_event( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb);
-void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state);
+static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state);
+
+static void ircomm_discovery_indication(discovery_t *discovery);
+static void ircomm_tx_controlchannel(struct ircomm_cb *self );
+static int ircomm_proc_read(char *buf, char **start, off_t offset,
+ int len, int unused);
+
+static void start_discovering(struct ircomm_cb *self);
+static void query_lsapsel(struct ircomm_cb * self);
+static void query_parameters(struct ircomm_cb *self);
+static void queryias_done(struct ircomm_cb *self);
+static void ircomm_getvalue_confirm(int result, __u16 obj_id,
+ struct ias_value *value, void *priv);
+
+
+struct ircomm_cb *discovering_instance;
+
+/*
+ * debug parameter ircomm_cs:
+ * 0 = client/server, 1 = client only 2 = server only
+ * usage for example:
+ * insmod ircomm ircomm_cs=1
+ * LILO boot : Linux ircomm_cs=2 etc.
+ */
+
+static int ircomm_cs = 0;
+MODULE_PARM(ircomm_cs, "i");
+
-int ircomm_check_handle(int handle);
-static void ircomm_parse_control(struct ircomm_cb *self, struct sk_buff *skb,
- int type);
static char *ircommstate[] = {
- "DISCOVERY",
"IDLE",
+
+ "DISCOVERY_WAIT",
+ "QUERYPARAM_WAIT",
+ "QUERYLSAP_WAIT",
+
"WAITI",
"WAITR",
"CONN",
@@ -107,38 +139,38 @@ static char *ircommevent[] = {
"IRCOMM_DATA_REQUEST",
"LMP_DATA_INDICATION",
"IRCOMM_CONTROL_REQUEST",
-};
-int ircomm_proc_read(char *buf, char **start, off_t offset,
- int len, int unused);
+ "DISCOVERY_INDICATION",
+ "GOT_PARAMETERS",
+ "GOT_LSAPSEL",
+ "QUERYIAS_ERROR",
+};
#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry proc_irda;
-struct proc_dir_entry proc_ircomm = {
- 0, 6, "ircomm",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, NULL,
- &ircomm_proc_read,
-};
+extern struct proc_dir_entry *proc_irda;
#endif
static void (*state[])( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb) =
{
- ircomm_state_discovery,
ircomm_state_idle,
+
+ ircomm_state_discoverywait,
+ ircomm_state_queryparamwait,
+ ircomm_state_querylsapwait,
+
ircomm_state_waiti,
ircomm_state_waitr,
ircomm_state_conn,
};
-
__initfunc(int ircomm_init(void))
{
int i;
- printk( KERN_INFO "%s\n", version);
- DEBUG( 4, "ircomm_common:init_module\n");
+ printk( "Linux-IrDA: IrCOMM protocol ( revision:%s ) \n",
+ revision_date);
+ DEBUG( 4, __FUNCTION__"()\n");
/* allocate master array */
@@ -146,7 +178,7 @@ __initfunc(int ircomm_init(void))
IRCOMM_MAX_CONNECTION,
GFP_KERNEL);
if ( ircomm == NULL) {
- printk( KERN_WARNING "IrCOMM: Can't allocate ircomm array!\n");
+ printk( KERN_ERR __FUNCTION__"(): kmalloc failed!\n");
return -ENOMEM;
}
@@ -158,7 +190,7 @@ __initfunc(int ircomm_init(void))
ircomm[i] = kmalloc( sizeof(struct ircomm_cb), GFP_KERNEL );
if(!ircomm[i]){
- printk(KERN_ERR "ircomm:kmalloc failed!\n");
+ printk( KERN_ERR __FUNCTION__"(): kmalloc failed!\n");
return -ENOMEM;
}
@@ -191,17 +223,20 @@ __initfunc(int ircomm_init(void))
*/
#ifdef CONFIG_PROC_FS
- proc_register( &proc_irda, &proc_ircomm);
+ create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
#endif /* CONFIG_PROC_FS */
+
+ discovering_instance = NULL;
return 0;
}
+#ifdef MODULE
void ircomm_cleanup(void)
{
int i;
- DEBUG( 4, "ircomm_common:cleanup_module\n");
+ DEBUG( 4, "ircomm:cleanup_module\n");
/*
* free some resources
*/
@@ -226,9 +261,10 @@ void ircomm_cleanup(void)
}
#ifdef CONFIG_PROC_FS
- proc_unregister( &proc_irda, proc_ircomm.low_ino);
-#endif
+ remove_proc_entry("ircomm", proc_irda);
+#endif /* CONFIG_PROC_FS */
}
+#endif /* MODULE */
/*
* ----------------------------------------------------------------------
@@ -236,21 +272,27 @@ void ircomm_cleanup(void)
* ----------------------------------------------------------------------
*/
-void ircomm_accept_data_indication(void *instance, void *sap, struct sk_buff *skb){
+static int ircomm_accept_data_indication(void *instance, void *sap,
+ struct sk_buff *skb)
+{
struct ircomm_cb *self = (struct ircomm_cb *)instance;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == IRCOMM_MAGIC, return;);
- ASSERT( skb != NULL, return;);
+ ASSERT( self != NULL, return -1;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return -1;);
+ ASSERT( skb != NULL, return -1;);
- DEBUG(4,"ircomm_accept_data_indication:\n");
+ DEBUG(4,__FUNCTION__"():\n");
ircomm_do_event( self, TTP_DATA_INDICATION, skb);
+ self->rx_packets++;
+
+ return 0;
}
-void ircomm_accept_connect_confirm(void *instance, void *sap,
+static void ircomm_accept_connect_confirm(void *instance, void *sap,
struct qos_info *qos,
- int maxsdusize, struct sk_buff *skb){
+ __u32 maxsdusize, struct sk_buff *skb)
+{
struct ircomm_cb *self = (struct ircomm_cb *)instance;
@@ -259,7 +301,7 @@ void ircomm_accept_connect_confirm(void *instance, void *sap,
ASSERT( skb != NULL, return;);
ASSERT( qos != NULL, return;);
- DEBUG(0,"ircomm_accept_connect_confirm:\n");
+ DEBUG(0,__FUNCTION__"(): got connected!\n");
if(maxsdusize == SAR_DISABLE)
self->max_txbuff_size = qos->data_size.value;
@@ -274,11 +316,11 @@ void ircomm_accept_connect_confirm(void *instance, void *sap,
ircomm_do_event( self, TTP_CONNECT_CONFIRM, skb);
}
-void ircomm_accept_connect_indication(void *instance, void *sap,
+static void ircomm_accept_connect_indication(void *instance, void *sap,
struct qos_info *qos,
- int maxsdusize,
- struct sk_buff *skb ){
-
+ __u32 maxsdusize,
+ struct sk_buff *skb )
+{
struct ircomm_cb *self = (struct ircomm_cb *)instance;
ASSERT( self != NULL, return;);
@@ -286,7 +328,7 @@ void ircomm_accept_connect_indication(void *instance, void *sap,
ASSERT( skb != NULL, return;);
ASSERT( qos != NULL, return;);
- DEBUG(0,"ircomm_accept_connect_indication:\n");
+ DEBUG(0,__FUNCTION__"()\n");
if(maxsdusize == SAR_DISABLE)
self->max_txbuff_size = qos->data_size.value;
@@ -295,22 +337,31 @@ void ircomm_accept_connect_indication(void *instance, void *sap,
self->qos = qos;
ircomm_do_event( self, TTP_CONNECT_INDICATION, skb);
+
+ /* stop connecting */
+ wake_up_interruptible( &self->discovery_wait);
+ wake_up_interruptible( &self->ias_wait);
+
}
-void ircomm_accept_disconnect_indication(void *instance, void *sap, LM_REASON reason,
- struct sk_buff *skb){
+static void ircomm_accept_disconnect_indication(void *instance, void *sap,
+ LM_REASON reason,
+ struct sk_buff *skb)
+{
struct ircomm_cb *self = (struct ircomm_cb *)instance;
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
- ASSERT( skb != NULL, return;);
- DEBUG(0,"ircomm_accept_disconnect_indication:\n");
+ DEBUG(0,__FUNCTION__"():\n");
ircomm_do_event( self, TTP_DISCONNECT_INDICATION, skb);
+
}
-void ircomm_accept_flow_indication( void *instance, void *sap, LOCAL_FLOW cmd){
-
+static void ircomm_accept_flow_indication( void *instance, void *sap,
+ LOCAL_FLOW cmd)
+{
+ IRCOMM_CMD command;
struct ircomm_cb *self = (struct ircomm_cb *)instance;
ASSERT( self != NULL, return;);
@@ -318,73 +369,204 @@ void ircomm_accept_flow_indication( void *instance, void *sap, LOCAL_FLOW cmd){
switch(cmd){
case FLOW_START:
- DEBUG(0,"ircomm_accept_flow_indication:START\n");
-
- self->pi = TX_READY;
+ DEBUG(4,__FUNCTION__"():START\n");
+ command = TX_READY;
self->ttp_stop = 0;
if(self->notify.flow_indication)
self->notify.flow_indication( self->notify.instance,
- self, cmd);
- ircomm_control_request(self);
+ self, command);
break;
case FLOW_STOP:
- DEBUG(0,"ircomm_accept_flow_indication:STOP\n");
- self->pi = TX_BUSY;
+ DEBUG(4,__FUNCTION__":STOP\n");
+ command = TX_BUSY;
self->ttp_stop = 1;
if(self->notify.flow_indication)
self->notify.flow_indication( self->notify.instance,
- self, cmd);
+ self, command);
break;
default:
- DEBUG(0,"ircomm_accept_flow_indication:unknown status!\n");
+ DEBUG(0,__FUNCTION__"();unknown status!\n");
}
}
+
+/*
+ * ircomm_discovery_indication()
+ * Remote device is discovered, try query the remote IAS to see which
+ * device it is, and which services it has.
+ */
+
+static void ircomm_discovery_indication(discovery_t *discovery)
+{
+ struct ircomm_cb *self;
+
+ self = discovering_instance;
+ if(self == NULL)
+ return;
+ ASSERT(self->magic == IRCOMM_MAGIC, return;);
+
+ self->daddr = discovery->daddr;
+ self->saddr = discovery->saddr;
+
+ DEBUG( 0, __FUNCTION__"():daddr=%08x\n", self->daddr);
+
+ ircomm_do_event(self, DISCOVERY_INDICATION, NULL);
+ return;
+}
+
+/*
+ * ircomm_getvalue_confirm()
+ * handler for iriap_getvaluebyclass_request()
+ */
+static void ircomm_getvalue_confirm(int result, __u16 obj_id,
+ struct ias_value *value, void *priv)
+{
+ struct ircomm_cb *self = (struct ircomm_cb *) priv;
+ struct sk_buff *skb= NULL;
+ __u8 *frame;
+ __u8 servicetype = 0 ;
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return;);
+
+ /* Check if request succeeded */
+ if (result != IAS_SUCCESS) {
+ DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ return;
+ }
+
+ DEBUG(4, __FUNCTION__"():type(%d)\n", value->type);
+
+ self->ias_type = value->type;
+ switch(value->type){
+ case IAS_OCT_SEQ:
+
+ DEBUG(4, __FUNCTION__"():got octet sequence:\n");
+#if 0
+ {
+ int i;
+ for ( i=0;i<value->len;i++)
+ printk("%02x",
+ (__u8)(*(value->t.oct_seq + i)));
+ printk("\n");
+ }
+#endif
+ skb = dev_alloc_skb((value->len) + 2);
+ ASSERT(skb != NULL, ircomm_do_event(self, QUERYIAS_ERROR, NULL);return;);
+ frame = skb_put(skb,2);
+ /* MSB first */
+ frame[0] = ( value->len >> 8 ) & 0xff;
+ frame[1] = value->len & 0xff;
+
+ frame = skb_put(skb,value->len);
+ memcpy(frame, value->t.oct_seq, value->len);
+ ircomm_parse_tuples(self, skb, IAS_PARAM);
+ kfree_skb(skb);
+
+ /*
+ * check if servicetype we want is available
+ */
+
+ DEBUG(0,__FUNCTION__"():peer capability is:\n");
+ DEBUG(0,"3wire raw: %s\n",
+ ((self->peer_servicetype & THREE_WIRE_RAW) ? "yes":"no"));
+ DEBUG(0,"3wire : %s\n",
+ ((self->peer_servicetype & THREE_WIRE) ? "yes":"no"));
+ DEBUG(0,"9wire : %s\n",
+ ((self->peer_servicetype & NINE_WIRE) ? "yes":"no"));
+ DEBUG(0,"IEEE1284 : %s\n",
+ ((self->peer_servicetype & CENTRONICS) ? "yes":"no"));
+
+ self->servicetype &= self->peer_servicetype;
+ if(!(self->servicetype)){
+ DEBUG(0,__FUNCTION__"(): servicetype mismatch!\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ break;
+ }
+
+ /*
+ * then choose better one
+ */
+ if(self->servicetype & THREE_WIRE_RAW)
+ servicetype = THREE_WIRE_RAW;
+ if(self->servicetype & THREE_WIRE)
+ servicetype = THREE_WIRE;
+ if(self->servicetype & NINE_WIRE)
+ servicetype = NINE_WIRE;
+ if(self->servicetype & CENTRONICS)
+ servicetype = CENTRONICS;
+
+ self->servicetype = servicetype;
+
+ /* enter next state */
+ ircomm_do_event(self, GOT_PARAMETERS, NULL);
+ break;
+
+ case IAS_INTEGER:
+ /* LsapSel seems to be sent to me */
+ DEBUG(0, __FUNCTION__"():got lsapsel = %d\n", value->t.integer);
+
+ if ( value->t.integer == -1){
+ DEBUG( 0, __FUNCTION__"():invalid value!\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ return;
+ }
+ self->dlsap = value->t.integer;
+ ircomm_do_event(self, GOT_LSAPSEL, NULL);
+ break;
+
+ case IAS_MISSING:
+ DEBUG( 0, __FUNCTION__":got IAS_MISSING\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ break;
+
+ default:
+ DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ break;
+ }
+}
+
+
+
/*
* ----------------------------------------------------------------------
- * Implementation of actions,descrived in section 7.4 of the reference.
+ * Impl. of actions (descrived in section 7.4 of the reference)
* ----------------------------------------------------------------------
*/
-
static void issue_connect_request(struct ircomm_cb *self,
- struct sk_buff *userdata ){
-
+ struct sk_buff *userdata )
+{
/* TODO: we have to send/build userdata field which contains
InitialControlParameters */
- /* but userdata field is not implemeted in irttp.c.. */
switch(self->servicetype){
case THREE_WIRE_RAW:
- /* not implemented yet! Do nothing */
- DEBUG(0, "ircomm:issue_connect_request:"
- "not implemented servicetype!");
+ DEBUG(0, __FUNCTION__"():THREE_WIRE_RAW is not implemented\n");
break;
case DEFAULT:
- irttp_connect_request(self->tsap, self->dlsap, self->daddr,
- NULL, self->maxsdusize, NULL);
- break;
-
case THREE_WIRE:
case NINE_WIRE:
case CENTRONICS:
- irttp_connect_request(self->tsap, self->dlsap, self->daddr,
- NULL, self->maxsdusize, NULL);
+ irttp_connect_request(self->tsap, self->dlsap,
+ self->saddr, self->daddr,
+ NULL, self->maxsdusize, userdata);
break;
default:
- DEBUG(0,"ircomm:issue_connect_request:Illegal servicetype %d\n"
- ,self->servicetype);
+ printk(KERN_ERR __FUNCTION__"():Illegal servicetype %d\n"
+ ,self->servicetype);
}
}
-
-static void disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb){
+static void disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb)
+{
/*
* Not implemented parameter"Reason".That is optional.
@@ -394,12 +576,13 @@ static void disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb){
if(self->notify.disconnect_indication)
self->notify.disconnect_indication( self->notify.instance,
self,
- self->reason,skb);
+ self->reason, skb);
}
static void connect_indication(struct ircomm_cb *self, struct qos_info *qos,
- struct sk_buff *skb){
+ struct sk_buff *skb)
+{
/* If controlparameters don't exist, we use the servicetype"DEFAULT".*/
/* if( !ircomm_parse_controlchannel( self, data)) */
@@ -412,13 +595,16 @@ static void connect_indication(struct ircomm_cb *self, struct qos_info *qos,
#if 0
/* it's for THREE_WIRE_RAW.*/
-static void connect_indication_three_wire_raw(void){
+static void connect_indication_three_wire_raw(void)
+{
DEBUG(0,"ircomm:connect_indication_threewire():not implemented!");
}
#endif
-static void connect_confirmation(struct ircomm_cb *self, struct sk_buff *skb){
+static void connect_confirmation(struct ircomm_cb *self, struct sk_buff *skb)
+{
+ DEBUG(4 ,__FUNCTION__"()\n");
/* give a connect_confirm to the client */
if( self->notify.connect_confirm )
@@ -427,13 +613,13 @@ static void connect_confirmation(struct ircomm_cb *self, struct sk_buff *skb){
}
static void issue_connect_response(struct ircomm_cb *self,
- struct sk_buff *skb ){
+ struct sk_buff *skb)
+{
- DEBUG(0,"ircomm:issue_connect_response:\n");
+ DEBUG(0,__FUNCTION__"()\n");
if( self->servicetype == THREE_WIRE_RAW){
- DEBUG(0,"ircomm:issue_connect_response():3WIRE-RAW is not "
- "implemented yet !\n");
+ DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented yet\n");
/* irlmp_connect_rsp(); */
} else {
irttp_connect_response(self->tsap, self->maxsdusize, skb);
@@ -441,64 +627,91 @@ static void issue_connect_response(struct ircomm_cb *self,
}
static void issue_disconnect_request(struct ircomm_cb *self,
- struct sk_buff *userdata ){
+ struct sk_buff *userdata)
+{
if(self->servicetype == THREE_WIRE_RAW){
- DEBUG(0,"ircomm:issue_disconnect_request():3wireraw is not implemented!");
+ DEBUG(0,__FUNCTION__"():3wireraw is not implemented\n");
}
else
- irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
+ irttp_disconnect_request(self->tsap, userdata,
+ self->disconnect_priority);
}
static void issue_data_request(struct ircomm_cb *self,
- struct sk_buff *userdata ){
+ struct sk_buff *userdata )
+{
int err;
if(self->servicetype == THREE_WIRE_RAW){
/* irlmp_data_request(self->lmhandle,userdata); */
- DEBUG(0,"ircomm:issue_data_request():not implemented!");
+ DEBUG(0,__FUNCTION__"():not implemented!");
return;
}
- DEBUG(4,"ircomm:issue_data_request():sending frame\n");
+ DEBUG(4,__FUNCTION__"():sending frame\n");
err = irttp_data_request(self->tsap , userdata );
- if(err)
- DEBUG(0,"ircomm:ttp_data_request failed\n");
- if(userdata && err)
- dev_kfree_skb( userdata);
-
+ if(err){
+ printk(KERN_ERR __FUNCTION__":ttp_data_request failed\n");
+ if(userdata)
+ dev_kfree_skb( userdata);
+ }
+ self->tx_packets++;
}
static void issue_control_request(struct ircomm_cb *self,
- struct sk_buff *userdata ){
- if(self->servicetype == THREE_WIRE_RAW){
- DEBUG(0,"THREE_WIRE_RAW is not implemented\n");
+ struct sk_buff *userdata )
+{
+ int err;
+
+ DEBUG(4,__FUNCTION__"()\n");
+ if(self->servicetype == THREE_WIRE_RAW)
+ {
+ DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented\n");
- }else {
- irttp_data_request(self->tsap,userdata);
}
-}
+ else
+ {
+ err = irttp_data_request(self->tsap,userdata);
+ if(err)
+ {
+ printk( __FUNCTION__"():ttp_data_request failed\n");
+ if(userdata)
+ dev_kfree_skb( userdata);
+ }
+ else
+ self->tx_controls++;
+ self->pending_control_tuples = 0;
+ }
+}
-static void process_data(struct ircomm_cb *self, struct sk_buff *skb ){
+static void process_data(struct ircomm_cb *self, struct sk_buff *skb )
+{
- DEBUG(4,"ircomm:process_data:skb_len is(%d),clen_is(%d)\n",
+ DEBUG(4,__FUNCTION__":skb->len=%d, ircomm header = 1, clen=%d\n",
(int)skb->len ,(int)skb->data[0]);
- /*
- * we always have to parse control channel
- * (see page17 of IrCOMM standard)
+ /* we have to parse control channel when receiving. (see
+ * page17 of IrCOMM standard) but it is not parsed here since
+ * upper layer may have some receive buffer.
+ *
+ * hence upper layer have to parse it when it consumes a packet.
+ * -- TH
*/
- ircomm_parse_control(self, skb, CONTROL_CHANNEL);
+ /* ircomm_parse_control(self, skb, CONTROL_CHANNEL); */
if(self->notify.data_indication && skb->len)
self->notify.data_indication(self->notify.instance, self,
skb);
}
-void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb){
+int ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
+{
/* Not implemented yet:THREE_WIRE_RAW service uses this function. */
DEBUG(0,"ircomm_data_indication:not implemented yet!\n");
+
+ return 0;
}
@@ -510,45 +723,38 @@ void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb){
*/
static void ircomm_do_event( struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb) {
+ struct sk_buff *skb)
+{
- DEBUG( 4, "ircomm_do_event: STATE = %s, EVENT = %s\n",
+ DEBUG( 4, __FUNCTION__": STATE = %s, EVENT = %s\n",
ircommstate[self->state], ircommevent[event]);
(*state[ self->state ]) ( self, event, skb);
}
-void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state) {
+static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state)
+{
self->state = state;
- DEBUG( 0, "ircomm_next_state: NEXT STATE = %d(%s), sv(%d)\n",
+ DEBUG( 0, __FUNCTION__": NEXT STATE=%d(%s), servicetype=(%d)\n",
(int)state, ircommstate[self->state],self->servicetype);
}
-/*
- * we currently need dummy (discovering) state for debugging,
- * which state is not defined in the reference.
- */
-
-static void ircomm_state_discovery( struct ircomm_cb *self,
- IRCOMM_EVENT event, struct sk_buff *skb ){
- DEBUG(0,"ircomm_state_discovery: "
- "why call me? \n");
- if(skb)
- dev_kfree_skb( skb);
-}
-
/*
* ircomm_state_idle
*/
static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb ){
+ struct sk_buff *skb )
+{
switch(event){
case IRCOMM_CONNECT_REQUEST:
- ircomm_next_state(self, COMM_WAITI);
- issue_connect_request( self, skb );
+ /* ircomm_next_state(self, COMM_WAITI); */
+ /* issue_connect_request( self, skb ); */
+
+ ircomm_next_state(self, COMM_DISCOVERY_WAIT);
+ start_discovering(self);
break;
case TTP_CONNECT_INDICATION:
@@ -559,15 +765,128 @@ static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
case LMP_CONNECT_INDICATION:
- /* I think this is already done in irlpt_event.c */
-
- DEBUG(0,"ircomm_state_idle():LMP_CONNECT_IND is notimplemented!");
+ DEBUG(0,__FUNCTION__"():LMP_CONNECT_IND is notimplemented!");
/* connect_indication_three_wire_raw(); */
/* ircomm_next_state(self, COMM_WAITR); */
break;
default:
- DEBUG(0,"ircomm_state_idle():unknown event =%d(%s)\n",
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+ event, ircommevent[event]);
+ }
+}
+
+/*
+ * ircomm_state_discoverywait
+ */
+static void ircomm_state_discoverywait(struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb )
+{
+ switch(event){
+
+ case TTP_CONNECT_INDICATION:
+
+ ircomm_next_state(self, COMM_WAITR);
+ queryias_done(self);
+ connect_indication( self, self->qos, skb);
+ break;
+
+ case DISCOVERY_INDICATION:
+ ircomm_next_state(self, COMM_QUERYPARAM_WAIT);
+ query_parameters(self);
+ break;
+
+ case IRCOMM_DISCONNECT_REQUEST:
+ ircomm_next_state(self, COMM_IDLE);
+ queryias_done(self);
+ break;
+
+ case QUERYIAS_ERROR:
+ ircomm_next_state(self, COMM_IDLE);
+ disconnect_indication(self, NULL);
+ queryias_done(self);
+ break;
+
+ default:
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+ event, ircommevent[event]);
+ }
+}
+
+/*
+ * ircomm_state_queryparamwait
+ */
+
+static void ircomm_state_queryparamwait(struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb )
+{
+ switch(event){
+
+ case TTP_CONNECT_INDICATION:
+
+ ircomm_next_state(self, COMM_WAITR);
+ connect_indication( self, self->qos, skb);
+ break;
+
+ case GOT_PARAMETERS:
+
+ ircomm_next_state(self, COMM_QUERYLSAP_WAIT);
+ query_lsapsel( self );
+ break;
+
+ case IRCOMM_DISCONNECT_REQUEST:
+ ircomm_next_state(self, COMM_IDLE);
+ queryias_done(self);
+ break;
+
+ case QUERYIAS_ERROR:
+ ircomm_next_state(self, COMM_IDLE);
+ disconnect_indication(self, NULL);
+ queryias_done(self);
+ break;
+
+ default:
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+ event, ircommevent[event]);
+ }
+}
+
+/*
+ * ircomm_state_querylsapwait
+ */
+
+static void ircomm_state_querylsapwait(struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb )
+{
+ switch(event){
+
+ case TTP_CONNECT_INDICATION:
+
+ ircomm_next_state(self, COMM_WAITR);
+ connect_indication( self, self->qos, skb);
+ break;
+
+ case GOT_LSAPSEL:
+
+ ircomm_next_state(self, COMM_WAITI);
+ queryias_done(self);
+ issue_connect_request( self, skb );
+ break;
+
+ case IRCOMM_DISCONNECT_REQUEST:
+ ircomm_next_state(self, COMM_IDLE);
+ queryias_done(self);
+ break;
+
+ case QUERYIAS_ERROR:
+ ircomm_next_state(self, COMM_IDLE);
+ disconnect_indication(self, NULL);
+ queryias_done(self);
+ break;
+
+
+ default:
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
event, ircommevent[event]);
}
}
@@ -577,7 +896,8 @@ static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
*/
static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb ){
+ struct sk_buff *skb )
+{
switch(event){
case TTP_CONNECT_CONFIRM:
ircomm_next_state(self, COMM_CONN);
@@ -596,7 +916,7 @@ static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
/* ircomm_next_state(self, COMM_IDLE); */
/* break; */
default:
- DEBUG(0,"ircomm_state_waiti:unknown event =%d(%s)\n",
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
event, ircommevent[event]);
}
}
@@ -607,7 +927,8 @@ static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
* ircomm_state_waitr
*/
static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb ) {
+ struct sk_buff *skb )
+{
switch(event){
case IRCOMM_CONNECT_RESPONSE:
@@ -615,8 +936,7 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
/* issue_connect_response */
if(self->servicetype==THREE_WIRE_RAW){
- DEBUG(0,"ircomm:issue_connect_response:"
- "THREE_WIRE_RAW is not implemented!\n");
+ DEBUG(0,__FUNCTION__"():3WIRE_RAW is not implemented\n");
/* irlmp_connect_response(Vpeersap,
* ACCEPT,null);
*/
@@ -629,6 +949,7 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
case IRCOMM_DISCONNECT_REQUEST:
ircomm_next_state(self, COMM_IDLE);
issue_disconnect_request(self, skb);
+ queryias_done(self);
break;
case TTP_DISCONNECT_INDICATION:
@@ -636,6 +957,19 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
disconnect_indication(self, skb);
break;
+ case DISCOVERY_INDICATION:
+ DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
+ queryias_done(self);
+ break;
+ case GOT_PARAMETERS:
+ DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
+ queryias_done(self);
+ break;
+ case GOT_LSAPSEL:
+ DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
+ queryias_done(self);
+ break;
+
/* case LMP_DISCONNECT_INDICATION: */
/* disconnect_indication(); */
/* ircomm_next_state(self, COMM_IDLE); */
@@ -651,23 +985,20 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
*/
static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb ){
+ struct sk_buff *skb )
+{
switch(event){
case TTP_DATA_INDICATION:
process_data(self, skb);
- /* stay CONN state*/
break;
case IRCOMM_DATA_REQUEST:
issue_data_request(self, skb);
- /* stay CONN state*/
break;
/* case LMP_DATA_INDICATION: */
/* ircomm_data_indicated(); */
-/* stay CONN state */
/* break; */
case IRCOMM_CONTROL_REQUEST:
issue_control_request(self, skb);
- /* stay CONN state*/
break;
case TTP_DISCONNECT_INDICATION:
ircomm_next_state(self, COMM_IDLE);
@@ -676,11 +1007,26 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
case IRCOMM_DISCONNECT_REQUEST:
ircomm_next_state(self, COMM_IDLE);
issue_disconnect_request(self, skb);
+ queryias_done(self);
break;
/* case LM_DISCONNECT_INDICATION: */
/* disconnect_indication(); */
/* ircomm_next_state(self, COMM_IDLE); */
/* break; */
+
+ case DISCOVERY_INDICATION:
+ DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
+ queryias_done(self);
+ break;
+ case GOT_PARAMETERS:
+ DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
+ queryias_done(self);
+ break;
+ case GOT_LSAPSEL:
+ DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
+ queryias_done(self);
+ break;
+
default:
DEBUG(0,"ircomm_state_conn:unknown event =%d(%s)\n",
event, ircommevent[event]);
@@ -688,16 +1034,116 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
}
+
/*
* ----------------------------------------------------------------------
- * ircomm requests
+ * IrCOMM service interfaces and supporting functions
*
* ----------------------------------------------------------------------
*/
+/*
+ * start_discovering()
+ *
+ * start discovering and enter DISCOVERY_WAIT state
+ */
+
+static void start_discovering(struct ircomm_cb *self)
+{
+ __u16 hints;
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return;);
+ DEBUG(4,__FUNCTION__"():servicetype = %d\n",self->servicetype);
+
+
+ hints = irlmp_service_to_hint(S_COMM);
+
+ DEBUG(0,__FUNCTION__"():start discovering..\n");
+ switch (ircomm_cs) {
+ case 0:
+ MOD_INC_USE_COUNT;
+ self->queryias_lock = 1;
+ discovering_instance = self;
+ self->skey = irlmp_register_service(hints);
+ self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+ NULL);
+ break;
+
+ case 1: /* client only */
+ MOD_INC_USE_COUNT;
+ self->queryias_lock = 1;
+ discovering_instance = self;
+ DEBUG( 0, __FUNCTION__"():client only mode\n");
+ self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+ NULL);
+ break;
+
+ case 2: /* server only */
+ default:
+ DEBUG( 0, __FUNCTION__"():server only mode\n");
+ self->skey = irlmp_register_service(hints);
+ discovering_instance = NULL;
+ break;
+ }
+
+ return;
+}
+
+/*
+ * queryias_done(self)
+ *
+ * called when discovery process got wrong results, completed, or terminated.
+ */
+
+static void queryias_done(struct ircomm_cb *self)
+{
+ DEBUG(0, __FUNCTION__"():\n");
+ if(self->queryias_lock){
+ self->queryias_lock = 0;
+ discovering_instance = NULL;
+ MOD_DEC_USE_COUNT;
+ irlmp_unregister_client(self->ckey);
+ }
+ if(ircomm_cs != 1)
+ irlmp_unregister_service(self->skey);
+ return;
+}
+
+
+
+static void query_parameters(struct ircomm_cb *self)
+{
+
+ DEBUG(0, __FUNCTION__"():querying IAS: Parameters..\n");
+ iriap_getvaluebyclass_request( "IrDA:IrCOMM", "Parameters",
+ self->saddr, self->daddr,
+ ircomm_getvalue_confirm, self );
+}
+
+
+static void query_lsapsel(struct ircomm_cb * self)
+{
+ DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
-void ircomm_connect_request(struct ircomm_cb *self, int maxsdusize){
+ if (!(self->servicetype & THREE_WIRE_RAW)) {
+ iriap_getvaluebyclass_request(
+ "IrDA:IrCOMM", "IrDA:TinyTP:LsapSel",
+ self->saddr, self->daddr,
+ ircomm_getvalue_confirm, self );
+ } else {
+ DEBUG(0, __FUNCTION__ "THREE_WIRE_RAW is not implemented!\n");
+ }
+}
+/*
+ * ircomm_connect_request()
+ * Impl. of this function is differ from one of the reference.
+ * This functin does discovery as well as sending connect request
+ */
+
+
+void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype)
+{
/*
* TODO:build a packet which contains "initial control parameters"
* and send it with connect_request
@@ -706,14 +1152,19 @@ void ircomm_connect_request(struct ircomm_cb *self, int maxsdusize){
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
- DEBUG(0,"ircomm_connect_request:\n");
- self->maxsdusize = maxsdusize;
+ DEBUG(0, __FUNCTION__"():sending connect_request...\n");
+
+ self->servicetype= servicetype;
+ /* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/
+
+ self->maxsdusize = SAR_DISABLE;
ircomm_do_event( self, IRCOMM_CONNECT_REQUEST, NULL);
}
void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
- int maxsdusize){
+ __u32 maxsdusize)
+{
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
@@ -729,11 +1180,8 @@ void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
if(!userdata){
/* FIXME: check for errors and initialize? DB */
userdata = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
- if(!userdata){
- DEBUG(0, __FUNCTION__"alloc_skb failed\n");
- return;
- }
- IS_SKB(userdata, return;);
+ ASSERT(userdata != NULL, return;);
+
skb_reserve(userdata,COMM_HEADER_SIZE);
}
@@ -746,31 +1194,73 @@ void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata);
}
-void ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata){
+void ircomm_disconnect_request(struct ircomm_cb *self,
+ struct sk_buff *userdata,
+ int priority)
+{
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
+ DEBUG(0,__FUNCTION__"()\n");
+
+#if 0
+ /* unregister layer */
+ switch (ircomm_cs) {
+ case 1: /* client only */
+ irlmp_unregister_client(ckey);
+ break;
+
+ case 2: /* server only */
+ irlmp_unregister_service(skey);
+ break;
+ case 0:
+ default:
+ irlmp_unregister_client(ckey);
+ irlmp_unregister_service(skey);
+ break;
+ }
+#endif
+
+ self->disconnect_priority = priority;
+ if(priority != P_HIGH)
+ self->disconnect_priority = P_NORMAL;
- DEBUG(0,"ircomm_disconnect_request\n");
- ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL);
+ ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata);
}
-void ircomm_data_request(struct ircomm_cb *self, struct sk_buff *userdata){
+int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *userdata)
+{
+ __u8 * frame;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == IRCOMM_MAGIC, return;);
- ASSERT( userdata != NULL, return;);
+ DEBUG(4,__FUNCTION__"()\n");
+ ASSERT( self != NULL, return -EFAULT;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return -EFAULT;);
+ ASSERT( userdata != NULL, return -EFAULT;);
+
if(self->state != COMM_CONN){
- DEBUG(4,"ignore IRCOMM_DATA_REQUEST:not connected\n");
- if(userdata)
- dev_kfree_skb(userdata);
- return;
+ DEBUG(4,__FUNCTION__"():not connected, data is ignored\n");
+ return -EINVAL;
}
- DEBUG(4,"ircomm_data_request\n");
+ if(self->ttp_stop)
+ return -EBUSY;
+
+ if(self->control_ch_pending){
+ /* send control_channel */
+ ircomm_tx_controlchannel(self);
+ }
+
+ if(self->ttp_stop)
+ return -EBUSY;
+
+ /* add "clen" field */
+ frame = skb_push(userdata,1);
+ frame[0]=0; /* without control channel */
+
ircomm_do_event(self, IRCOMM_DATA_REQUEST, userdata);
+ return 0;
}
/*
@@ -780,19 +1270,25 @@ void ircomm_data_request(struct ircomm_cb *self, struct sk_buff *userdata){
* ----------------------------------------------------------------------
*/
-static void ircomm_tx_ctrlbuffer(struct ircomm_cb *self ){
+
+static void ircomm_tx_controlchannel(struct ircomm_cb *self )
+{
__u8 clen;
struct sk_buff *skb = self->ctrl_skb;
- DEBUG(4,"ircomm_tx_ctrlbuffer:\n");
+ DEBUG(4,__FUNCTION__"()\n");
+ /* 'self' should have been checked */
+ ASSERT(!self->ttp_stop, return ;);
+ ASSERT(self->state == COMM_CONN, return ;);
/* add "clen" field */
clen=skb->len;
- if(clen){
- skb_push(skb,1);
- skb->data[0]=clen;
+ ASSERT(clen != 0,return;);
+
+ skb_push(skb,1);
+ skb->data[0]=clen;
#if 0
printk("tx_ctrl:");
@@ -803,145 +1299,106 @@ static void ircomm_tx_ctrlbuffer(struct ircomm_cb *self ){
printk("\n");
}
#endif
-
- ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb);
-
- skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
- if (skb==NULL){
- DEBUG(0,"ircomm_tx_ctrlbuffer:alloc_skb failed!\n");
- return;
- }
- skb_reserve(skb,COMM_HEADER_SIZE);
- self->ctrl_skb = skb;
- }
-}
-
-
-void ircomm_control_request(struct ircomm_cb *self){
- struct sk_buff *skb;
+ ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb);
+ self->control_ch_pending = 0;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == IRCOMM_MAGIC, return;);
+ skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+ ASSERT(skb != NULL, return ;);
- DEBUG(0, "ircomm_control_request:\n");
-
- if(self->ttp_stop || self->state != COMM_CONN){
- DEBUG(0,"ircomm_control_request:can't send it.. ignore it\n");
- return;
- }
-
- skb = self->ctrl_skb;
- IS_SKB(skb,return;);
-
- if(skb->len)
- ircomm_tx_ctrlbuffer(self);
+ skb_reserve(skb,COMM_HEADER_SIZE);
+ self->ctrl_skb = skb;
}
-static void append_tuple(struct ircomm_cb *self,
- __u8 instruction, __u8 pl , __u8 *value){
-
+static void append_tuple(struct ircomm_cb *self, __u8 instruction, __u8 pl ,
+ __u8 *value)
+{
__u8 *frame;
struct sk_buff *skb;
- int i,c;
+ int i,c = 0;
+ unsigned long flags;
+
+ save_flags(flags);cli();
skb = self->ctrl_skb;
ASSERT(skb != NULL, return;);
- IS_SKB(skb,return;);
- /*if there is little room in the packet... */
-
- if(skb->len > COMM_DEFAULT_DATA_SIZE - COMM_HEADER_SIZE - (pl+2)){
- if(!self->ttp_stop && self->state == COMM_CONN){
-
- /* send a packet if we can */
- ircomm_tx_ctrlbuffer(self);
- skb = self->ctrl_skb;
- } else {
- DEBUG(0, "ircomm_append_ctrl:there's no room.. ignore it\n");
-
- /* TODO: we have to detect whether we have to resend some
- information after ttp_stop is cleared */
-
- /* self->resend_ctrl = 1; */
- return;
- }
+ if(skb_tailroom(skb) < (pl+2)){
+ DEBUG(0, __FUNCTION__"there's no room.. ignore it\n");
+ self->ignored_control_tuples++;
+ restore_flags(flags);
+ return;
}
frame = skb_put(skb,pl+2);
- c = 0;
frame[c++] = instruction; /* PI */
frame[c++] = pl; /* PL */
for(i=0; i < pl ; i++)
frame[c++] = *value++; /* PV */
-
+ restore_flags(flags);
+ self->pending_control_tuples++;
+ self->control_ch_pending = 1;
}
/*
- * ircomm_append_ctrl();
+ * ircomm_control_request();
* this function is exported as a request to send some control-channel tuples
* to peer device
*/
-void ircomm_append_ctrl(struct ircomm_cb *self, __u8 instruction){
+void ircomm_control_request(struct ircomm_cb *self, __u8 instruction)
+{
- __u8 pv[70];
+ __u8 pv[32]; /* 32 max, for PORT_NAME */
__u8 *value = &pv[0];
__u32 temp;
+ int notsupp=0;
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
- if(self->state != COMM_CONN)
- return;
-
if(self->servicetype == THREE_WIRE_RAW){
- DEBUG(0,"THREE_WIRE_RAW shuold not use me!\n");
+ DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW shuold not use me!\n");
return;
}
- DEBUG(4,"ircomm_append_ctrl:\n");
+ DEBUG(4,__FUNCTION__"()\n");
/* find parameter and its length */
- switch(instruction){
+ if(self->servicetype == THREE_WIRE) goto threewire;
+ if(self->servicetype == NINE_WIRE) goto ninewire;
- case POLL_FOR_LINE_SETTINGS:
- case STATUS_QUERY:
+
+ /* FIXME: centronics service is not fully implemented yet*/
+ switch(instruction){
case IEEE1284_MODE_SUPPORT:
case IEEE1284_DEVICEID:
append_tuple(self,instruction,0,NULL);
break;
-
- case SERVICETYPE:
- value[0] = self->servicetype;
- append_tuple(self,instruction,1,value);
+ case STATUS_QUERY:
+ append_tuple(self,instruction,0,NULL);
break;
- case DATA_FORMAT:
- value[0] = self->data_format;
+ case SET_BUSY_TIMEOUT:
+ value[0] = self->busy_timeout;
append_tuple(self,instruction,1,value);
break;
- case FLOW_CONTROL:
- if(self->null_modem_mode){
+ case IEEE1284_ECP_EPP_DATA_TRANSFER:
+ value[0] = self->ecp_epp_mode;
+ value[1] = self->channel_or_addr;
+ append_tuple(self,instruction,2,value);
+ break;
+ default:
+ notsupp=1;
+ }
- /* inside out */
- value[0] = (self->flow_ctrl & 0x55) << 1;
- value[0] |= (self->flow_ctrl & 0xAA) >> 1;
- }else{
- value[0] = self->flow_ctrl;
- }
- append_tuple(self,instruction,1,value);
- break;
- case LINESTATUS:
- value[0] = self->line_status;
- append_tuple(self,instruction,1,value);
- break;
- case BREAK_SIGNAL:
- value[0] = self->break_signal;
- append_tuple(self,instruction,1,value);
+ ninewire:
+ switch(instruction){
+ case POLL_FOR_LINE_SETTINGS:
+ append_tuple(self,instruction,0,NULL);
break;
case DTELINE_STATE:
if(self->null_modem_mode){
@@ -972,8 +1429,42 @@ void ircomm_append_ctrl(struct ircomm_cb *self, __u8 instruction){
value[0] = self->dce;
append_tuple(self,instruction,1,value);
break;
- case SET_BUSY_TIMEOUT:
- value[0] = self->busy_timeout;
+
+ default:
+ notsupp=1;
+ }
+
+ threewire:
+ switch(instruction){
+
+ case SERVICETYPE:
+ value[0] = self->servicetype;
+ append_tuple(self,instruction,1,value);
+ break;
+
+ case DATA_FORMAT:
+ value[0] = self->data_format;
+ append_tuple(self,instruction,1,value);
+ break;
+
+ case FLOW_CONTROL:
+ if(self->null_modem_mode){
+ /* inside out */
+ value[0] = (self->flow_ctrl & 0x55) << 1;
+ value[0] |= (self->flow_ctrl & 0xAA) >> 1;
+ }else{
+ value[0] = self->flow_ctrl;
+ }
+ append_tuple(self,instruction,1,value);
+ break;
+
+ case LINESTATUS:
+ value[0] = self->line_status;
+ append_tuple(self,instruction,1,value);
+ break;
+
+ case BREAK_SIGNAL:
+ value[0] = self->break_signal;
append_tuple(self,instruction,1,value);
break;
@@ -989,12 +1480,6 @@ void ircomm_append_ctrl(struct ircomm_cb *self, __u8 instruction){
append_tuple(self,instruction,2,value);
break;
- case IEEE1284_ECP_EPP_DATA_TRANSFER:
- value[0] = self->ecp_epp_mode;
- value[1] = self->channel_or_addr;
- append_tuple(self,instruction,2,value);
- break;
-
case DATA_RATE:
temp = self->data_rate;
value[3] = (__u8)((temp >> 24) & 0x000000ff);
@@ -1003,202 +1488,300 @@ void ircomm_append_ctrl(struct ircomm_cb *self, __u8 instruction){
value[0] = (__u8)(temp & 0x000000ff);
append_tuple(self,instruction,4,value);
break;
-
#if 0
case PORT_NAME:
case FIXED_PORT_NAME:
temp = strlen(&self->port_name);
- if(temp < 70){
+ if(temp < 32){
value = (__u8) (self->port_name);
append_tuple(self,instruction,temp,value);
- }
- break;
+ }else
+ DEBUG(0,__FUNCTION__"() PORT_NAME:too long\n");
#endif
-
-/* TODO: control tuples for centronics emulation is not implemented */
-/* case IEEE1284_MODE: */
+ break;
default:
- DEBUG(0,"ircomm_append_ctrl:instruction(0x%02x)is not"
- "implemented\n",instruction);
+ if(notsupp)
+ DEBUG(0,__FUNCTION__"():instruction(0x%02x)is not"
+ "implemented\n",instruction);
}
}
-static void ircomm_parse_control(struct ircomm_cb *self,
- struct sk_buff *skb,
- int type){
+void ircomm_parse_tuples(struct ircomm_cb *self, struct sk_buff *skb, int type)
+{
__u8 *data;
- __u8 pi,pl,pv[64];
+ __u8 pi,plen;
int clen = 0;
- int i,indicate,count = 0;
+ int indicate=0;
-
- data = skb->data;
- if(type == IAS_PARAM)
- clen = ((data[count++] << 8) & data[count++]); /* MSB first */
- else /* CONTROL_CHANNEL */
- clen = data[count++];
+ ASSERT(skb != NULL, return;);
+ ASSERT(self != NULL, return ;);
+ ASSERT(self->magic == IRCOMM_MAGIC, return ;);
- if(clen == 0){
- skb_pull( skb, 1); /* remove clen field */
- return;
+#ifdef IRCOMM_DEBUG_TUPLE
+ DEBUG(0, __FUNCTION__"():tuple sequence is:\n");
+ {
+ int i;
+ for ( i=0;i< skb->len;i++)
+ printk("%02x", (__u8)(skb->data[i]));
+ printk("\n");
}
+#endif
+ data = skb->data;
+ if(type == IAS_PARAM)
+ {
+ clen = (data[0] << 8) & 0xff00;
+ clen |= data[1] & 0x00ff;
+ ASSERT( clen <= (skb->len - 2) && clen <= 1024, goto corrupted;);
+ DEBUG(4, __FUNCTION__"():IAS_PARAM len = %d\n",clen );
+ skb_pull( skb, 2);
+ }
+ else
+ {
+ /* CONTROL_CHANNEL */
+ clen = data[0];
+ ASSERT( clen < skb->len, goto corrupted;);
+ DEBUG(4, __FUNCTION__"():CONTROL_CHANNEL:len = %d\n",clen );
+ skb_pull( skb, 1);
+ }
+ while( clen >= 2 ){
+ data = skb->data;
+ indicate = 0;
-
- while( count < clen ){
/*
* parse controlparameters and set value into structure
*/
- pi = data[count++];
- pl = data[count++];
-
- DEBUG(0, "parse_control:instruction(0x%02x)\n",pi) ;
+ pi = data[0];
+ plen = data[1];
+ ASSERT( clen >= 2+plen, goto corrupted; );
+ DEBUG(4, __FUNCTION__"():instruction=0x%02x,len=%d\n",
+ pi, plen) ;
- /* copy a tuple into pv[] */
-#ifdef IRCOMM_DEBUG_TUPLE
- printk("data:");
- for(i=0; i < pl; i++){
- pv[i] = data[count++];
- printk("%02x",pv[i]);
- }
- printk("\n");
-#else
- for(i=0; i < pl; i++)
- pv[i] = data[count++];
-#endif
+ switch(pi)
+ {
+ case POLL_FOR_LINE_SETTINGS:
+ ircomm_control_request(self, DTELINE_STATE);
+ break;
-
- /* parse pv */
- indicate = 0;
-
- switch(pi){
-
- /*
- * for 3-wire/9-wire/centronics
- */
-
case SERVICETYPE:
- self->peer_servicetype = pv[0];
+ self->peer_servicetype = data[2];
break;
+
case PORT_TYPE:
- self->peer_port_type = pv[0];
- break;
-#if 0
- case PORT_NAME:
- self->peer_port_name = *pv;
- break;
- case FIXED_PORT_NAME:
- self->peer_port_name = *pv;
- /*
- * We should not connect if user of IrCOMM can't
- * recognize the port name
- */
- self->port_name_critical = TRUE;
- break;
-#endif
- case DATA_RATE:
- self->peer_data_rate = (pv[3]<<24) & (pv[2]<<16)
- & (pv[1]<<8) & pv[0];
- indicate = 1;
+ self->peer_port_type = data[2];
break;
+
case DATA_FORMAT:
- self->peer_data_format = pv[0];
+ self->peer_data_format = data[2];
break;
+
case FLOW_CONTROL:
- self->peer_flow_ctrl = pv[0];
- indicate = 1;
- break;
- case XON_XOFF_CHAR:
- self->peer_xon_char = pv[0];
- self->peer_xoff_char = pv[1];
- indicate = 1;
- break;
- case ENQ_ACK_CHAR:
- self->peer_enq_char = pv[0];
- self->peer_ack_char = pv[1];
+ self->peer_flow_ctrl = data[2];
indicate = 1;
break;
+
case LINESTATUS:
- self->peer_line_status = pv[0];
+ self->peer_line_status = data[2];
indicate = 1;
break;
+
case BREAK_SIGNAL:
- self->peer_break_signal = pv[0];
+ self->peer_break_signal = data[2];
/* indicate = 1; */
break;
-
- /*
- * for 9-wire
- */
+
+ case DCELINE_STATE:
+ self->peer_dce = data[2];
+ indicate = 1;
+ break;
case DTELINE_STATE:
if(self->null_modem_mode){
/* input DTR as {DSR & CD & RI} */
self->peer_dce = 0;
- if(pv[0] & DELTA_DTR)
- self->peer_dce |= DELTA_DSR|DELTA_RI|DELTA_DCD;
- if(pv[0] & MCR_DTR)
- self->peer_dce |= MSR_DSR|MSR_RI|MSR_DCD;
-
+ if(data[2] & DELTA_DTR)
+ self->peer_dce |= (DELTA_DSR|
+ DELTA_RI|
+ DELTA_DCD);
+ if(data[2] & MCR_DTR)
+ self->peer_dce |= (MSR_DSR|
+ MSR_RI|
+ MSR_DCD);
/* rts as cts */
- if(pv[0] & DELTA_RTS)
+ if(data[2] & DELTA_RTS)
self->peer_dce |= DELTA_CTS;
- if(pv[0] & MCR_RTS)
+ if(data[2] & MCR_RTS)
self->peer_dce |= MSR_CTS;
}else{
- self->peer_dte = pv[0];
+ self->peer_dte = data[2];
}
indicate = 1;
break;
+
+ case XON_XOFF_CHAR:
+ self->peer_xon_char = data[2];
+ self->peer_xoff_char = data[3];
+ indicate = 1;
+ break;
- case DCELINE_STATE:
- self->peer_dce = pv[0];
+ case ENQ_ACK_CHAR:
+ self->peer_enq_char = data[2];
+ self->peer_ack_char = data[3];
indicate = 1;
break;
- case POLL_FOR_LINE_SETTINGS:
- ircomm_append_ctrl(self, DTELINE_STATE);
- ircomm_control_request(self);
+ case DATA_RATE:
+ self->peer_data_rate = ( data[5]<<24
+ & data[4]<<16
+ & data[3]<<8
+ & data[2]);
+ indicate = 1;
break;
- /*
- * for centronics .... not implemented yet
+ case PORT_NAME:
+ ASSERT(plen <= 32 , goto corrupted;);
+ memcpy(self->port_name, data + 2, plen);
+ *(__u8 *)(self->port_name+plen) = 0;
+ break;
+
+ case FIXED_PORT_NAME:
+ ASSERT(plen <= 32 , goto corrupted;);
+ memcpy(self->port_name, data + 2, plen);
+ *(__u8 *)(self->port_name+plen) = 0;
+ /*
+ * We should not connect if user of IrCOMM can't
+ * recognize the port name
*/
-/* case STATUS_QUERY: */
-/* case SET_BUSY_TIMEOUT: */
-/* case IEEE1284_MODE_SUPPORT: */
-/* case IEEE1284_DEVICEID: */
-/* case IEEE1284_MODE: */
-/* case IEEE1284_ECP_EPP_DATA_TRANSFER: */
-
- default:
- DEBUG(0, "ircomm_parse_control:not implemented "
- "instruction(%d)\n", pi);
+ self->port_name_critical = TRUE;
break;
+
+ default:
+ DEBUG(0, __FUNCTION__
+ "():not implemented (PI=%d)\n", pi);
}
- if(indicate && self->notify.flow_indication
- && type == CONTROL_CHANNEL){
-
- DEBUG(0,"ircomm:parse_control:indicating..:\n");
+
+ if(indicate &&
+ self->notify.flow_indication && type == CONTROL_CHANNEL)
+ {
+ DEBUG(4,__FUNCTION__":indicating..:\n");
self->pi = pi;
if(self->notify.flow_indication)
- self->notify.flow_indication(self->notify.instance, self, 0);
- indicate = 0;
+ self->notify.flow_indication(self->notify.instance,
+ self,
+ CONTROL_CHANNEL);
}
+ skb_pull(skb, 2+plen);
+ clen -= (2+plen);
}
- skb_pull( skb, 1+clen);
+
return;
+
+ corrupted:
+ skb_pull(skb, skb->len); /* remove suspicious data */
+ return;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * Function ircomm_open_instance() ,ircomm_close_instance() and friends
+ *
+ * ircomm_open_instance discoveres the peer device and then issues a
+ * connect request
+ * ----------------------------------------------------------------------
+ */
+
+
+
+struct ircomm_cb * ircomm_open_instance( struct notify_t client_notify)
+{
+ int i;
+ struct ircomm_cb *self = NULL;
+ struct notify_t notify;
+ unsigned long flags;
+
+ ASSERT(ircomm != NULL,return NULL;);
+ DEBUG(0,__FUNCTION__"():\n");
+
+ /* find free handle */
+
+ save_flags(flags);
+ cli();
+ for(i = 0; i < IRCOMM_MAX_CONNECTION; i++){
+ ASSERT(ircomm[i] != NULL,return(NULL););
+ if(!ircomm[i]->in_use){
+ self = ircomm[i];
+ break;
+ }
+ }
+
+ if (!self){
+ DEBUG(0,__FUNCTION__"():no free handle!\n");
+ return (NULL);
+ }
+
+ self->in_use = 1;
+ restore_flags(flags);
+
+ self->notify = client_notify;
+ self->ttp_stop = 0;
+ self->control_ch_pending = 0;
+
+ /* register callbacks */
+
+ irda_notify_init(&notify);
+ notify.data_indication = ircomm_accept_data_indication;
+ notify.connect_confirm = ircomm_accept_connect_confirm;
+ notify.connect_indication = ircomm_accept_connect_indication;
+ notify.flow_indication = ircomm_accept_flow_indication;
+ notify.disconnect_indication = ircomm_accept_disconnect_indication;
+ notify.instance = self;
+ strncpy( notify.name, "IrCOMM", NOTIFY_MAX_NAME);
+
+ self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
+ &notify);
+ if(!self->tsap){
+ DEBUG(0,__FUNCTION__"failed to allocate tsap\n");
+ return NULL;
+ }
+
+ ircomm_next_state(self, COMM_IDLE);
+ return (self);
}
+int ircomm_close_instance(struct ircomm_cb *self)
+{
+ ASSERT( self != NULL, return -EIO;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return -EIO;);
+ ASSERT( self->ctrl_skb != NULL, return -EIO;);
+
+ DEBUG(0,__FUNCTION__"()\n");
+
+ /* shutdown ircomm layer */
+ if(self->state != COMM_IDLE && self->state != COMM_WAITI)
+ {
+ DEBUG(0,__FUNCTION__"():force disconnecting..\n");
+ ircomm_disconnect_request(self, NULL, P_HIGH);
+ }
+
+ skb_trim(self->ctrl_skb,0);
+ /* remove a tsap */
+ if(self->tsap)
+ irttp_close_tsap(self->tsap);
+ self->tsap = NULL;
+ self->in_use = 0;
+ return 0;
+}
+
+
/*
* ----------------------------------------------------------------------
* Function init_module(void) ,cleanup_module()
@@ -1209,20 +1792,21 @@ static void ircomm_parse_control(struct ircomm_cb *self,
*/
#ifdef MODULE
+int init_module(void)
+{
+ int err;
-int init_module(void) {
- ircomm_init();
+ err = ircomm_init();
- DEBUG( 4, "ircomm:init_module:done\n");
- return 0;
+ DEBUG( 4, __FUNCTION__"():done.\n");
+ return err;
}
void cleanup_module(void)
{
ircomm_cleanup();
- DEBUG( 0, "ircomm_common:cleanup_module:done.\n");
+ DEBUG( 4, __FUNCTION__"():done.\n");
}
-
#endif /* MODULE */
/************************************************************
@@ -1238,53 +1822,92 @@ void cleanup_module(void)
*
*/
int ircomm_proc_read(char *buf, char **start, off_t offset,
- int len, int unused){
+ int len, int unused)
+{
int i, index;
len = 0;
for (i=0; i<IRCOMM_MAX_CONNECTION; i++) {
+ len += sprintf(buf+len, "instance %d:\n",i);
+ if(ircomm[i]->in_use == 0){
+ len += sprintf(buf+len, "\tunused\n");
+ continue;
+ }
+
if (ircomm[i] == NULL || ircomm[i]->magic != IRCOMM_MAGIC) {
- len += sprintf(buf+len, "???\t");
- }else {
- switch (ircomm[i]->servicetype) {
- case UNKNOWN:
- index = 0;
- break;
- case THREE_WIRE_RAW:
- index = 1;
- break;
- case THREE_WIRE:
- index = 2;
- break;
- case NINE_WIRE:
- index = 3;
- break;
- case CENTRONICS:
- index = 4;
- break;
- default:
- index = 0;
- break;
- }
- len += sprintf(buf+len, "service: %s\t",
- ircommservicetype[index]);
- if(index){
- len += sprintf(buf+len, "porttype: %s ",
- ircommporttype[ircomm[i]->port_type]);
- len += sprintf(buf+len, "state: %s ",
- ircommstate[ircomm[i]->state]);
- len += sprintf(buf+len, "user: %s ",
- ircomm[i]->notify.name);
- len += sprintf(buf+len, "nullmodem emulation: %s",
- (ircomm[i]->null_modem_mode ? "yes":"no"));
- }
+ len += sprintf(buf+len, "\tbroken???\n");
+ continue;
+ }
+
+ switch (ircomm[i]->servicetype) {
+ case UNKNOWN:
+ index = 0;
+ break;
+ case THREE_WIRE_RAW:
+ index = 1;
+ break;
+ case THREE_WIRE:
+ index = 2;
+ break;
+ case NINE_WIRE:
+ index = 3;
+ break;
+ case CENTRONICS:
+ index = 4;
+ break;
+ default:
+ index = 0;
+ break;
}
- len += sprintf(buf+len, "\n");
+ len += sprintf(buf+len, " service: %s ",
+ ircommservicetype[index]);
+ if(!index)
+ continue;
+
+ len += sprintf(buf+len, "porttype: %s ",
+ ircommporttype[ircomm[i]->port_type]);
+ len += sprintf(buf+len, "state: %s ",
+ ircommstate[ircomm[i]->state]);
+ len += sprintf(buf+len, "user: %s\n",
+ ircomm[i]->notify.name);
+
+ len += sprintf(buf+len, " tx packets: %d ",
+ ircomm[i]->tx_packets);
+ len += sprintf(buf+len, "rx packets: %d ",
+ ircomm[i]->rx_packets);
+ len += sprintf(buf+len, "tx controls: %d\n",
+ ircomm[i]->tx_controls);
+
+ len += sprintf(buf+len, " pending tuples: %d ",
+ ircomm[i]->pending_control_tuples);
+ len += sprintf(buf+len, " ignored tuples: %d\n",
+ ircomm[i]->ignored_control_tuples);
+
+ len += sprintf(buf+len, " nullmodem emulation: %s ",
+ (ircomm[i]->null_modem_mode ? "yes":"no"));
+ len += sprintf(buf+len, "IrTTP: %s\n",
+ (ircomm[i]->ttp_stop ? "BUSY":"READY"));
+
+ len += sprintf(buf+len, " Peer capability: ");
+ if(ircomm[i]->peer_cap & THREE_WIRE_RAW)
+ len += sprintf(buf+len, "3wire-raw ");
+ if(ircomm[i]->peer_cap & THREE_WIRE)
+ len += sprintf(buf+len, "3wire ");
+ if(ircomm[i]->peer_cap & NINE_WIRE)
+ len += sprintf(buf+len, "9wire ");
+ if(ircomm[i]->peer_cap & CENTRONICS)
+ len += sprintf(buf+len, "centronics");
+
+ len += sprintf(buf+len, "\n Port name: %s\n",
+ (ircomm[i]->port_name));
}
+
return len;
}
-
#endif /* CONFIG_PROC_FS */
+
+
+