This is my leaving gift. Please ignore...

        Jean
diff -u -p linux/include/linux/irda.f3.h linux/include/linux/irda.h
--- linux/include/linux/irda.f3.h       Fri Dec 10 08:14:32 1999
+++ linux/include/linux/irda.h  Fri Dec 10 08:15:29 1999
@@ -85,6 +85,7 @@ typedef enum {
 
 #define IRLMP_ENUMDEVICES        1
 #define IRLMP_IAS_SET            2
+#define IRLMP_IAS_GET            2
 #define IRLMP_IAS_QUERY          3
 #define IRLMP_HINTS_SET                 4
 
diff -u -p linux/include/net/irda/irda.f3.h linux/include/net/irda/irda.h
--- linux/include/net/irda/irda.f3.h    Fri Dec 10 09:47:51 1999
+++ linux/include/net/irda/irda.h       Fri Dec 10 10:35:00 1999
@@ -135,12 +135,13 @@ struct irda_sock {
        __u32 ckey;           /* IrLMP client handle */
        __u32 skey;           /* IrLMP service handle */
 
-       struct ias_object *ias_obj;
-       struct iriap_cb *iriap;
+       struct ias_object *ias_obj;     /* Our service name + lsap in IAS */
+       struct iriap_cb *iriap;         /* Used to query remote IAS */
+       struct ias_value *ias_result;   /* Used by getsockopt(IRLMP_IAS_QUERY) */
 
        int nslots;           /* Number of slots to use for discovery */
 
-       int errno;
+       int errno;              /* status of the IAS query */
 
        struct sock *sk;
        struct wait_queue *ias_wait;       /* Wait for LM-IAS answer */
diff -u -p linux/net/irda/af_irda.f3.c linux/net/irda/af_irda.c
--- linux/net/irda/af_irda.f3.c Fri Dec 10 08:10:04 1999
+++ linux/net/irda/af_irda.c    Fri Dec 10 13:27:49 1999
@@ -976,6 +976,7 @@ static int irda_create(struct socket *so
        self->mask = 0xffff;
        self->rx_flow = self->tx_flow = FLOW_START;
        self->nslots = DISCOVERY_DEFAULT_SLOTS;
+       self->daddr = DEV_ADDR_ANY;
 
        /* Notify that we are using the irda module, so nobody removes it */
        irda_mod_inc_use_count();
@@ -1687,6 +1688,101 @@ static int irda_setsockopt(struct socket
 }
 
 /*
+ * Function irda_simple_get_value_confirm (obj_id, value, priv)
+ *
+ *    Got answer from remote LM-IAS, just copy object to requester...
+ *
+ * Note : duplicate from above, but we need our own version that
+ * doesn't touch the dtsap_sel and save the full value structure...
+ */
+static void irda_simple_get_value_confirm(int result, __u16 obj_id, 
+                                         struct ias_value *value, void *priv)
+{
+       struct irda_sock *self;
+       
+       IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+       ASSERT(priv != NULL, return;);
+       self = (struct irda_sock *) priv;
+       
+       if (!self) {
+               WARNING(__FUNCTION__ "(), lost myself!\n");
+               return;
+       }
+
+       /* We probably don't need to make any more queries */
+       iriap_close(self->iriap);
+       self->iriap = NULL;
+
+       /* Check if request succeeded */
+       if (result != IAS_SUCCESS) {
+               IRDA_DEBUG(0, __FUNCTION__ "(), IAS query failed!\n");
+
+               self->errno = result;
+
+               /* Wake up any processes waiting for result */
+               wake_up_interruptible(&self->ias_wait);
+
+               return;
+       }
+
+       /* Clone the object (so the requester can free it) */
+       self->ias_result = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
+       memcpy(self->ias_result, value, sizeof(struct ias_value));
+
+       /* Wake up any processes waiting for result */
+       wake_up_interruptible(&self->ias_wait);
+}
+
+/*
+ * Function irda_extract_ias_value(ias_opt, ias_value)
+ *
+ *    Translate internal IAS value structure to the user space representation
+ *
+ * The external representation of IAS values, as we exchange them with
+ * user space program is quite different from the internal representation,
+ * as stored in the IAS database (because we need a flat structure for
+ * crossing kernel boundary).
+ * This function transform the former in the latter. We also check
+ * that the value type is valid.
+ */
+static int irda_extract_ias_value(struct irda_ias_set *ias_opt,
+                                 struct ias_value *ias_value)
+{
+       /* Look at the type */
+       switch(ias_value->type) {
+       case IAS_INTEGER:
+               /* Copy the integer */
+               ias_opt->attribute.irda_attrib_int = ias_value->t.integer;
+               break;
+       case IAS_OCT_SEQ:
+               /* Set length */
+               ias_opt->attribute.irda_attrib_octet_seq.len = ias_value->len;
+               /* Copy over */
+               memcpy(ias_opt->attribute.irda_attrib_octet_seq.OctetSeq,
+                      ias_value->t.oct_seq, ias_value->len);
+               break;
+       case IAS_STRING:
+               /* Set length */
+               ias_opt->attribute.irda_attrib_string.len = ias_value->len;
+               ias_opt->attribute.irda_attrib_string.charset = ias_value->charset;
+               /* Copy over */
+               memcpy(ias_opt->attribute.irda_attrib_string.string,
+                      ias_value->t.string, ias_value->len);
+               /* NULL terminate the string (avoid troubles) */
+               ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0';
+               break;
+       default :
+               return -EINVAL;
+       }
+
+       /* Copy type over */
+       ias_opt->irda_attrib_type = ias_value->type;
+
+       return 0;
+}
+
+/*
  * Function irda_getsockopt (sock, level, optname, optval, optlen)
  *
  *    
@@ -1700,8 +1796,13 @@ static int irda_getsockopt(struct socket
        struct irda_device_list list;
        struct irda_device_info *info;
        discovery_t *discovery;
+       struct irda_ias_set     ias_opt;        /* IAS get/query params */
+       struct ias_object *     ias_obj;        /* Object in IAS */
+       struct ias_attrib *     ias_attr;       /* Attribute in IAS object */
+       int daddr = 0;          /* Destination address for IAS queries */
        int val = 0;
        int len = 0;
+       int err;
        int offset, total;
 
        self = sk->protinfo.irda;
@@ -1757,7 +1858,7 @@ static int irda_getsockopt(struct socket
                                strncpy(info->info, discovery->nickname,
                                        NICKNAME_MAX_LEN);
 
-                               if (copy_to_user(optval+offset, info, 
+                               if (copy_to_user(optval+total, info, 
                                                 sizeof(struct irda_device_info)))
                                        return -EFAULT;
                                list.len++;
@@ -1786,10 +1887,103 @@ static int irda_getsockopt(struct socket
                if (copy_to_user(optval, &val, len))
                        return -EFAULT;
                break;
-               /*
-         if (copy_to_user(wrq->u.data.pointer, (u_char *) priv, sizeof(priv)))
-               ret = -EFAULT;
-               */
+       case IRLMP_IAS_GET:
+               /* The user want an object from our local IAS database.
+                * We just need to query the IAS and return the value
+                * that we found */
+
+               /* Check that the user has allocated the right space for us */
+               if (len != sizeof(ias_opt))
+                       return -EINVAL;
+
+               /* Copy query to the driver. */
+               if (copy_from_user((char *) &ias_opt, (char *)optval, len))
+                       return -EFAULT;
+
+               /* Find the object we target */
+               ias_obj = irias_find_object(ias_opt.irda_class_name);
+               if(ias_obj == (struct ias_object *) NULL)
+                       return -EINVAL;
+
+               /* Find the attribute (in the object) we target */
+               ias_attr = irias_find_attrib(ias_obj,
+                                            ias_opt.irda_attrib_name); 
+               if(ias_attr == (struct ias_attrib *) NULL)
+                       return -EINVAL;
+
+               /* Translate from internal to user structure */
+               err = irda_extract_ias_value(&ias_opt, ias_attr->value);
+               if(err)
+                       return err;
+
+               /* Copy reply to the user */
+               if (copy_to_user((char *)optval, (char *) &ias_opt,
+                                sizeof(ias_opt)))
+                       return -EFAULT;
+               /* Note : don't need to put optlen, we checked it */
+               break;
+       case IRLMP_IAS_QUERY:
+               /* The user want an object from a remote IAS database.
+                * We need to use IAP to query the remote database and
+                * then wait for the answer to come back. */
+
+               /* Check that the user has allocated the right space for us */
+               if (len != sizeof(ias_opt))
+                       return -EINVAL;
+
+               /* Copy query to the driver. */
+               if (copy_from_user((char *) &ias_opt, (char *)optval, len))
+                       return -EFAULT;
+
+               /* Check the destination address requested */
+               daddr = ias_opt.attribute.irda_attrib_int;
+               if(self->daddr != DEV_ADDR_ANY) {
+                       /* If we are connected, we must use the correct
+                        * destination address (or leave it unspecified) */
+                       if((daddr != DEV_ADDR_ANY) || (daddr != self->daddr))
+                               return -EINVAL;
+                       daddr = self->daddr;
+               } else {
+                       /* If we are not connected, we must specify a valid
+                        * destination address */
+                       if(daddr == DEV_ADDR_ANY)
+                               return -EINVAL;
+               }
+
+               /* Check that we can proceed with IAP */
+               if (self->iriap) {
+                       WARNING(__FUNCTION__
+                               "(), busy with a previous query\n");
+                       return -EBUSY;
+               }
+
+               self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
+                                        irda_simple_get_value_confirm);
+
+               /* Query remote LM-IAS */
+               self->errno = 0;
+               iriap_getvaluebyclass_request(self->iriap, self->saddr,
+                                             daddr,
+                                             ias_opt.irda_class_name,
+                                             ias_opt.irda_attrib_name);
+               /* Wait for answer */
+               interruptible_sleep_on(&self->ias_wait);
+               /* Check what happened */
+               if(self->errno)
+                       return(self->errno);
+
+               /* Translate from internal to user structure */
+               err = irda_extract_ias_value(&ias_opt, self->ias_result);
+               kfree(self->ias_result); /* Cleanup (need to be *here*) */
+               if(err)
+                       return err;
+
+               /* Copy reply to the user */
+               if (copy_to_user((char *)optval, (char *) &ias_opt,
+                                sizeof(ias_opt)))
+                       return -EFAULT;
+               /* Note : don't need to put optlen, we checked it */
+               break;
        default:
                return -ENOPROTOOPT;
        }
/*********************************************************************
 *                
 * Filename:      irdaspray.c
 * Version:       
 * Description:   
 * Status:        Experimental.
 * Author:        Dag Brattli <[EMAIL PROTECTED]>
 *                Jean Tourrilhes <[EMAIL PROTECTED]>
 * Created at:    10/12/99
 * Modified at:   Mon May 10 18:31:35 1999
 * Modified by:   Dag Brattli <[EMAIL PROTECTED]>
 * 
 *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
 *     
 *     This program is free software; you can redistribute it and/or 
 *     modify it under the terms of the GNU General Public License as 
 *     published by the Free Software Foundation; either version 2 of 
 *     the License, or (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License 
 *     along with this program; if not, write to the Free Software 
 *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
 *     MA 02111-1307 USA
 *     
 ********************************************************************/

/*
 * This program demonstrate the use of auto-connect (connect to a service
 * without having to discover/specify an address) and how a program
 * can report discovery results to the user in case the service is not
 * unique on the network.
 * Of course, you need both auto-connect and query-ias in the kernel, and
 * a few bugs sorted out...
 *
 * Jean Tourrilhes
 */

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

#include <linux/irda.h>

#ifndef AF_IRDA
#define AF_IRDA 23
#endif /* AF_IRDA */

#define MAX_DEVICES 10

int fd;
int mtu = 0;
int frame_size = 1024;
int frame_number = 100;
unsigned char buf[4096];
int delay = 0;
int echo = 0;             /* Use discard service by default */

/*
 * Function echo_discover_devices (fd)
 *
 *    Try to discover some remote device(s) that we can connect to
 *
 */
int irdaspray_discover_devices(int fd, char *service_name)
{
        struct irda_device_list *list;
        struct irda_ias_set ias_query;
        unsigned char *buf;
        int err;
        int len;
        int i;

        /* Get the name of our own device (not essential) */
        len = sizeof(ias_query);
        strcpy(ias_query.irda_class_name, "Device");
        strcpy(ias_query.irda_attrib_name, "DeviceName");
        if (!getsockopt(fd, SOL_IRLMP, IRLMP_IAS_GET, &ias_query, &len)) {
                printf("The name of our device is = ``%s''\n",
                       ias_query.attribute.irda_attrib_string.string);
        }

        /* Init... Note : should be cleaned up... */
        len = sizeof(struct irda_device_list) +
                sizeof(struct irda_device_info) * MAX_DEVICES;

        buf = malloc(len);
        list = (struct irda_device_list *) buf;
        

        /* Perform a discovery and get device list */
        if (getsockopt(fd, SOL_IRLMP, IRLMP_ENUMDEVICES, buf, &len)) {
                perror("getsockopt-enum");
                exit(-1);
        }

        /* Did we got any ? */
        if ((len <= 0) || (list->len <= 0)) {
                printf("Didn't find any devices!\n");
                return -1;
        }

        /* List all devices */
        printf("Discovered %d devices :\n", list->len);
        for (i=0;i<list->len;i++) {
                printf("  [%d] name:  %s, daddr: 0x%08x",
                       i + 1, list->dev[i].info, list->dev[i].daddr);

                /* Ask if the requested service exist on this device */
                len = sizeof(ias_query);
                ias_query.attribute.irda_attrib_int = list->dev[i].daddr;
                strcpy(ias_query.irda_class_name, service_name);
                strcpy(ias_query.irda_attrib_name, "IrDA:TinyTP:LsapSel");
                err = getsockopt(fd, SOL_IRLMP, IRLMP_IAS_QUERY,
                                 &ias_query, &len);
                if(err == 0) {
                        printf(", has service %s\n", service_name);
                } else {
                        if(err != 1)
                                printf(" <can't query IAS>\n");
                        else
                                printf("\n");
                }
        }
                        
        /* Ask the user */
        printf("Enter device number:");
        fflush(stdout);
        if(scanf("%X", &i) != 1)
                return -1;
        i--;
        if((i < 0) && (i > list->len))
                return -1;
        return(list->dev[i].daddr);
}

/*
 * Function irdaspray_connect_request (self)
 *
 *    Try to connect to remote device
 *
 */
static int irdaspray_connect_request(int fd)
{
        struct sockaddr_irda peer;
        char *service_name;
        int len = sizeof(int);
        int daddr;
        int err;

        /* Set the service name */
        if (echo)
                service_name = "IrECHO";
        else
                service_name = "IrDISCARD";

        /*
         * First, we try the auto-connect, which in 99% of the case
         * should be good enough...
         *
         * Auto connect lookup devices in range and query them about the
         * service we want. If there is only one device that support
         * this service, we are magically connected to it...
         */
        peer.sir_family = AF_IRDA;
        strncpy(peer.sir_name, service_name, 25);
        peer.sir_addr = 0x0;    /* Maybe DEV_ADDR_ANY is better ? */
        
        err = connect(fd, (struct sockaddr*) &peer, 
                      sizeof(struct sockaddr_irda));

        /* Check what has happened */
        if(err == 0) {
                printf("Auto-connect did found exactly one device !\n");
                return 0;
        }
        if(err != -ENOTUNIQ) {
                printf("Auto-connect could not find anything...\n");
                return -1;
        }

        printf("Auto-connect has found more than one device...\n");
        /*
         * At this point, if we don't have any user interface or if we
         * don't want to bother with that, we could just tell the user
         * to aim its device closer to the target and just quit...
         * However, for the purpose of the exercise, let's pretend that
         * the user doesn't want to move his device and has plenty of UI...
         */

        /* Make a proper discovery and ask user to choose */
        daddr = irdaspray_discover_devices(fd, service_name);
        if (daddr == -1)
                return -1;

        /* Now we can try again to connect using the address */
        peer.sir_family = AF_IRDA;
        strncpy(peer.sir_name, service_name, 25);
        peer.sir_addr = daddr;
        
        if (connect(fd, (struct sockaddr*) &peer, 
                    sizeof(struct sockaddr_irda))) {
                perror("connect");
                return -1;
        }

        return 0;
}

int irdaspray_transmit(int fd)
{
        int total = 0;
        int actual;
        int i;

        /* Transmit frames */
        for (i=0; i<frame_number; i++) {
                actual = send(fd, buf, frame_size, 0);
                total += actual;
        }
        return total;
}

int irdaspray_receive(int fd)
{
        int total = 0;
        int actual;
        int i;

        /* Receive frames */
        for (i=0; i<frame_number; i++) {
                actual = recv(fd, buf, sizeof(buf), 0);
                total += actual;
        }
        return total;
}

static void usage(char *argv[])
{
        fprintf(stderr, "usage: %s [-v] [-e] [-h] [-b frame-size] [-n frames] [-f 
file] [device]\n", argv[0]);
        fprintf(stderr, "      -v verbose\n");
        fprintf(stderr, "      -e use echo service for full duplex transfer\n");
        fprintf(stderr, "      -h print this message\n");
        fprintf(stderr, "      -b frame-size in bytes (default 1024)\n");
        fprintf(stderr, "      -n number of frames (default 100)\n");
        fprintf(stderr, "      -f file to preload buffer (zero buffer by default)\n");
        fprintf(stderr, "      -d inter-buffer transmission delay in usecs (default 
0)\n");
        exit(1);
}

/*
 * Function main (argc, )
 *
 *    
 *
 */
int main(int argc, char *argv[])
{
        struct timeval start, end;
        int total;
        double time;
        int status;
        int ret;
        int c;
        int pid = 0;

        while ((c = getopt(argc, argv, "vehs:m:n:f:d:")) != -1) {
                switch (c) {
                case 'm':
                        mtu = atoi(optarg);
                        break;
                        
                case 'e':
                        echo = 1; /* Use echo service instead of discard */
                        break;
                        
                case 'h':
                        usage(argv);
                        break;
                        
                case 'n':
                        frame_number = atoi(optarg);
                        break;
                        
                case 's':
                        frame_size = atoi(optarg);
                        break;
                        
/*              case 'f': */
/*                      fflag = TRUE; */
/*                      if ((infile = fopen(optarg, "r")) == NULL) { */
/*                              fprintf(stderr, "%s: Can't open file %s.\n", argv[0], 
optarg); */
/*                              exit(2); */
/*                      } */
/*                      break; */
                        
                case 'd':
                        delay = atoi(optarg);
                        break;
                        
                default:
                        usage(argv);
                        break;
                }
        }

        /* Create socket */
        fd = socket(AF_IRDA, SOCK_STREAM, 0);
        if (fd < 0) {
                perror("socket");
                exit(-1);
        }

        /* Try connect */
        ret = irdaspray_connect_request(fd);
        if (ret) {
                return -1;
        }
        
        printf("Connected!\n");

        gettimeofday(&start, (struct timezone*) 0);

        if (echo) {
                /* Fork off receiver */
                pid = fork();
                
                if (pid) {
                        total = irdaspray_receive(fd);
                } else {
                        total = irdaspray_transmit(fd);
                }
        } else
                total = irdaspray_transmit(fd);

        gettimeofday(&end, (struct timezone*) 0);

        time = (double) (end.tv_sec - start.tv_sec) + (double)
                ((double) (end.tv_usec - start.tv_usec) / 1000000.0);

        if (pid) 
                printf("Received %d bytes in %f seconds (%0.3f kbytes/s)\n",
                       total, time, (double) (total / time) / 1024); 
        else {
                if (echo)
                        wait(&status);
                
                printf("Transmitted %d bytes in %f seconds (%0.3f kbytes/s)\n",
                       total, time, (double) (total / time) / 1024);
        }

        return 0;
}

Reply via email to