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 */