Dag,

        For your pleasure, I modified the auto-connect to be according
to your rules. This time, no policy in the kernel, and we do things
proper. I hope it will make you happy...

        Jean

P.S. : Of course, I've uncovered a few other details, but please put
them on your todo list with a very low priority, even lower than Ultra
support, far behind PyObex and what real people really need.
diff -u -p linux/include/net/irda/irlap.f1.h linux/include/net/irda/irlap.h
--- linux/include/net/irda/irlap.f1.h   Thu Dec  9 11:48:25 1999
+++ linux/include/net/irda/irlap.h      Thu Dec  9 11:50:05 1999
@@ -92,6 +92,7 @@ struct irda_compressor {
 struct irlap_cb {
        queue_t q;     /* Must be first */
        magic_t magic;
+       int     n_lsaps;        /* Ref-count : number of SAP open above us */
 
        struct device  *netdev;
 
diff -u -p linux/net/irda/irlap.f1.c linux/net/irda/irlap.c
--- linux/net/irda/irlap.f1.c   Thu Dec  9 11:52:09 1999
+++ linux/net/irda/irlap.c      Thu Dec  9 12:23:43 1999
@@ -120,6 +120,7 @@ struct irlap_cb *irlap_open(struct devic
        
        memset(self, 0, sizeof(struct irlap_cb));
        self->magic = LAP_MAGIC;
+       self->n_lsaps = 0;      /* No LSAP open for now */
 
        /* Make a binding between the layers */
        self->netdev = dev;
@@ -265,6 +266,10 @@ void irlap_connect_request(struct irlap_
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == LAP_MAGIC, return;);
 
+       self->n_lsaps++;        /* One more LSAP connected */
+       /* Note : verify that we refcount LSAP open on incomming connections */
+
+       /* May want to check if the same in case n_lsaps > 1 */
        self->daddr = daddr;
        
        /*
@@ -434,12 +439,23 @@ void irlap_disconnect_request(struct irl
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == LAP_MAGIC, return;);
        
+       self->n_lsaps--;        /* Remove one LSAP from our list */
+
+       /* Check if it was the last LSAP */
+       if(self->n_lsaps)
+               return;
+
+       IRDA_DEBUG(1, __FUNCTION__ "(), going to disconnect the LAP\n"); 
+
        /* Don't disconnect until all data frames are successfully sent */
        if (skb_queue_len(&self->txq) > 0) {
                self->disconnect_pending = TRUE;
                
                return;
        }
+
+       /* Not connected means no address - makes IrLMP happy */
+       self->daddr = DEV_ADDR_ANY;
 
        /* Check if we are in the right state for disconnecting */
        switch (self->state) {
diff -u -p linux/net/irda/irlmp_event.f1.c linux/net/irda/irlmp_event.c
--- linux/net/irda/irlmp_event.f1.c     Thu Dec  9 12:02:49 1999
+++ linux/net/irda/irlmp_event.c        Thu Dec  9 12:19:13 1999
@@ -306,8 +306,8 @@ static void irlmp_state_u_connect(struct
 
                irlmp_next_lap_state(self, LAP_STANDBY);
 
-               /* FIXME */
-/*             irlap_disconnect_request( self->irlap); */
+               /* FIXME -> With refcount, should be better */
+/*             irlap_disconnect_request( self->irlap);*/
                break;
        default:
                IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
diff -u -p linux/net/irda/af_irda.f1.c linux/net/irda/af_irda.c
--- linux/net/irda/af_irda.f1.c Thu Dec  9 10:20:38 1999
+++ linux/net/irda/af_irda.c    Thu Dec  9 12:25:57 1999
@@ -485,6 +485,101 @@ static int irda_find_lsap_sel(struct ird
 }
 
 /*
+ * Function irda_discover_daddr_and_lsap_sel (self, name)
+ *
+ *    This try to find a device with the requested service.
+ *
+ * It basically look into the discovery log. For each address in the list,
+ * it queries the LM-IAS of the device to find if this device offer
+ * the requested service.
+ * If there is more than one node supporting the service, we complain
+ * to the user (it should move devices around).
+ * The, we set both the destination address and the lsap selector to point
+ * on the service on the unique device we have found.
+ *
+ * Note : this function fails if there is more than one device in range,
+ * because IrLMP doesn't disconnect the LAP when the last LSAP is closed.
+ * Moreover, we would need to wait the LAP disconnection...
+ */
+static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
+{
+       discovery_t *discovery;
+       int err = -ENETUNREACH;
+       __u32   daddr = 0x0;            /* Address we found the service on */
+       __u8    dtsap_sel = 0x0;        /* TSAP associated with it */
+
+       IRDA_DEBUG(2, __FUNCTION__ "(), name=%s\n", name);
+
+       ASSERT(self != NULL, return -1;);
+
+       /* Tell IrLMP we want to be notified */
+       irlmp_update_client(self->ckey, self->mask, NULL, 
+                           irda_discovery_indication);
+       
+       /* Do some discovery */
+       irlmp_discovery_request(self->nslots);
+               
+       /* Check if the we got some results */
+       if (!cachelog)
+               /* Wait for answer */
+               /*interruptible_sleep_on(&self->discovery_wait);*/
+               return -EAGAIN;
+
+       /* 
+        * Now, check all discovered devices (if any), and connect
+        * client only about the services that the client is
+        * interested in...
+        */
+       discovery = (discovery_t *) hashbin_get_first(cachelog);
+       while (discovery != NULL) {
+               /* Mask out the ones we don't want */
+               if (discovery->hints.word & self->mask) {
+                       /* Try this address */
+                       self->daddr = discovery->daddr;
+                       self->saddr = 0x0;
+                       IRDA_DEBUG(1, __FUNCTION__ "(), trying daddr = %08x\n", 
+self->daddr);
+
+                       /* Query remote LM-IAS for this service */
+                       err = irda_find_lsap_sel(self, name);
+                       if (err == 0) {
+                               /* We found the requested service */
+                               if(daddr != 0x0) {
+                                       IRDA_DEBUG(0, __FUNCTION__
+                                                  "(), discovered service ''%s'' in 
+two different devices !!!\n",
+                                                  name);
+                                       return(-ENOTUNIQ);
+                               }
+                               /* First time we foun that one, save it ! */
+                               daddr = self->daddr;
+                               dtsap_sel = self->dtsap_sel;
+                       }
+               }
+
+               /* Next node, maybe we will be more lucky...  */
+               discovery = (discovery_t *) hashbin_get_next(cachelog);
+       }
+       cachelog = NULL;
+
+       /* Check out what we found */
+       if(daddr == 0x0) {
+               IRDA_DEBUG(0, __FUNCTION__
+                          "(), cannot discover service ''%s'' in any device !!!\n",
+                          name);
+               self->daddr = 0;        /* Guessing */
+               return(-ENETUNREACH);
+       }
+
+       /* Revert back to discovered device & service */
+       self->daddr = daddr;
+       self->saddr = 0x0;
+       self->dtsap_sel = dtsap_sel;
+
+       IRDA_DEBUG(0, __FUNCTION__ "(), discovered requested service ''%s'' at address 
+%08x\n", name, self->daddr);
+
+       return 0;
+}
+
+/*
  * Function irda_getname (sock, uaddr, uaddr_len, peer)
  *
  *    Return the our own, or peers socket address (sockaddr_irda)
@@ -742,18 +837,26 @@ static int irda_connect(struct socket *s
        if (addr_len != sizeof(struct sockaddr_irda))
                return -EINVAL;
 
-       /* Check if user supplied the required destination device address */
-       if (!addr->sir_addr)
-               return -EINVAL;
-
-       self->daddr = addr->sir_addr;
-       IRDA_DEBUG(1, __FUNCTION__ "(), daddr = %08x\n", self->daddr);
-
-       /* Query remote LM-IAS */
-       err = irda_find_lsap_sel(self, addr->sir_name);
-       if (err) {
-               IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n");
-               return err;
+       /* Check if user supplied any destination device address */
+       if (!addr->sir_addr) {
+               /* Try to find one suitable */
+               err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name);
+               if (err) {
+                       IRDA_DEBUG(0, __FUNCTION__ "(), auto-connect failed!\n");
+                       return -EINVAL;
+               }
+       }
+       else {
+               /* Use the one provided by the user */
+               self->daddr = addr->sir_addr;
+               IRDA_DEBUG(1, __FUNCTION__ "(), daddr = %08x\n", self->daddr);
+
+               /* Query remote LM-IAS */
+               err = irda_find_lsap_sel(self, addr->sir_name);
+               if (err) {
+                       IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n");
+                       return err;
+               }
        }
 
        /* Check if we have opened a local TSAP */

Reply via email to