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;
}