summaryrefslogtreecommitdiffstats
path: root/net/irda
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
commit99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch)
tree3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /net/irda
parente73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff)
Merge with Linux 2.3.38.
Diffstat (limited to 'net/irda')
-rw-r--r--net/irda/Config.in2
-rw-r--r--net/irda/af_irda.c918
-rw-r--r--net/irda/discovery.c3
-rw-r--r--net/irda/ircomm/ircomm_core.c43
-rw-r--r--net/irda/ircomm/ircomm_event.c12
-rw-r--r--net/irda/ircomm/ircomm_lmp.c17
-rw-r--r--net/irda/ircomm/ircomm_param.c141
-rw-r--r--net/irda/ircomm/ircomm_ttp.c28
-rw-r--r--net/irda/ircomm/ircomm_tty.c292
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c143
-rw-r--r--net/irda/ircomm/ircomm_tty_ioctl.c106
-rw-r--r--net/irda/irda_device.c98
-rw-r--r--net/irda/iriap.c204
-rw-r--r--net/irda/iriap_event.c54
-rw-r--r--net/irda/irias_object.c29
-rw-r--r--net/irda/irlan/irlan_client.c13
-rw-r--r--net/irda/irlan/irlan_client_event.c4
-rw-r--r--net/irda/irlan/irlan_common.c3
-rw-r--r--net/irda/irlan/irlan_eth.c3
-rw-r--r--net/irda/irlap.c362
-rw-r--r--net/irda/irlap_event.c502
-rw-r--r--net/irda/irlap_frame.c363
-rw-r--r--net/irda/irlmp.c216
-rw-r--r--net/irda/irlmp_event.c175
-rw-r--r--net/irda/irlmp_frame.c133
-rw-r--r--net/irda/irmod.c28
-rw-r--r--net/irda/irqueue.c16
-rw-r--r--net/irda/irttp.c130
-rw-r--r--net/irda/parameters.c4
-rw-r--r--net/irda/qos.c184
-rw-r--r--net/irda/timer.c6
-rw-r--r--net/irda/wrapper.c31
32 files changed, 2946 insertions, 1317 deletions
diff --git a/net/irda/Config.in b/net/irda/Config.in
index 942182e35..8cf2b4a82 100644
--- a/net/irda/Config.in
+++ b/net/irda/Config.in
@@ -12,7 +12,7 @@ if [ "$CONFIG_NET" != "n" ]; then
comment 'IrDA protocols'
source net/irda/irlan/Config.in
source net/irda/ircomm/Config.in
-
+ bool ' Ultra (connectionless) protocol' CONFIG_IRDA_ULTRA
bool ' IrDA protocol options' CONFIG_IRDA_OPTIONS
if [ "$CONFIG_IRDA_OPTIONS" != "n" ]; then
comment ' IrDA options'
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 19bbae258..8bea0ce98 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -1,28 +1,48 @@
/*********************************************************************
*
* Filename: af_irda.c
- * Version: 0.7
+ * Version: 0.9
* Description: IrDA sockets implementation
- * Status: Experimental.
+ * Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun May 31 10:12:43 1998
- * Modified at: Sun Oct 31 19:32:37 1999
+ * Modified at: Sat Dec 25 21:10:23 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
*
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
- *
+ * Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no>
+ * Copyright (c) 1999 Jean Tourrilhes <jeant@rockfort.hpl.hp.com>
+ * 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.
- *
- * Neither Dag Brattli nor University of Tromsų admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
+ *
+ * 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
+ *
+ * Linux-IrDA now supports four different types of IrDA sockets:
+ *
+ * o SOCK_STREAM: TinyTP connections with SAR disabled. The
+ * max SDU size is 0 for conn. of this type
+ * o SOCK_SEQPACKET: TinyTP connections with SAR enabled. TTP may
+ * fragment the messages, but will preserve
+ * the message boundaries
+ * o SOCK_DGRAM: IRDAPROTO_UNITDATA: TinyTP connections with Unitdata
+ * (unreliable) transfers
+ * IRDAPROTO_ULTRA: Connectionless and unreliable data
*
********************************************************************/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/sockios.h>
@@ -39,6 +59,7 @@
#include <net/irda/irda.h>
#include <net/irda/iriap.h>
#include <net/irda/irias_object.h>
+#include <net/irda/irlmp.h>
#include <net/irda/irttp.h>
#include <net/irda/discovery.h>
@@ -50,7 +71,14 @@ extern int irlap_driver_rcv(struct sk_buff *, struct net_device *,
static int irda_create(struct socket *sock, int protocol);
static struct proto_ops irda_stream_ops;
+static struct proto_ops irda_seqpacket_ops;
static struct proto_ops irda_dgram_ops;
+
+#ifdef CONFIG_IRDA_ULTRA
+static struct proto_ops irda_ultra_ops;
+#define ULTRA_MAX_DATA 382
+#endif /* CONFIG_IRDA_ULTRA */
+
static hashbin_t *cachelog = NULL;
static DECLARE_WAIT_QUEUE_HEAD(discovery_wait); /* Wait for discovery */
@@ -133,6 +161,10 @@ static void irda_connect_confirm(void *instance, void *sap,
self = (struct irda_sock *) instance;
+ sk = self->sk;
+ if (sk == NULL)
+ return;
+
/* How much header space do we need to reserve */
self->max_header_size = max_header_size;
@@ -140,19 +172,30 @@ static void irda_connect_confirm(void *instance, void *sap,
self->max_sdu_size_tx = max_sdu_size;
/* Find out what the largest chunk of data that we can transmit is */
- if (max_sdu_size == SAR_DISABLE)
- self->max_data_size = irttp_get_max_seq_size(self->tsap);
- else
+ switch (sk->type) {
+ case SOCK_STREAM:
+ if (max_sdu_size != 0) {
+ ERROR(__FUNCTION__ "(), max_sdu_size must be 0\n");
+ return;
+ }
+ self->max_data_size = irttp_get_max_seg_size(self->tsap);
+ break;
+ case SOCK_SEQPACKET:
+ if (max_sdu_size == 0) {
+ ERROR(__FUNCTION__ "(), max_sdu_size cannot be 0\n");
+ return;
+ }
self->max_data_size = max_sdu_size;
+ break;
+ default:
+ self->max_data_size = irttp_get_max_seg_size(self->tsap);
+ };
- IRDA_DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+ IRDA_DEBUG(2, __FUNCTION__ "(), max_data_size=%d\n",
+ self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
- sk = self->sk;
- if (sk == NULL)
- return;
-
skb_queue_tail(&sk->receive_queue, skb);
/* We are now connected! */
@@ -175,7 +218,11 @@ static void irda_connect_indication(void *instance, void *sap,
IRDA_DEBUG(2, __FUNCTION__ "()\n");
- self = (struct irda_sock *) instance;
+ self = (struct irda_sock *) instance;
+
+ sk = self->sk;
+ if (sk == NULL)
+ return;
/* How much header space do we need to reserve */
self->max_header_size = max_header_size;
@@ -184,21 +231,31 @@ static void irda_connect_indication(void *instance, void *sap,
self->max_sdu_size_tx = max_sdu_size;
/* Find out what the largest chunk of data that we can transmit is */
- if (max_sdu_size == SAR_DISABLE)
- self->max_data_size = irttp_get_max_seq_size(self->tsap);
- else
+ switch (sk->type) {
+ case SOCK_STREAM:
+ if (max_sdu_size != 0) {
+ ERROR(__FUNCTION__ "(), max_sdu_size must be 0\n");
+ return;
+ }
+ self->max_data_size = irttp_get_max_seg_size(self->tsap);
+ break;
+ case SOCK_SEQPACKET:
+ if (max_sdu_size == 0) {
+ ERROR(__FUNCTION__ "(), max_sdu_size cannot be 0\n");
+ return;
+ }
self->max_data_size = max_sdu_size;
+ break;
+ default:
+ self->max_data_size = irttp_get_max_seg_size(self->tsap);
+ };
- IRDA_DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+ IRDA_DEBUG(2, __FUNCTION__ "(), max_data_size=%d\n",
+ self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
-
- sk = self->sk;
- if (sk == NULL)
- return;
skb_queue_tail(&sk->receive_queue, skb);
-
sk->state_change(sk);
}
@@ -212,7 +269,7 @@ void irda_connect_response(struct irda_sock *self)
{
struct sk_buff *skb;
- IRDA_DEBUG(1, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
@@ -239,7 +296,7 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
struct irda_sock *self;
struct sock *sk;
- IRDA_DEBUG(1, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
self = (struct irda_sock *) instance;
ASSERT(self != NULL, return;);
@@ -254,26 +311,30 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
break;
case FLOW_START:
self->tx_flow = flow;
- IRDA_DEBUG(1, __FUNCTION__ "(), IrTTP wants us to start again\n");
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), IrTTP wants us to start again\n");
wake_up_interruptible(sk->sleep);
break;
default:
IRDA_DEBUG( 0, __FUNCTION__ "(), Unknown flow command!\n");
+ /* Unknown flow command, better stop */
+ self->tx_flow = flow;
+ break;
}
}
/*
- * Function irda_get_value_confirm (obj_id, value, priv)
+ * Function irda_getvalue_confirm (obj_id, value, priv)
*
* Got answer from remote LM-IAS
*
*/
-static void irda_get_value_confirm(int result, __u16 obj_id,
- struct ias_value *value, void *priv)
+static void irda_getvalue_confirm(int result, __u16 obj_id,
+ struct ias_value *value, void *priv)
{
struct irda_sock *self;
- IRDA_DEBUG(1, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
ASSERT(priv != NULL, return;);
self = (struct irda_sock *) priv;
@@ -287,12 +348,12 @@ static void irda_get_value_confirm(int result, __u16 obj_id,
iriap_close(self->iriap);
self->iriap = NULL;
+ self->errno = result;
+
/* 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);
@@ -312,6 +373,8 @@ static void irda_get_value_confirm(int result, __u16 obj_id,
IRDA_DEBUG(0, __FUNCTION__ "(), bad type!\n");
break;
}
+ irias_delete_value(value);
+
/* Wake up any processes waiting for result */
wake_up_interruptible(&self->ias_wait);
}
@@ -324,7 +387,7 @@ static void irda_get_value_confirm(int result, __u16 obj_id,
*/
static void irda_discovery_indication(hashbin_t *log)
{
- IRDA_DEBUG(1, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
cachelog = log;
@@ -353,6 +416,7 @@ static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name)
notify.connect_indication = irda_connect_indication;
notify.disconnect_indication = irda_disconnect_indication;
notify.data_indication = irda_data_indication;
+ notify.udata_indication = irda_data_indication;
notify.flow_indication = irda_flow_indication;
notify.instance = self;
strncpy(notify.name, name, NOTIFY_MAX_NAME);
@@ -370,6 +434,38 @@ static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name)
}
/*
+ * Function irda_open_lsap (self)
+ *
+ * Open local Link Service Access Point (LSAP). Used for opening Ultra
+ * sockets
+ */
+#ifdef CONFIG_IRDA_ULTRA
+static int irda_open_lsap(struct irda_sock *self, int pid)
+{
+ notify_t notify;
+
+ if (self->lsap) {
+ WARNING(__FUNCTION__ "(), busy!\n");
+ return -EBUSY;
+ }
+
+ /* Initialize callbacks to be used by the IrDA stack */
+ irda_notify_init(&notify);
+ notify.udata_indication = irda_data_indication;
+ notify.instance = self;
+ strncpy(notify.name, "Ultra", NOTIFY_MAX_NAME);
+
+ self->lsap = irlmp_open_lsap(LSAP_CONNLESS, &notify, pid);
+ if (self->lsap == NULL) {
+ IRDA_DEBUG( 0, __FUNCTION__ "(), Unable to allocate LSAP!\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_IRDA_ULTRA */
+
+/*
* Function irda_find_lsap_sel (self, name)
*
* Try to lookup LSAP selector in remote LM-IAS
@@ -377,7 +473,7 @@ static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name)
*/
static int irda_find_lsap_sel(struct irda_sock *self, char *name)
{
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "(), name=%s\n", name);
ASSERT(self != NULL, return -1;);
@@ -387,7 +483,7 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name)
}
self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- irda_get_value_confirm);
+ irda_getvalue_confirm);
/* Query remote LM-IAS */
iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
@@ -401,6 +497,104 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name)
return -ENETUNREACH; /* May not be true */
}
+ /*
+ * 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)
*
@@ -446,12 +640,16 @@ static int irda_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+ if ((sk->type != SOCK_STREAM) && (sk->type != SOCK_SEQPACKET) &&
+ (sk->type != SOCK_DGRAM))
+ return -EOPNOTSUPP;
- if (sk->type == SOCK_STREAM && sk->state != TCP_LISTEN) {
+ if (sk->state != TCP_LISTEN) {
sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN;
-
+
return 0;
}
@@ -472,15 +670,38 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
__u16 hints = 0;
int err;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
self = sk->protinfo.irda;
ASSERT(self != NULL, return -1;);
- if ((addr_len < sizeof(struct sockaddr_irda)) ||
- (addr_len > sizeof(struct sockaddr_irda)))
+ if (addr_len != sizeof(struct sockaddr_irda))
return -EINVAL;
+#ifdef CONFIG_IRDA_ULTRA
+ /* Special care for Ultra sockets */
+ if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA)) {
+ self->pid = addr->sir_lsap_sel;
+ if (self->pid & 0x80) {
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), extension in PID not supp!\n");
+ return -EOPNOTSUPP;
+ }
+ err = irda_open_lsap(self, self->pid);
+ if (err < 0)
+ return err;
+
+ self->max_data_size = ULTRA_MAX_DATA - LMP_PID_HEADER;
+ self->max_header_size = IRDA_MAX_HEADER + LMP_PID_HEADER;
+
+ /* Pretend we are connected */
+ sock->state = SS_CONNECTED;
+ sk->state = TCP_ESTABLISHED;
+
+ return 0;
+ }
+#endif /* CONFIG_IRDA_ULTRA */
+
err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name);
if (err < 0)
return err;
@@ -490,6 +711,8 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel",
self->stsap_sel);
irias_insert_object(self->ias_obj);
+
+#if 1 /* Will be removed in near future */
/* Fill in some default hint bits values */
if (strncmp(addr->sir_name, "OBEX", 4) == 0)
@@ -497,7 +720,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (hints)
self->skey = irlmp_register_service(hints);
-
+#endif
return 0;
}
@@ -515,7 +738,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
struct sk_buff *skb;
int err;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
self = sk->protinfo.irda;
ASSERT(self != NULL, return -1;);
@@ -530,10 +753,11 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
if ((sk = sock->sk) == NULL)
return -EINVAL;
- if (sk->type != SOCK_STREAM)
+ if ((sk->type != SOCK_STREAM) && (sk->type != SOCK_SEQPACKET) &&
+ (sk->type != SOCK_DGRAM))
return -EOPNOTSUPP;
- if (sk->state != TCP_LISTEN)
+ if (sk->state != TCP_LISTEN)
return -EINVAL;
/*
@@ -606,9 +830,13 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
struct irda_sock *self;
int err;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
self = sk->protinfo.irda;
+
+ /* Don't allow connect for Ultra sockets */
+ if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA))
+ return -ESOCKTNOSUPPORT;
if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
sock->state = SS_CONNECTED;
@@ -629,18 +857,26 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
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 */
@@ -704,8 +940,9 @@ static int irda_create(struct socket *sock, int protocol)
/* Check for valid socket type */
switch (sock->type) {
- case SOCK_STREAM: /* FALLTHROUGH */
- case SOCK_SEQPACKET:
+ case SOCK_STREAM: /* For TTP connections with SAR disabled */
+ case SOCK_SEQPACKET: /* For TTP connections with SAR enabled */
+ case SOCK_DGRAM: /* For TTP Unitdata or LMP Ultra transfers */
break;
default:
return -ESOCKTNOSUPPORT;
@@ -726,10 +963,35 @@ static int irda_create(struct socket *sock, int protocol)
sk->protinfo.irda = self;
sock_init_data(sock, sk);
- if (sock->type == SOCK_STREAM)
+ switch (sock->type) {
+ case SOCK_STREAM:
sock->ops = &irda_stream_ops;
- else
- sock->ops = &irda_dgram_ops;
+ self->max_sdu_size_rx = TTP_SAR_DISABLE;
+ break;
+ case SOCK_SEQPACKET:
+ sock->ops = &irda_seqpacket_ops;
+ self->max_sdu_size_rx = TTP_SAR_UNBOUND;
+ break;
+ case SOCK_DGRAM:
+ switch (protocol) {
+#ifdef CONFIG_IRDA_ULTRA
+ case IRDAPROTO_ULTRA:
+ sock->ops = &irda_ultra_ops;
+ break;
+#endif /* CONFIG_IRDA_ULTRA */
+ case IRDAPROTO_UNITDATA:
+ sock->ops = &irda_dgram_ops;
+ /* We let Unitdata conn. be like seqpack conn. */
+ self->max_sdu_size_rx = TTP_SAR_UNBOUND;
+ break;
+ default:
+ ERROR(__FUNCTION__ "(), protocol not supported!\n");
+ return -ESOCKTNOSUPPORT;
+ }
+ break;
+ default:
+ return -ESOCKTNOSUPPORT;
+ }
sk->protocol = protocol;
@@ -737,8 +999,8 @@ static int irda_create(struct socket *sock, int protocol)
self->ckey = irlmp_register_client(0, NULL, NULL);
self->mask = 0xffff;
self->rx_flow = self->tx_flow = FLOW_START;
- self->max_sdu_size_rx = SAR_DISABLE; /* Default value */
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();
@@ -774,7 +1036,12 @@ void irda_destroy_socket(struct irda_sock *self)
irttp_close_tsap(self->tsap);
self->tsap = NULL;
}
-
+#ifdef CONFIG_IRDA_ULTRA
+ if (self->lsap) {
+ irlmp_close_lsap(self->lsap);
+ self->lsap = NULL;
+ }
+#endif /* CONFIG_IRDA_ULTRA */
kfree(self);
/* Notify that we are not using the irda module anymore */
@@ -784,7 +1051,7 @@ void irda_destroy_socket(struct irda_sock *self)
}
/*
- * Function irda_release (sock, peer)
+ * Function irda_release (sock)
*
*
*
@@ -793,7 +1060,7 @@ static int irda_release(struct socket *sock)
{
struct sock *sk = sock->sk;
- IRDA_DEBUG(1, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
if (sk == NULL)
return 0;
@@ -814,14 +1081,14 @@ static int irda_release(struct socket *sock)
/*
* Function irda_sendmsg (sock, msg, len, scm)
*
- * Send message down to TinyTP
- *
+ * Send message down to TinyTP. This function is used for both STREAM and
+ * SEQPACK services. This is possible since it forces the client to
+ * fragment the message if necessary
*/
static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
-/* struct sockaddr_irda *addr = (struct sockaddr_irda *) msg->msg_name; */
struct irda_sock *self;
struct sk_buff *skb;
unsigned char *asmptr;
@@ -855,9 +1122,9 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
/* Check that we don't send out to big frames */
if (len > self->max_data_size) {
- IRDA_DEBUG(0, __FUNCTION__ "(), Warning to much data! "
- "Chopping frame from %d to %d bytes!\n", len,
- self->max_data_size);
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), Chopping frame from %d to %d bytes!\n", len,
+ self->max_data_size);
len = self->max_data_size;
}
@@ -868,7 +1135,6 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
skb_reserve(skb, self->max_header_size);
- IRDA_DEBUG(4, __FUNCTION__ "(), appending user data\n");
asmptr = skb->h.raw = skb_put(skb, len);
memcpy_fromiovec(asmptr, msg->msg_iov, len);
@@ -881,14 +1147,15 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
IRDA_DEBUG(0, __FUNCTION__ "(), err=%d\n", err);
return err;
}
+ /* Tell client how much data we actually sent */
return len;
}
/*
- * Function irda_recvmsg (sock, msg, size, flags, scm)
- *
- * Try to receive message and copy it to user
+ * Function irda_recvmsg_dgram (sock, msg, size, flags, scm)
*
+ * Try to receive message and copy it to user. The frame is discarded
+ * after being read, regardless of how much the user actually read
*/
static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg,
int size, int flags, struct scm_cookie *scm)
@@ -912,6 +1179,9 @@ static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg,
copied = skb->len;
if (copied > size) {
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), Received truncated frame (%d < %d)!\n",
+ copied, size);
copied = size;
msg->msg_flags |= MSG_TRUNC;
}
@@ -980,7 +1250,6 @@ static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg,
if (flags & MSG_WAITALL)
target = size;
-
msg->msg_namelen = 0;
do {
@@ -1060,6 +1329,132 @@ static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg,
}
/*
+ * Function irda_sendmsg_dgram (sock, msg, len, scm)
+ *
+ * Send message down to TinyTP for the unreliable sequenced
+ * packet service...
+ *
+ */
+static int irda_sendmsg_dgram(struct socket *sock, struct msghdr *msg,
+ int len, struct scm_cookie *scm)
+{
+ struct sock *sk = sock->sk;
+ struct irda_sock *self;
+ struct sk_buff *skb;
+ unsigned char *asmptr;
+ int err;
+
+ IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
+
+ if (msg->msg_flags & ~MSG_DONTWAIT)
+ return -EINVAL;
+
+ if (sk->shutdown & SEND_SHUTDOWN) {
+ send_sig(SIGPIPE, current, 0);
+ return -EPIPE;
+ }
+
+ if (sk->state != TCP_ESTABLISHED)
+ return -ENOTCONN;
+
+ self = sk->protinfo.irda;
+ ASSERT(self != NULL, return -1;);
+
+ /*
+ * Check that we don't send out to big frames. This is an unreliable
+ * service, so we have no fragmentation and no coalescence
+ */
+ if (len > self->max_data_size) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), Warning to much data! "
+ "Chopping frame from %d to %d bytes!\n", len,
+ self->max_data_size);
+ len = self->max_data_size;
+ }
+
+ skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0,
+ msg->msg_flags & MSG_DONTWAIT, &err);
+ if (!skb)
+ return -ENOBUFS;
+
+ skb_reserve(skb, self->max_header_size);
+
+ IRDA_DEBUG(4, __FUNCTION__ "(), appending user data\n");
+ asmptr = skb->h.raw = skb_put(skb, len);
+ memcpy_fromiovec(asmptr, msg->msg_iov, len);
+
+ /*
+ * Just send the message to TinyTP, and let it deal with possible
+ * errors. No need to duplicate all that here
+ */
+ err = irttp_udata_request(self->tsap, skb);
+ if (err) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), err=%d\n", err);
+ return err;
+ }
+ return len;
+}
+
+/*
+ * Function irda_sendmsg_ultra (sock, msg, len, scm)
+ *
+ * Send message down to IrLMP for the unreliable Ultra
+ * packet service...
+ */
+#ifdef CONFIG_IRDA_ULTRA
+static int irda_sendmsg_ultra(struct socket *sock, struct msghdr *msg,
+ int len, struct scm_cookie *scm)
+{
+ struct sock *sk = sock->sk;
+ struct irda_sock *self;
+ struct sk_buff *skb;
+ unsigned char *asmptr;
+ int err;
+
+ IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
+
+ if (msg->msg_flags & ~MSG_DONTWAIT)
+ return -EINVAL;
+
+ if (sk->shutdown & SEND_SHUTDOWN) {
+ send_sig(SIGPIPE, current, 0);
+ return -EPIPE;
+ }
+
+ self = sk->protinfo.irda;
+ ASSERT(self != NULL, return -1;);
+
+ /*
+ * Check that we don't send out to big frames. This is an unreliable
+ * service, so we have no fragmentation and no coalescence
+ */
+ if (len > self->max_data_size) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), Warning to much data! "
+ "Chopping frame from %d to %d bytes!\n", len,
+ self->max_data_size);
+ len = self->max_data_size;
+ }
+
+ skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0,
+ msg->msg_flags & MSG_DONTWAIT, &err);
+ if (!skb)
+ return -ENOBUFS;
+
+ skb_reserve(skb, self->max_header_size);
+
+ IRDA_DEBUG(4, __FUNCTION__ "(), appending user data\n");
+ asmptr = skb->h.raw = skb_put(skb, len);
+ memcpy_fromiovec(asmptr, msg->msg_iov, len);
+
+ err = irlmp_connless_data_request(self->lsap, skb);
+ if (err) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), err=%d\n", err);
+ return err;
+ }
+ return len;
+}
+#endif /* CONFIG_IRDA_ULTRA */
+
+/*
* Function irda_shutdown (sk, how)
*
*
@@ -1070,7 +1465,7 @@ static int irda_shutdown(struct socket *sock, int how)
struct irda_sock *self;
struct sock *sk = sock->sk;
- IRDA_DEBUG( 0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
self = sk->protinfo.irda;
ASSERT(self != NULL, return -1;);
@@ -1103,7 +1498,7 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
struct sock *sk = sock->sk;
unsigned int mask;
- IRDA_DEBUG(1, __FUNCTION__ "()\n");
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
poll_wait(file, sk->sleep, wait);
mask = 0;
@@ -1115,9 +1510,10 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
mask |= POLLHUP;
/* readable? */
- if (!skb_queue_empty(&sk->receive_queue))
+ if (!skb_queue_empty(&sk->receive_queue)) {
+ IRDA_DEBUG(4, "Socket is readable\n");
mask |= POLLIN | POLLRDNORM;
-
+ }
/* Connection-based need to check for termination and startup */
if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)
mask |= POLLHUP;
@@ -1208,6 +1604,8 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
{
struct sock *sk = sock->sk;
struct irda_sock *self;
+ struct irda_ias_set ias_opt;
+ struct ias_object *ias_obj;
int opt;
self = sk->protinfo.irda;
@@ -1215,20 +1613,101 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
if (level != SOL_IRLMP)
return -ENOPROTOOPT;
-
- if (optlen < sizeof(int))
- return -EINVAL;
-
- if (get_user(opt, (int *)optval))
- return -EFAULT;
-
+
switch (optname) {
case IRLMP_IAS_SET:
+ if (optlen != sizeof(struct irda_ias_set))
+ return -EINVAL;
+
+ /* Copy query to the driver. */
+ if (copy_from_user(&ias_opt, (char *)optval, optlen))
+ return -EFAULT;
+
+ /* Find the object we target */
+ ias_obj = irias_find_object(ias_opt.irda_class_name);
+ if(ias_obj == (struct ias_object *) NULL) {
+ /* Create a new object */
+ ias_obj = irias_new_object(ias_opt.irda_class_name,
+ jiffies);
+ }
+
+ /* Do we have it already ? */
+ if(irias_find_attrib(ias_obj, ias_opt.irda_attrib_name))
+ return -EINVAL;
+
+ /* Look at the type */
+ switch(ias_opt.irda_attrib_type) {
+ case IAS_INTEGER:
+ /* Add an integer attribute */
+ irias_add_integer_attrib(ias_obj,
+ ias_opt.irda_attrib_name,
+ ias_opt.attribute.irda_attrib_int);
+ break;
+ case IAS_OCT_SEQ:
+ /* Check length */
+ if(ias_opt.attribute.irda_attrib_octet_seq.len >
+ IAS_MAX_OCTET_STRING)
+ return -EINVAL;
+ /* Add an octet sequence attribute */
+ irias_add_octseq_attrib(
+ ias_obj,
+ ias_opt.irda_attrib_name,
+ ias_opt.attribute.irda_attrib_octet_seq.octet_seq,
+ ias_opt.attribute.irda_attrib_octet_seq.len);
+ break;
+ case IAS_STRING:
+ /* Should check charset & co */
+ /* Check length */
+ if(ias_opt.attribute.irda_attrib_string.len >
+ IAS_MAX_STRING)
+ return -EINVAL;
+ /* NULL terminate the string (avoid troubles) */
+ ias_opt.attribute.irda_attrib_string.string[ias_opt.attribute.irda_attrib_string.len] = '\0';
+ /* Add a string attribute */
+ irias_add_string_attrib(
+ ias_obj,
+ ias_opt.irda_attrib_name,
+ ias_opt.attribute.irda_attrib_string.string);
+ break;
+ default :
+ return -EINVAL;
+ }
+ irias_insert_object(ias_obj);
+ break;
+
IRDA_DEBUG(0, __FUNCTION__ "(), sorry not impl. yet!\n");
return -ENOPROTOOPT;
- case IRTTP_MAX_SDU_SIZE:
- IRDA_DEBUG(2, __FUNCTION__ "(), setting max_sdu_size = %d\n", opt);
- self->max_sdu_size_rx = opt;
+ case IRLMP_MAX_SDU_SIZE:
+ if (optlen < sizeof(int))
+ return -EINVAL;
+
+ if (get_user(opt, (int *)optval))
+ return -EFAULT;
+
+ /* Only possible for a seqpacket service (TTP with SAR) */
+ if (sk->type != SOCK_SEQPACKET) {
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), setting max_sdu_size = %d\n", opt);
+ self->max_sdu_size_rx = opt;
+ } else {
+ WARNING(__FUNCTION__
+ "(), not allowed to set MAXSDUSIZE for this "
+ "socket type!\n");
+ return -ENOPROTOOPT;
+ }
+ break;
+ case IRLMP_HINTS_SET:
+ if (optlen < sizeof(int))
+ return -EINVAL;
+
+ if (get_user(opt, (int *)optval))
+ return -EFAULT;
+
+ /* Unregister any old registration */
+ if (self->skey)
+ irlmp_unregister_service(self->skey);
+
+ self->skey = irlmp_register_service((__u16) opt);
break;
default:
return -ENOPROTOOPT;
@@ -1236,6 +1715,104 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
return 0;
}
+ /*
+ * Function irda_simple_getvalue_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_getvalue_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 = -EHOSTUNREACH;
+
+ /* 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));
+ irias_delete_value(value);
+
+ self->errno = 0;
+
+ /* 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.octet_seq,
+ 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)
*
@@ -1250,8 +1827,12 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
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 val = 0;
int len = 0;
+ int err;
int offset, total;
self = sk->protinfo.irda;
@@ -1293,9 +1874,8 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
while (discovery != NULL) {
/* Mask out the ones we don't want */
if (discovery->hints.word & self->mask) {
-
/* Check if room for this device entry */
- if (len - total < sizeof(struct irda_device_info))
+ if (len-total<sizeof(struct irda_device_info))
break;
/* Copy discovery information */
@@ -1307,7 +1887,7 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
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++;
@@ -1327,7 +1907,7 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
sizeof(struct irda_device_info)))
return -EFAULT;
break;
- case IRTTP_MAX_SDU_SIZE:
+ case IRLMP_MAX_SDU_SIZE:
val = self->max_data_size;
len = sizeof(int);
if (put_user(len, optlen))
@@ -1336,10 +1916,95 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
if (copy_to_user(optval, &val, len))
return -EFAULT;
break;
+ 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 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_getvalue_confirm);
+
+ /* Treat unexpected signals as disconnect */
+ self->errno = -EHOSTUNREACH;
+
+ /* Query remote LM-IAS */
+ iriap_getvaluebyclass_request(self->iriap,
+ self->saddr, self->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);
+ if (self->ias_result)
+ kfree(self->ias_result);
+ 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;
}
-
+
return 0;
}
@@ -1370,7 +2035,7 @@ static struct proto_ops SOCKOPS_WRAPPED(irda_stream_ops) = {
sock_no_mmap
};
-static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = {
+static struct proto_ops SOCKOPS_WRAPPED(irda_seqpacket_ops) = {
PF_IRDA,
irda_release,
@@ -1388,12 +2053,57 @@ static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = {
sock_no_fcntl,
irda_sendmsg,
irda_recvmsg_dgram,
- sock_no_mmap
+ sock_no_mmap,
+};
+
+static struct proto_ops SOCKOPS_WRAPPED(irda_dgram_ops) = {
+ PF_IRDA,
+
+ irda_release,
+ irda_bind,
+ irda_connect,
+ sock_no_socketpair,
+ irda_accept,
+ irda_getname,
+ datagram_poll,
+ irda_ioctl,
+ irda_listen,
+ irda_shutdown,
+ irda_setsockopt,
+ irda_getsockopt,
+ sock_no_fcntl,
+ irda_sendmsg_dgram,
+ irda_recvmsg_dgram,
+ sock_no_mmap,
};
+#ifdef CONFIG_IRDA_ULTRA
+static struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = {
+ PF_IRDA,
+
+ irda_release,
+ irda_bind,
+ sock_no_connect,
+ sock_no_socketpair,
+ sock_no_accept,
+ irda_getname,
+ datagram_poll,
+ irda_ioctl,
+ sock_no_listen,
+ irda_shutdown,
+ irda_setsockopt,
+ irda_getsockopt,
+ sock_no_fcntl,
+ irda_sendmsg_ultra,
+ irda_recvmsg_dgram,
+ sock_no_mmap,
+};
+#endif /* CONFIG_IRDA_ULTRA */
+
#include <linux/smp_lock.h>
-SOCKOPS_WRAP(irda_dgram, PF_IRDA);
SOCKOPS_WRAP(irda_stream, PF_IRDA);
+SOCKOPS_WRAP(irda_seqpacket, PF_IRDA);
+SOCKOPS_WRAP(irda_dgram, PF_IRDA);
/*
* Function irda_device_event (this, event, ptr)
diff --git a/net/irda/discovery.c b/net/irda/discovery.c
index 84d0239e3..957426154 100644
--- a/net/irda/discovery.c
+++ b/net/irda/discovery.c
@@ -209,7 +209,8 @@ __u32 irlmp_find_device(hashbin_t *cachelog, char *name, __u32 *saddr)
* Print discovery information in /proc file system
*
*/
-int discovery_proc_read(char *buf, char **start, off_t offset, int len)
+int discovery_proc_read(char *buf, char **start, off_t offset, int len,
+ int unused)
{
discovery_t *discovery;
unsigned long flags;
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
index ed45a509f..805186128 100644
--- a/net/irda/ircomm/ircomm_core.c
+++ b/net/irda/ircomm/ircomm_core.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Jun 6 20:37:34 1999
- * Modified at: Sat Oct 30 12:48:14 1999
+ * Modified at: Tue Dec 21 13:26:41 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -144,16 +144,14 @@ static int __ircomm_close(struct ircomm_cb *self)
{
IRDA_DEBUG(2, __FUNCTION__"()\n");
- ASSERT(self != NULL, return -EIO;);
- ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
-
/* Disconnect link if any */
ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
/* Remove TSAP */
- if (self->tsap)
+ if (self->tsap) {
irttp_close_tsap(self->tsap);
- self->tsap = NULL;
+ self->tsap = NULL;
+ }
/* Remove LSAP */
if (self->lsap) {
@@ -177,6 +175,11 @@ int ircomm_close(struct ircomm_cb *self)
{
struct ircomm_cb *entry;
+ ASSERT(self != NULL, return -EIO;);
+ ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
entry = hashbin_remove(ircomm, self->line, NULL);
ASSERT(entry == self, return -1;);
@@ -236,14 +239,14 @@ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
* deliver it first. The side effect is that the control channel
* will be removed from the skb
*/
-#if 0
- if (clen > 0)
- ircomm_control_indication(self, skb, clen);
-#endif
if (self->notify.connect_indication)
self->notify.connect_indication(self->notify.instance, self,
info->qos, info->max_data_size,
info->max_header_size, skb);
+ else {
+ IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+ dev_kfree_skb(skb);
+ }
}
/*
@@ -282,6 +285,10 @@ void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
self, info->qos,
info->max_data_size,
info->max_header_size, skb);
+ else {
+ IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+ dev_kfree_skb(skb);
+ }
}
/*
@@ -319,6 +326,10 @@ void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
if (self->notify.data_indication)
self->notify.data_indication(self->notify.instance, self, skb);
+ else {
+ IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+ dev_kfree_skb(skb);
+ }
}
/*
@@ -349,7 +360,8 @@ void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
if (skb->len)
ircomm_data_indication(self, skb);
else {
- IRDA_DEBUG(4, __FUNCTION__ "(), data was control info only!\n");
+ IRDA_DEBUG(4, __FUNCTION__
+ "(), data was control info only!\n");
dev_kfree_skb(skb);
}
}
@@ -399,6 +411,10 @@ static void ircomm_control_indication(struct ircomm_cb *self,
if (self->notify.udata_indication)
self->notify.udata_indication(self->notify.instance, self,
ctrl_skb);
+ else {
+ IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+ dev_kfree_skb(skb);
+ }
}
/*
@@ -438,6 +454,9 @@ void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
if (self->notify.disconnect_indication) {
self->notify.disconnect_indication(self->notify.instance, self,
info->reason, skb);
+ } else {
+ IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
+ dev_kfree_skb(skb);
}
}
@@ -462,7 +481,7 @@ void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
#ifdef CONFIG_PROC_FS
/*
- * Function ircomm_proc_read (buf, start, offset, len)
+ * Function ircomm_proc_read (buf, start, offset, len, unused)
*
*
*
diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c
index 7e2bdd50a..5b43be858 100644
--- a/net/irda/ircomm/ircomm_event.c
+++ b/net/irda/ircomm/ircomm_event.c
@@ -3,10 +3,10 @@
* Filename: ircomm_event.c
* Version: 1.0
* Description: IrCOMM layer state machine
- * Status: Experimental.
+ * Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Jun 6 20:33:11 1999
- * Modified at: Sat Oct 30 13:05:23 1999
+ * Modified at: Sun Dec 12 13:44:32 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -109,6 +109,8 @@ static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
default:
IRDA_DEBUG(4, __FUNCTION__"(), unknown event: %s\n",
ircomm_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
return -EINVAL;
}
return ret;
@@ -139,6 +141,8 @@ static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
default:
IRDA_DEBUG(0, __FUNCTION__"(), unknown event: %s\n",
ircomm_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
ret = -EINVAL;
}
return ret;
@@ -172,6 +176,8 @@ static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
default:
IRDA_DEBUG(0, __FUNCTION__ "(), unknown event = %s\n",
ircomm_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
ret = -EINVAL;
}
return ret;
@@ -214,6 +220,8 @@ static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
default:
IRDA_DEBUG(0, __FUNCTION__ "(), unknown event = %s\n",
ircomm_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
ret = -EINVAL;
}
return ret;
diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c
index bf35c75e0..ca4526260 100644
--- a/net/irda/ircomm/ircomm_lmp.c
+++ b/net/irda/ircomm/ircomm_lmp.c
@@ -1,12 +1,12 @@
/*********************************************************************
*
* Filename: ircomm_lmp.c
- * Version:
+ * Version: 1.0
* Description: Interface between IrCOMM and IrLMP
- * Status: Experimental.
+ * Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Jun 6 20:48:27 1999
- * Modified at: Sat Oct 30 12:55:24 1999
+ * Modified at: Sun Dec 12 13:44:17 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: Previous IrLPT work by Thomas Davis
*
@@ -60,7 +60,7 @@ int ircomm_open_lsap(struct ircomm_cb *self)
notify.instance = self;
strncpy(notify.name, "IrCOMM", NOTIFY_MAX_NAME);
- self->lsap = irlmp_open_lsap(LSAP_ANY, &notify);
+ self->lsap = irlmp_open_lsap(LSAP_ANY, &notify, 0);
if (!self->lsap) {
IRDA_DEBUG(0,__FUNCTION__"failed to allocate tsap\n");
return -1;
@@ -128,11 +128,8 @@ int ircomm_lmp_disconnect_request(struct ircomm_cb *self,
if (!skb)
return -ENOMEM;
- /*
- * Reserve space for MUX and LAP header
- */
- skb_reserve(skb, LMP_MAX_HEADER);
-
+ /* Reserve space for MUX and LAP header */
+ skb_reserve(skb, LMP_MAX_HEADER);
userdata = skb;
}
ret = irlmp_disconnect_request(self->lsap, userdata);
@@ -323,5 +320,3 @@ void ircomm_lmp_disconnect_indication(void *instance, void *sap,
ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info);
}
-
-
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
index 382027892..3c9ff35da 100644
--- a/net/irda/ircomm/ircomm_param.c
+++ b/net/irda/ircomm/ircomm_param.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Jun 7 10:25:11 1999
- * Modified at: Sat Oct 30 13:05:42 1999
+ * Modified at: Tue Dec 14 15:26:30 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -28,6 +28,9 @@
*
********************************************************************/
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
#include <net/irda/irda.h>
#include <net/irda/parameters.h>
@@ -67,7 +70,7 @@ static pi_minor_info_t pi_minor_call_table_non_raw[] = {
static pi_minor_info_t pi_minor_call_table_9_wire[] = {
{ ircomm_param_dte, PV_INT_8_BITS },
{ ircomm_param_dce, PV_INT_8_BITS },
- { ircomm_param_poll, PV_INT_8_BITS },
+ { ircomm_param_poll, PV_NO_VALUE },
};
static pi_major_info_t pi_major_call_table[] = {
@@ -102,6 +105,7 @@ int ircomm_param_flush(struct ircomm_tty_cb *self)
*/
int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
{
+ struct tty_struct *tty;
unsigned long flags;
struct sk_buff *skb;
int count;
@@ -111,10 +115,9 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
- if (self->state != IRCOMM_TTY_READY) {
- IRDA_DEBUG(2, __FUNCTION__ "(), not ready yet!\n");
+ tty = self->tty;
+ if (!tty)
return 0;
- }
/* Make sure we don't send parameters for raw mode */
if (self->service_type == IRCOMM_3_WIRE_RAW)
@@ -132,8 +135,7 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
}
skb_reserve(skb, self->max_header_size);
-
- self->ctrl_skb = skb;
+ self->ctrl_skb = skb;
}
/*
* Inserting is a little bit tricky since we don't know how much
@@ -142,17 +144,22 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
count = irda_param_insert(self, pi, skb->tail, skb_tailroom(skb),
&ircomm_param_info);
if (count < 0) {
- IRDA_DEBUG(0, __FUNCTION__ "(), no room for parameter!\n");
+ WARNING(__FUNCTION__ "(), no room for parameter!\n");
restore_flags(flags);
return -1;
}
skb_put(skb, count);
+
restore_flags(flags);
+ IRDA_DEBUG(2, __FUNCTION__ "(), skb->len=%d\n", skb->len);
+
if (flush) {
- ircomm_control_request(self->ircomm, skb);
- self->ctrl_skb = NULL;
+ /* ircomm_tty_do_softint will take care of the rest */
+ queue_task(&self->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
}
+
return count;
}
@@ -172,38 +179,45 @@ static int ircomm_param_service_type(void *instance, param_t *param, int get)
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
if (get) {
- param->pv.b = self->session.service_type;
+ param->pv.b = self->settings.service_type;
return 0;
}
+ /* Find all common service types */
+ service_type &= self->service_type;
+ if (!service_type) {
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), No common service type to use!\n");
+ return -1;
+ }
+ IRDA_DEBUG(0, __FUNCTION__ "(), services in common=%02x\n",
+ service_type);
+
/*
* Now choose a preferred service type of those available
*/
- if (service_type & IRCOMM_3_WIRE_RAW) {
- IRDA_DEBUG(2, __FUNCTION__ "(), peer supports 3 wire raw\n");
- self->session.service_type |= IRCOMM_3_WIRE_RAW;
- }
- if (service_type & IRCOMM_3_WIRE) {
- IRDA_DEBUG(2, __FUNCTION__ "(), peer supports 3 wire\n");
- self->session.service_type |= IRCOMM_3_WIRE;
- }
- if (service_type & IRCOMM_9_WIRE) {
- IRDA_DEBUG(2, __FUNCTION__ "(), peer supports 9 wire\n");
- self->session.service_type |= IRCOMM_9_WIRE;
- }
- if (service_type & IRCOMM_CENTRONICS) {
- IRDA_DEBUG(2, __FUNCTION__ "(), peer supports Centronics\n");
- self->session.service_type |= IRCOMM_CENTRONICS;
- }
-
- self->session.service_type &= self->service_type;
- if (!self->session.service_type) {
- IRDA_DEBUG(2, __FUNCTION__"(), No common service type to use!\n");
- return -1;
+ if (service_type & IRCOMM_CENTRONICS)
+ self->settings.service_type = IRCOMM_CENTRONICS;
+ else if (service_type & IRCOMM_9_WIRE)
+ self->settings.service_type = IRCOMM_9_WIRE;
+ else if (service_type & IRCOMM_3_WIRE)
+ self->settings.service_type = IRCOMM_3_WIRE;
+ else if (service_type & IRCOMM_3_WIRE_RAW)
+ self->settings.service_type = IRCOMM_3_WIRE_RAW;
+
+ IRDA_DEBUG(0, __FUNCTION__ "(), resulting service type=0x%02x\n",
+ self->settings.service_type);
+
+ /*
+ * Now the line is ready for some communication. Check if we are a
+ * server, and send over some initial parameters
+ */
+ if (!self->client && (self->settings.service_type != IRCOMM_3_WIRE_RAW))
+ {
+ /* Init connection */
+ ircomm_tty_send_initial_parameters(self);
+ ircomm_tty_link_established(self);
}
-
- IRDA_DEBUG(2, __FUNCTION__ "(), resulting service type=0x%02x\n",
- self->session.service_type);
return 0;
}
@@ -225,10 +239,10 @@ static int ircomm_param_port_type(void *instance, param_t *param, int get)
if (get)
param->pv.b = IRCOMM_SERIAL;
else {
- self->session.port_type = param->pv.b;
+ self->settings.port_type = param->pv.b;
IRDA_DEBUG(0, __FUNCTION__ "(), port type=%d\n",
- self->session.port_type);
+ self->settings.port_type);
}
return 0;
}
@@ -250,7 +264,7 @@ static int ircomm_param_port_name(void *instance, param_t *param, int get)
IRDA_DEBUG(0, __FUNCTION__ "(), not imp!\n");
} else {
IRDA_DEBUG(0, __FUNCTION__ "(), port-name=%s\n", param->pv.c);
- strncpy(self->session.port_name, param->pv.c, 32);
+ strncpy(self->settings.port_name, param->pv.c, 32);
}
return 0;
@@ -259,7 +273,7 @@ static int ircomm_param_port_name(void *instance, param_t *param, int get)
/*
* Function ircomm_param_data_rate (self, param)
*
- * Exchange data rate to be used in this session
+ * Exchange data rate to be used in this settings
*
*/
static int ircomm_param_data_rate(void *instance, param_t *param, int get)
@@ -270,9 +284,9 @@ static int ircomm_param_data_rate(void *instance, param_t *param, int get)
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
if (get)
- param->pv.i = self->session.data_rate;
+ param->pv.i = self->settings.data_rate;
else
- self->session.data_rate = param->pv.i;
+ self->settings.data_rate = param->pv.i;
IRDA_DEBUG(2, __FUNCTION__ "(), data rate = %d\n", param->pv.i);
@@ -282,7 +296,7 @@ static int ircomm_param_data_rate(void *instance, param_t *param, int get)
/*
* Function ircomm_param_data_format (self, param)
*
- * Exchange data format to be used in this session
+ * Exchange data format to be used in this settings
*
*/
static int ircomm_param_data_format(void *instance, param_t *param, int get)
@@ -293,9 +307,9 @@ static int ircomm_param_data_format(void *instance, param_t *param, int get)
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
if (get)
- param->pv.b = self->session.data_format;
+ param->pv.b = self->settings.data_format;
else
- self->session.data_format = param->pv.b;
+ self->settings.data_format = param->pv.b;
return 0;
}
@@ -303,7 +317,7 @@ static int ircomm_param_data_format(void *instance, param_t *param, int get)
/*
* Function ircomm_param_flow_control (self, param)
*
- * Exchange flow control settings to be used in this session
+ * Exchange flow control settings to be used in this settings
*
*/
static int ircomm_param_flow_control(void *instance, param_t *param, int get)
@@ -314,9 +328,9 @@ static int ircomm_param_flow_control(void *instance, param_t *param, int get)
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
if (get)
- param->pv.b = self->session.flow_control;
+ param->pv.b = self->settings.flow_control;
else
- self->session.flow_control = param->pv.b;
+ self->settings.flow_control = param->pv.b;
IRDA_DEBUG(1, __FUNCTION__ "(), flow control = 0x%02x\n", param->pv.b);
@@ -337,14 +351,14 @@ static int ircomm_param_xon_xoff(void *instance, param_t *param, int get)
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
if (get) {
- param->pv.s = self->session.xonxoff[0];
- param->pv.s |= self->session.xonxoff[1] << 8;
+ param->pv.s = self->settings.xonxoff[0];
+ param->pv.s |= self->settings.xonxoff[1] << 8;
} else {
- self->session.xonxoff[0] = param->pv.s & 0xff;
- self->session.xonxoff[1] = param->pv.s >> 8;
+ self->settings.xonxoff[0] = param->pv.s & 0xff;
+ self->settings.xonxoff[1] = param->pv.s >> 8;
}
- IRDA_DEBUG(0, __FUNCTION__ "(), XON/XOFF = 0x%02x\n,0x%02x",
+ IRDA_DEBUG(0, __FUNCTION__ "(), XON/XOFF = 0x%02x,0x%02x\n",
param->pv.s & 0xff, param->pv.s >> 8);
return 0;
@@ -364,11 +378,11 @@ static int ircomm_param_enq_ack(void *instance, param_t *param, int get)
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
if (get) {
- param->pv.s = self->session.enqack[0];
- param->pv.s |= self->session.enqack[1] << 8;
+ param->pv.s = self->settings.enqack[0];
+ param->pv.s |= self->settings.enqack[1] << 8;
} else {
- self->session.enqack[0] = param->pv.s & 0xff;
- self->session.enqack[1] = param->pv.s >> 8;
+ self->settings.enqack[0] = param->pv.s & 0xff;
+ self->settings.enqack[1] = param->pv.s >> 8;
}
IRDA_DEBUG(0, __FUNCTION__ "(), ENQ/ACK = 0x%02x,0x%02x\n",
@@ -405,29 +419,29 @@ static int ircomm_param_dte(void *instance, param_t *param, int get)
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
if (get)
- param->pv.b = self->session.dte;
+ param->pv.b = self->settings.dte;
else {
dte = param->pv.b;
if (dte & IRCOMM_DELTA_DTR)
- self->session.dce |= (IRCOMM_DELTA_DSR|
+ self->settings.dce |= (IRCOMM_DELTA_DSR|
IRCOMM_DELTA_RI |
IRCOMM_DELTA_CD);
if (dte & IRCOMM_DTR)
- self->session.dce |= (IRCOMM_DSR|
+ self->settings.dce |= (IRCOMM_DSR|
IRCOMM_RI |
IRCOMM_CD);
if (dte & IRCOMM_DELTA_RTS)
- self->session.dce |= IRCOMM_DELTA_CTS;
+ self->settings.dce |= IRCOMM_DELTA_CTS;
if (dte & IRCOMM_RTS)
- self->session.dce |= IRCOMM_CTS;
+ self->settings.dce |= IRCOMM_CTS;
/* Take appropriate actions */
ircomm_tty_check_modem_status(self);
/* Null modem cable emulator */
- self->session.null_modem = TRUE;
+ self->settings.null_modem = TRUE;
}
return 0;
@@ -451,7 +465,7 @@ static int ircomm_param_dce(void *instance, param_t *param, int get)
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
- self->session.dce = dce;
+ self->settings.dce = dce;
/* Check if any of the settings have changed */
if (dce & 0x0f) {
@@ -483,7 +497,6 @@ static int ircomm_param_poll(void *instance, param_t *param, int get)
/* Respond with DTE line settings */
ircomm_param_request(self, IRCOMM_DTE, TRUE);
}
-
return 0;
}
diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c
index 211bc14a8..642b8416a 100644
--- a/net/irda/ircomm/ircomm_ttp.c
+++ b/net/irda/ircomm/ircomm_ttp.c
@@ -1,12 +1,12 @@
/*********************************************************************
*
* Filename: ircomm_ttp.c
- * Version:
+ * Version: 1.0
* Description: Interface between IrCOMM and IrTTP
- * Status: Experimental.
+ * Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Jun 6 20:48:27 1999
- * Modified at: Sat Oct 30 12:55:36 1999
+ * Modified at: Mon Dec 13 11:35:13 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -64,7 +64,7 @@ int ircomm_open_tsap(struct ircomm_cb *self)
self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
&notify);
if (!self->tsap) {
- IRDA_DEBUG(0,__FUNCTION__"failed to allocate tsap\n");
+ IRDA_DEBUG(0, __FUNCTION__"failed to allocate tsap\n");
return -1;
}
self->slsap_sel = self->tsap->stsap_sel;
@@ -95,8 +95,8 @@ int ircomm_ttp_connect_request(struct ircomm_cb *self,
IRDA_DEBUG(4, __FUNCTION__ "()\n");
ret = irttp_connect_request(self->tsap, info->dlsap_sel,
- info->saddr, info->daddr,
- NULL, SAR_DISABLE, userdata);
+ info->saddr, info->daddr, NULL,
+ TTP_SAR_DISABLE, userdata);
return ret;
}
@@ -112,7 +112,7 @@ int ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb)
IRDA_DEBUG(4, __FUNCTION__"()\n");
- ret = irttp_connect_response(self->tsap, SAR_DISABLE, skb);
+ ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, skb);
return ret;
}
@@ -139,7 +139,7 @@ int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
* Insert clen field, currently we either send data only, or control
* only frames, to make things easier and avoid queueing
*/
- ASSERT(skb_headroom(skb) >= 1, return -1;);
+ ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
skb_push(skb, IRCOMM_HEADER_SIZE);
skb->data[0] = clen;
@@ -191,12 +191,13 @@ void ircomm_ttp_connect_confirm(void *instance, void *sap,
ASSERT(skb != NULL, return;);
ASSERT(qos != NULL, return;);
- if (max_sdu_size != SAR_DISABLE) {
+ if (max_sdu_size != TTP_SAR_DISABLE) {
ERROR(__FUNCTION__ "(), SAR not allowed for IrCOMM!\n");
+ dev_kfree_skb(skb);
return;
}
- info.max_data_size = irttp_get_max_seq_size(self->tsap)
+ info.max_data_size = irttp_get_max_seg_size(self->tsap)
- IRCOMM_HEADER_SIZE;
info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
info.qos = qos;
@@ -227,12 +228,13 @@ void ircomm_ttp_connect_indication(void *instance, void *sap,
ASSERT(skb != NULL, return;);
ASSERT(qos != NULL, return;);
- if (max_sdu_size != SAR_DISABLE) {
+ if (max_sdu_size != TTP_SAR_DISABLE) {
ERROR(__FUNCTION__ "(), SAR not allowed for IrCOMM!\n");
+ dev_kfree_skb(skb);
return;
}
- info.max_data_size = irttp_get_max_seq_size(self->tsap)
+ info.max_data_size = irttp_get_max_seg_size(self->tsap)
- IRCOMM_HEADER_SIZE;
info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
info.qos = qos;
@@ -270,7 +272,7 @@ void ircomm_ttp_disconnect_indication(void *instance, void *sap,
struct ircomm_cb *self = (struct ircomm_cb *) instance;
struct ircomm_info info;
- IRDA_DEBUG(4, __FUNCTION__"()\n");
+ IRDA_DEBUG(2, __FUNCTION__"()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_MAGIC, return;);
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index e79b10bcd..b53f8a8cf 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -6,11 +6,11 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Jun 6 21:00:56 1999
- * Modified at: Sat Oct 30 12:49:26 1999
+ * Modified at: Tue Jan 4 14:12:06 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: serial.c and previous IrCOMM work by Takahide Higuchi
*
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1999-2000 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
@@ -61,6 +61,7 @@ static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch);
static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout);
static void ircomm_tty_hangup(struct tty_struct *tty);
static void ircomm_tty_do_softint(void *private_);
+static void ircomm_tty_shutdown(struct ircomm_tty_cb *self);
static int ircomm_tty_data_indication(void *instance, void *sap,
struct sk_buff *skb);
@@ -134,6 +135,20 @@ int __init ircomm_tty_init(void)
return 0;
}
+#ifdef MODULE
+static void __ircomm_tty_cleanup(struct ircomm_tty_cb *self)
+{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+ ircomm_tty_shutdown(self);
+
+ self->magic = 0;
+ kfree(self);
+}
+
/*
* Function ircomm_tty_cleanup ()
*
@@ -144,7 +159,7 @@ void ircomm_tty_cleanup(void)
{
int ret;
- IRDA_DEBUG(4, __FUNCTION__"()\n");
+ IRDA_DEBUG(4, __FUNCTION__"()\n");
ret = tty_unregister_driver(&driver);
if (ret) {
@@ -152,8 +167,9 @@ void ircomm_tty_cleanup(void)
return;
}
- hashbin_delete(ircomm_tty, (FREE_FUNC) kfree);
+ hashbin_delete(ircomm_tty, (FREE_FUNC) __ircomm_tty_cleanup);
}
+#endif /* MODULE */
/*
* Function ircomm_startup (self)
@@ -166,6 +182,8 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
notify_t notify;
int ret;
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
@@ -189,9 +207,10 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
strncpy(notify.name, "ircomm_tty", NOTIFY_MAX_NAME);
notify.instance = self;
- if (!self->ircomm)
+ if (!self->ircomm) {
self->ircomm = ircomm_open(&notify, self->service_type,
self->line);
+ }
if (!self->ircomm)
return -ENODEV;
@@ -224,25 +243,23 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
unsigned long flags;
struct tty_struct *tty;
- tty = self->tty;
-
IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ tty = self->tty;
+
if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
/* this is a callout device */
/* just verify that normal device is not in use */
if (self->flags & ASYNC_NORMAL_ACTIVE)
return -EBUSY;
-#if 0
if ((self->flags & ASYNC_CALLOUT_ACTIVE) &&
(self->flags & ASYNC_SESSION_LOCKOUT) &&
(self->session != current->session))
- return -EBUSY;
-#endif
+ return -EBUSY;
if ((self->flags & ASYNC_CALLOUT_ACTIVE) &&
(self->flags & ASYNC_PGRP_LOCKOUT) &&
(self->pgrp != current->pgrp))
- return -EBUSY;
+ return -EBUSY;
self->flags |= ASYNC_CALLOUT_ACTIVE;
return 0;
}
@@ -263,13 +280,15 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
}
if (self->flags & ASYNC_CALLOUT_ACTIVE) {
- if (self->normal_termios.c_cflag & CLOCAL)
+ if (self->normal_termios.c_cflag & CLOCAL) {
IRDA_DEBUG(1, __FUNCTION__ "(), doing CLOCAL!\n");
do_clocal = 1;
+ }
} else {
- if (tty->termios->c_cflag & CLOCAL)
+ if (tty->termios->c_cflag & CLOCAL) {
IRDA_DEBUG(1, __FUNCTION__ "(), doing CLOCAL!\n");
do_clocal = 1;
+ }
}
/* Wait for carrier detect and the line to become
@@ -297,13 +316,13 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
if (!(self->flags & ASYNC_CALLOUT_ACTIVE) &&
(tty->termios->c_cflag & CBAUD)) {
save_flags(flags); cli();
- self->session.dte |= IRCOMM_RTS + IRCOMM_DTR;
+ self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR;
ircomm_param_request(self, IRCOMM_DTE, TRUE);
restore_flags(flags);
}
- set_current_state(TASK_INTERRUPTIBLE);
+ current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) || !(self->flags & ASYNC_INITIALIZED)){
retval = (self->flags & ASYNC_HUP_NOTIFY) ?
@@ -318,7 +337,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
*/
if (!(self->flags & ASYNC_CALLOUT_ACTIVE) &&
!(self->flags & ASYNC_CLOSING) &&
- (do_clocal || (self->session.dce & IRCOMM_CD)) &&
+ (do_clocal || (self->settings.dce & IRCOMM_CD)) &&
self->state == IRCOMM_TTY_READY)
{
break;
@@ -386,6 +405,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
memset(self, 0, sizeof(struct ircomm_tty_cb));
self->magic = IRCOMM_TTY_MAGIC;
+ self->flow = FLOW_STOP;
+
self->line = line;
self->tqueue.routine = ircomm_tty_do_softint;
self->tqueue.data = self;
@@ -397,7 +418,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
/* Init some important stuff */
init_timer(&self->watchdog_timer);
init_waitqueue_head(&self->open_wait);
- init_waitqueue_head(&self->close_wait);
+ init_waitqueue_head(&self->close_wait);
/*
* Force TTY into raw mode by default which is usually what
@@ -440,10 +461,12 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
/* Check if this is a "normal" ircomm device, or an irlpt device */
if (line < 0x10) {
self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
+ self->settings.service_type = IRCOMM_9_WIRE; /* Default */
IRDA_DEBUG(2, __FUNCTION__ "(), IrCOMM device\n");
} else {
IRDA_DEBUG(2, __FUNCTION__ "(), IrLPT device\n");
self->service_type = IRCOMM_3_WIRE_RAW;
+ self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */
}
ret = ircomm_tty_startup(self);
@@ -453,15 +476,14 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
ret = ircomm_tty_block_til_ready(self, filp);
if (ret) {
/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
- IRDA_DEBUG(0, __FUNCTION__
+ IRDA_DEBUG(2, __FUNCTION__
"(), returning after block_til_ready with %d\n",
ret);
return ret;
}
-#if 0
+
self->session = current->session;
-#endif
self->pgrp = current->pgrp;
return 0;
@@ -478,14 +500,11 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned long flags;
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
if (!tty)
return;
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
save_flags(flags);
cli();
@@ -493,10 +512,27 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
MOD_DEC_USE_COUNT;
restore_flags(flags);
- IRDA_DEBUG(2, __FUNCTION__ "(), returning 1\n");
+ IRDA_DEBUG(0, __FUNCTION__ "(), returning 1\n");
return;
}
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+ if ((tty->count == 1) && (self->open_count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. state->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ IRDA_DEBUG(0, __FUNCTION__ "(), bad serial port count; "
+ "tty->count is 1, state->count is %d\n",
+ self->open_count);
+ self->open_count = 1;
+ }
+
if (--self->open_count < 0) {
ERROR(__FUNCTION__
"(), bad serial port count for ttys%d: %d\n",
@@ -507,7 +543,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
MOD_DEC_USE_COUNT;
restore_flags(flags);
- IRDA_DEBUG(2, __FUNCTION__ "(), open count > 0\n");
+ IRDA_DEBUG(0, __FUNCTION__ "(), open count > 0\n");
return;
}
self->flags |= ASYNC_CLOSING;
@@ -520,7 +556,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, self->closing_wait);
- self->flags &= ~ASYNC_INITIALIZED;
+ ircomm_tty_shutdown(self);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
@@ -543,34 +579,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&self->close_wait);
MOD_DEC_USE_COUNT;
-
- del_timer(&self->watchdog_timer);
-
- /* Free parameter buffer */
- if (self->ctrl_skb) {
- dev_kfree_skb(self->ctrl_skb);
- self->ctrl_skb = NULL;
- }
-
- /* Free transmit buffer */
- if (self->tx_skb) {
- dev_kfree_skb(self->tx_skb);
- self->tx_skb = NULL;
- }
-
restore_flags(flags);
-
- ircomm_tty_detach_cable(self);
- ircomm_close(self->ircomm);
- self->ircomm = NULL;
-
-#if IRCOMM_TTY_CLOSE_WILL_DEALLOC
- self->magic = 0;
-
- hashbin_remove(ircomm_tty, self->line, NULL);
-
- kfree(self);
-#endif
}
/*
@@ -606,7 +615,9 @@ static void ircomm_tty_do_softint(void *private_)
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) private_;
struct tty_struct *tty;
unsigned long flags;
- struct sk_buff *skb;
+ struct sk_buff *skb, *ctrl_skb;
+
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
if (!self || self->magic != IRCOMM_TTY_MAGIC)
return;
@@ -615,6 +626,19 @@ static void ircomm_tty_do_softint(void *private_)
if (!tty)
return;
+ /* Unlink control buffer */
+ save_flags(flags);
+ cli();
+
+ ctrl_skb = self->ctrl_skb;
+ self->ctrl_skb = NULL;
+
+ restore_flags(flags);
+
+ /* Flush control buffer if any */
+ if (ctrl_skb && self->flow == FLOW_START)
+ ircomm_control_request(self->ircomm, ctrl_skb);
+
if (tty->hw_stopped)
return;
@@ -625,7 +649,7 @@ static void ircomm_tty_do_softint(void *private_)
skb = self->tx_skb;
self->tx_skb = NULL;
- restore_flags(flags);
+ restore_flags(flags);
/* Flush transmit buffer if any */
if (skb)
@@ -658,7 +682,7 @@ static int ircomm_tty_write(struct tty_struct *tty, int from_user,
int len = 0;
int size;
- IRDA_DEBUG(3, __FUNCTION__ "(), count=%d, hw_stopped=%d\n", count,
+ IRDA_DEBUG(2, __FUNCTION__ "(), count=%d, hw_stopped=%d\n", count,
tty->hw_stopped);
ASSERT(self != NULL, return -1;);
@@ -788,7 +812,7 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned long orig_jiffies, poll_time;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -831,8 +855,8 @@ static void ircomm_tty_throttle(struct tty_struct *tty)
/* Hardware flow control? */
if (tty->termios->c_cflag & CRTSCTS) {
- self->session.dte &= ~IRCOMM_RTS;
- self->session.dte |= IRCOMM_DELTA_RTS;
+ self->settings.dte &= ~IRCOMM_RTS;
+ self->settings.dte |= IRCOMM_DELTA_RTS;
ircomm_param_request(self, IRCOMM_DTE, TRUE);
}
@@ -863,7 +887,7 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty)
/* Using hardware flow control? */
if (tty->termios->c_cflag & CRTSCTS) {
- self->session.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
+ self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
ircomm_param_request(self, IRCOMM_DTE, TRUE);
IRDA_DEBUG(1, __FUNCTION__"(), FLOW_START\n");
@@ -897,6 +921,46 @@ static int ircomm_tty_chars_in_buffer(struct tty_struct *tty)
return len;
}
+static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
+{
+ unsigned long flags;
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ if (!(self->flags & ASYNC_INITIALIZED))
+ return;
+
+ save_flags(flags);
+ cli();
+
+ del_timer(&self->watchdog_timer);
+
+ /* Free parameter buffer */
+ if (self->ctrl_skb) {
+ dev_kfree_skb(self->ctrl_skb);
+ self->ctrl_skb = NULL;
+ }
+
+ /* Free transmit buffer */
+ if (self->tx_skb) {
+ dev_kfree_skb(self->tx_skb);
+ self->tx_skb = NULL;
+ }
+
+ ircomm_tty_detach_cable(self);
+
+ if (self->ircomm) {
+ ircomm_close(self->ircomm);
+ self->ircomm = NULL;
+ }
+ self->flags &= ~ASYNC_INITIALIZED;
+
+ restore_flags(flags);
+}
+
/*
* Function ircomm_tty_hangup (tty)
*
@@ -908,7 +972,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- IRDA_DEBUG(2, __FUNCTION__"()\n");
+ IRDA_DEBUG(0, __FUNCTION__"()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -917,17 +981,11 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
return;
/* ircomm_tty_flush_buffer(tty); */
- ircomm_tty_detach_cable(self);
- ircomm_close(self->ircomm);
+ ircomm_tty_shutdown(self);
- self->ircomm = NULL;
-
- self->flags &= ~ASYNC_INITIALIZED;
-
- self->open_count = 0;
self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
self->tty = 0;
-
+ self->open_count = 0;
wake_up_interruptible(&self->open_wait);
}
@@ -983,19 +1041,21 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
struct tty_struct *tty;
int status;
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
tty = self->tty;
- status = self->session.dce;
+ status = self->settings.dce;
if (status & IRCOMM_DCE_DELTA_ANY) {
/*wake_up_interruptible(&self->delta_msr_wait);*/
}
if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
IRDA_DEBUG(2, __FUNCTION__
- "(), ttys%d CD now %s...\n", self->line,
+ "(), ircomm%d CD now %s...\n", self->line,
(status & IRCOMM_CD) ? "on" : "off");
if (status & IRCOMM_CD) {
@@ -1003,27 +1063,30 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
} else if (!((self->flags & ASYNC_CALLOUT_ACTIVE) &&
(self->flags & ASYNC_CALLOUT_NOHUP)))
{
- IRDA_DEBUG(2, __FUNCTION__ "(), Doing serial hangup..\n");
-
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), Doing serial hangup..\n");
if (tty)
tty_hangup(tty);
+
+ /* Hangup will remote the tty, so better break out */
+ return;
}
}
if (self->flags & ASYNC_CTS_FLOW) {
if (tty->hw_stopped) {
if (status & IRCOMM_CTS) {
- IRDA_DEBUG(2, __FUNCTION__ "(), CTS tx start...\n");
-
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), CTS tx start...\n");
tty->hw_stopped = 0;
-
+
queue_task(&self->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
return;
}
} else {
if (!(status & IRCOMM_CTS)) {
- IRDA_DEBUG(2, __FUNCTION__ "(), CTS tx stop...\n");
-
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), CTS tx stop...\n");
tty->hw_stopped = 1;
}
}
@@ -1047,8 +1110,26 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
ASSERT(skb != NULL, return -1;);
- if (!self->tty)
+ if (!self->tty) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), no tty!\n");
+ dev_kfree_skb(skb);
return 0;
+ }
+
+ /*
+ * If we receive data when hardware is stopped then something is wrong.
+ * We try to poll the peers line settings to check if we are up todate.
+ * Devices like WinCE can do this, and since they don't send any
+ * params, we can just as well declare the hardware for running.
+ */
+ if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), polling for line settings!\n");
+ ircomm_param_request(self, IRCOMM_POLL, TRUE);
+
+ /* We can just as well declare the hardware for running */
+ ircomm_tty_send_initial_parameters(self);
+ ircomm_tty_link_established(self);
+ }
/*
* Just give it over to the line discipline. There is no need to
@@ -1113,15 +1194,15 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
/* ircomm_tty_do_softint will take care of the rest */
queue_task(&self->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
+ mark_bh(IMMEDIATE_BH);
break;
- default:
- /* If we get here, something is very wrong, better stop */
+ default: /* If we get here, something is very wrong, better stop */
case FLOW_STOP:
IRDA_DEBUG(2, __FUNCTION__ "(), hw stopped!\n");
tty->hw_stopped = 1;
break;
}
+ self->flow = cmd;
}
static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf)
@@ -1141,57 +1222,57 @@ static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf)
ret += sprintf(buf+ret, "No common service type!\n");
ret += sprintf(buf+ret, "\n");
- ret += sprintf(buf+ret, "Port name: %s\n", self->session.port_name);
+ ret += sprintf(buf+ret, "Port name: %s\n", self->settings.port_name);
ret += sprintf(buf+ret, "DTE status: ");
- if (self->session.dte & IRCOMM_RTS)
+ if (self->settings.dte & IRCOMM_RTS)
ret += sprintf(buf+ret, "RTS|");
- if (self->session.dte & IRCOMM_DTR)
+ if (self->settings.dte & IRCOMM_DTR)
ret += sprintf(buf+ret, "DTR|");
- if (self->session.dte)
+ if (self->settings.dte)
ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
ret += sprintf(buf+ret, "DCE status: ");
- if (self->session.dce & IRCOMM_CTS)
+ if (self->settings.dce & IRCOMM_CTS)
ret += sprintf(buf+ret, "CTS|");
- if (self->session.dce & IRCOMM_DSR)
+ if (self->settings.dce & IRCOMM_DSR)
ret += sprintf(buf+ret, "DSR|");
- if (self->session.dce & IRCOMM_CD)
+ if (self->settings.dce & IRCOMM_CD)
ret += sprintf(buf+ret, "CD|");
- if (self->session.dce & IRCOMM_RI)
+ if (self->settings.dce & IRCOMM_RI)
ret += sprintf(buf+ret, "RI|");
- if (self->session.dce)
+ if (self->settings.dce)
ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
ret += sprintf(buf+ret, "Configuration: ");
- if (!self->session.null_modem)
+ if (!self->settings.null_modem)
ret += sprintf(buf+ret, "DTE <-> DCE\n");
else
ret += sprintf(buf+ret,
"DTE <-> DTE (null modem emulation)\n");
- ret += sprintf(buf+ret, "Data rate: %d\n", self->session.data_rate);
+ ret += sprintf(buf+ret, "Data rate: %d\n", self->settings.data_rate);
ret += sprintf(buf+ret, "Flow control: ");
- if (self->session.flow_control & IRCOMM_XON_XOFF_IN)
+ if (self->settings.flow_control & IRCOMM_XON_XOFF_IN)
ret += sprintf(buf+ret, "XON_XOFF_IN|");
- if (self->session.flow_control & IRCOMM_XON_XOFF_OUT)
+ if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT)
ret += sprintf(buf+ret, "XON_XOFF_OUT|");
- if (self->session.flow_control & IRCOMM_RTS_CTS_IN)
+ if (self->settings.flow_control & IRCOMM_RTS_CTS_IN)
ret += sprintf(buf+ret, "RTS_CTS_IN|");
- if (self->session.flow_control & IRCOMM_RTS_CTS_OUT)
+ if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT)
ret += sprintf(buf+ret, "RTS_CTS_OUT|");
- if (self->session.flow_control & IRCOMM_DSR_DTR_IN)
+ if (self->settings.flow_control & IRCOMM_DSR_DTR_IN)
ret += sprintf(buf+ret, "DSR_DTR_IN|");
- if (self->session.flow_control & IRCOMM_DSR_DTR_OUT)
+ if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT)
ret += sprintf(buf+ret, "DSR_DTR_OUT|");
- if (self->session.flow_control & IRCOMM_ENQ_ACK_IN)
+ if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN)
ret += sprintf(buf+ret, "ENQ_ACK_IN|");
- if (self->session.flow_control & IRCOMM_ENQ_ACK_OUT)
+ if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT)
ret += sprintf(buf+ret, "ENQ_ACK_OUT|");
- if (self->session.flow_control)
+ if (self->settings.flow_control)
ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
@@ -1214,7 +1295,12 @@ static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf)
ret--; /* remove the last | */
ret += sprintf(buf+ret, "\n");
+ ret += sprintf(buf+ret, "Role: %s\n", self->client ?
+ "client" : "server");
ret += sprintf(buf+ret, "Open count: %d\n", self->open_count);
+ ret += sprintf(buf+ret, "Max data size: %d\n", self->max_data_size);
+ ret += sprintf(buf+ret, "Max header size: %d\n", self->max_header_size);
+
if (self->tty)
ret += sprintf(buf+ret, "Hardware: %s\n",
self->tty->hw_stopped ? "Stopped" : "Running");
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
index db8f382dc..94c9fee09 100644
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -6,10 +6,10 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Jun 5 17:42:00 1999
- * Modified at: Sun Oct 31 22:19:37 1999
+ * Modified at: Tue Jan 4 14:20:49 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1999-2000 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
@@ -124,7 +124,7 @@ static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
*/
int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
{
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
@@ -159,17 +159,21 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
*/
void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
{
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+ del_timer(&self->watchdog_timer);
+
/* Remove IrCOMM hint bits */
irlmp_unregister_client(self->ckey);
irlmp_unregister_service(self->skey);
- if (self->iriap)
+ if (self->iriap) {
iriap_close(self->iriap);
+ self->iriap = NULL;
+ }
/* Remove LM-IAS object */
if (self->obj) {
@@ -183,7 +187,7 @@ void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
self->daddr = self->saddr = 0;
self->dlsap_sel = self->slsap_sel = 0;
- memset(&self->session, 0, sizeof(struct ircomm_params));
+ memset(&self->settings, 0, sizeof(struct ircomm_params));
}
/*
@@ -197,6 +201,8 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
__u8 oct_seq[6];
__u16 hints;
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -237,7 +243,7 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
* Send initial parameters to the remote IrCOMM device. These parameters
* must be sent before any data.
*/
-static int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
+int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
{
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
@@ -250,27 +256,29 @@ static int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
* haven't set them already
*/
IRDA_DEBUG(2, __FUNCTION__ "(), data-rate = %d\n",
- self->session.data_rate);
- if (!self->session.data_rate)
- self->session.data_rate = 9600;
+ self->settings.data_rate);
+ if (!self->settings.data_rate)
+ self->settings.data_rate = 9600;
IRDA_DEBUG(2, __FUNCTION__ "(), data-format = %d\n",
- self->session.data_format);
- if (!self->session.data_format)
- self->session.data_format = IRCOMM_WSIZE_8; /* 8N1 */
+ self->settings.data_format);
+ if (!self->settings.data_format)
+ self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */
IRDA_DEBUG(2, __FUNCTION__ "(), flow-control = %d\n",
- self->session.flow_control);
- /*self->session.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
+ self->settings.flow_control);
+ /*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
/* Do not set delta values for the initial parameters */
- self->session.dte = IRCOMM_DTR | IRCOMM_RTS;
+ self->settings.dte = IRCOMM_DTR | IRCOMM_RTS;
- ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE);
+ /* Only send service type parameter when we are the client */
+ if (self->client)
+ ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE);
ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
/* For a 3 wire service, we just flush the last parameter and return */
- if (self->session.service_type == IRCOMM_3_WIRE) {
+ if (self->settings.service_type == IRCOMM_3_WIRE) {
ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
return 0;
}
@@ -335,6 +343,12 @@ void ircomm_tty_disconnect_indication(void *instance, void *sap,
if (!self->tty)
return;
+ /* This will stop control data transfers */
+ self->flow = FLOW_STOP;
+
+ /* Stop data transfers */
+ self->tty->hw_stopped = 1;
+
ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
NULL);
}
@@ -395,6 +409,7 @@ static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
IRDA_DEBUG(0, __FUNCTION__"(), got unknown type!\n");
break;
}
+ irias_delete_value(value);
}
/*
@@ -416,10 +431,14 @@ void ircomm_tty_connect_confirm(void *instance, void *sap,
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+ self->client = TRUE;
self->max_data_size = max_data_size;
self->max_header_size = max_header_size;
+ self->flow = FLOW_START;
ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
+
+ dev_kfree_skb(skb);
}
/*
@@ -443,8 +462,10 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+ self->client = FALSE;
self->max_data_size = max_data_size;
self->max_header_size = max_header_size;
+ self->flow = FLOW_START;
clen = skb->data[0];
if (clen)
@@ -453,6 +474,8 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
&ircomm_param_info);
ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
+
+ dev_kfree_skb(skb);
}
/*
@@ -465,26 +488,32 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
{
IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+ if (!self->tty)
+ return;
+
del_timer(&self->watchdog_timer);
- /*
+ /*
* IrCOMM link is now up, and if we are not using hardware
- * flow-control, then declare the hardware as running. Otherwise
- * the client will have to wait for the CD to be set.
+ * flow-control, then declare the hardware as running. Otherwise we
+ * will have to wait for the peer device (DCE) to raise the CTS
+ * line.
*/
- if (!(self->flags & ASYNC_CTS_FLOW)) {
+ if (self->flags & ASYNC_CTS_FLOW) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), waiting for CTS ...\n");
+ return;
+ } else {
IRDA_DEBUG(2, __FUNCTION__ "(), starting hardware!\n");
- if (!self->tty)
- return;
+
self->tty->hw_stopped = 0;
+
+ /* Wake up processes blocked on open */
+ wake_up_interruptible(&self->open_wait);
}
- /* Wake up processes blocked on open */
- wake_up_interruptible(&self->open_wait);
- /*
- * Wake up processes blocked on write, or waiting for a write
- * wakeup notification
- */
queue_task(&self->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
@@ -498,6 +527,9 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
*/
void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout)
{
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
ircomm_tty_watchdog_timer_expired);
}
@@ -512,7 +544,7 @@ void ircomm_tty_watchdog_timer_expired(void *data)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -535,13 +567,12 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
ircomm_tty_state[self->state], ircomm_tty_event[event]);
-
switch (event) {
case IRCOMM_TTY_ATTACH_CABLE:
/* Try to discover any remote devices */
ircomm_tty_start_watchdog_timer(self, 3*HZ);
ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
-
+
irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
break;
case IRCOMM_TTY_DISCOVERY_INDICATION:
@@ -570,10 +601,6 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
/* Accept connection */
ircomm_connect_response(self->ircomm, NULL);
ircomm_tty_next_state(self, IRCOMM_TTY_READY);
-
- /* Init connection */
- ircomm_tty_send_initial_parameters(self);
- ircomm_tty_link_established(self);
break;
case IRCOMM_TTY_WD_TIMER_EXPIRED:
/* Just stay idle */
@@ -640,15 +667,15 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
/* Accept connection */
ircomm_connect_response(self->ircomm, NULL);
ircomm_tty_next_state(self, IRCOMM_TTY_READY);
-
- /* Init connection */
- ircomm_tty_send_initial_parameters(self);
- ircomm_tty_link_established(self);
break;
case IRCOMM_TTY_WD_TIMER_EXPIRED:
+#if 1
+ /* Give up */
+#else
/* Try to discover any remote devices */
ircomm_tty_start_watchdog_timer(self, 3*HZ);
irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
+#endif
break;
case IRCOMM_TTY_DETACH_CABLE:
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
@@ -706,10 +733,6 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
/* Accept connection */
ircomm_connect_response(self->ircomm, NULL);
ircomm_tty_next_state(self, IRCOMM_TTY_READY);
-
- /* Init connection */
- ircomm_tty_send_initial_parameters(self);
- ircomm_tty_link_established(self);
break;
case IRCOMM_TTY_DETACH_CABLE:
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
@@ -758,10 +781,6 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
/* Accept connection */
ircomm_connect_response(self->ircomm, NULL);
ircomm_tty_next_state(self, IRCOMM_TTY_READY);
-
- /* Init connection */
- ircomm_tty_send_initial_parameters(self);
- ircomm_tty_link_established(self);
break;
case IRCOMM_TTY_DETACH_CABLE:
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
@@ -808,10 +827,6 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
/* Accept connection */
ircomm_connect_response(self->ircomm, NULL);
ircomm_tty_next_state(self, IRCOMM_TTY_READY);
-
- /* Init connection */
- ircomm_tty_send_initial_parameters(self);
- ircomm_tty_link_established(self);
break;
case IRCOMM_TTY_WD_TIMER_EXPIRED:
/* Go back to search mode */
@@ -819,7 +834,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
ircomm_tty_start_watchdog_timer(self, 3*HZ);
break;
case IRCOMM_TTY_DETACH_CABLE:
- ircomm_disconnect_request(self->ircomm, NULL);
+ /* ircomm_disconnect_request(self->ircomm, NULL); */
ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
break;
default:
@@ -855,9 +870,15 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
ircomm_tty_start_watchdog_timer(self, 3*HZ);
- /* Drop carrier */
- self->session.dce = IRCOMM_DELTA_CD;
- ircomm_tty_check_modem_status(self);
+ if (self->flags & ASYNC_CHECK_CD) {
+ /* Drop carrier */
+ self->settings.dce = IRCOMM_DELTA_CD;
+ ircomm_tty_check_modem_status(self);
+ } else {
+ IRDA_DEBUG(0, __FUNCTION__ "(), hanging up!\n");
+ if (self->tty)
+ tty_hangup(self->tty);
+ }
break;
default:
IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %s\n",
@@ -876,9 +897,12 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
struct sk_buff *skb, struct ircomm_tty_info *info)
{
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%s\n",
ircomm_tty_state[self->state], ircomm_tty_event[event]);
-
+
return (*state[self->state])(self, event, skb, info);
}
@@ -890,6 +914,9 @@ int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
*/
void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
{
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
self->state = state;
IRDA_DEBUG(2, __FUNCTION__": next state=%s, service type=%d\n",
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c
index 5262af954..107ceb612 100644
--- a/net/irda/ircomm/ircomm_tty_ioctl.c
+++ b/net/irda/ircomm/ircomm_tty_ioctl.c
@@ -6,10 +6,10 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Thu Jun 10 14:39:09 1999
- * Modified at: Sat Oct 30 12:50:41 1999
+ * Modified at: Wed Jan 5 14:45:43 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1999-2000 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
@@ -59,6 +59,8 @@ void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
unsigned cflag, cval;
int baud;
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
if (!self->tty || !self->tty->termios || !self->ircomm)
return;
@@ -85,16 +87,17 @@ void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
if (!baud)
baud = 9600; /* B0 transition handled in rs_set_termios */
- self->session.data_rate = baud;
+ self->settings.data_rate = baud;
ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
/* CTS flow control flag and modem status interrupts */
if (cflag & CRTSCTS) {
self->flags |= ASYNC_CTS_FLOW;
- self->session.flow_control |= IRCOMM_RTS_CTS_IN;
- } else
+ self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
+ } else {
self->flags &= ~ASYNC_CTS_FLOW;
-
+ self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
+ }
if (cflag & CLOCAL)
self->flags &= ~ASYNC_CHECK_CD;
else
@@ -126,7 +129,7 @@ void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
self->ignore_status_mask |= LSR_OE;
}
#endif
- self->session.data_format = cval;
+ self->settings.data_format = cval;
ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
@@ -146,6 +149,8 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned int cflag = tty->termios->c_cflag;
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(tty->termios->c_iflag) ==
RELEVANT_IFLAG(old_termios->c_iflag)))
@@ -158,17 +163,17 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) &&
!(cflag & CBAUD)) {
- self->session.dte &= ~(IRCOMM_DTR|IRCOMM_RTS);
+ self->settings.dte &= ~(IRCOMM_DTR|IRCOMM_RTS);
ircomm_param_request(self, IRCOMM_DTE, TRUE);
}
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
(cflag & CBAUD)) {
- self->session.dte |= IRCOMM_DTR;
+ self->settings.dte |= IRCOMM_DTR;
if (!(tty->termios->c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
- self->session.dte |= IRCOMM_RTS;
+ self->settings.dte |= IRCOMM_RTS;
}
ircomm_param_request(self, IRCOMM_DTE, TRUE);
}
@@ -193,14 +198,14 @@ static int ircomm_tty_get_modem_info(struct ircomm_tty_cb *self,
{
unsigned int result;
- IRDA_DEBUG(1, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
- result = ((self->session.dte & IRCOMM_RTS) ? TIOCM_RTS : 0)
- | ((self->session.dte & IRCOMM_DTR) ? TIOCM_DTR : 0)
- | ((self->session.dce & IRCOMM_CD) ? TIOCM_CAR : 0)
- | ((self->session.dce & IRCOMM_RI) ? TIOCM_RNG : 0)
- | ((self->session.dce & IRCOMM_DSR) ? TIOCM_DSR : 0)
- | ((self->session.dce & IRCOMM_CTS) ? TIOCM_CTS : 0);
+ result = ((self->settings.dte & IRCOMM_RTS) ? TIOCM_RTS : 0)
+ | ((self->settings.dte & IRCOMM_DTR) ? TIOCM_DTR : 0)
+ | ((self->settings.dce & IRCOMM_CD) ? TIOCM_CAR : 0)
+ | ((self->settings.dce & IRCOMM_RI) ? TIOCM_RNG : 0)
+ | ((self->settings.dce & IRCOMM_DSR) ? TIOCM_DSR : 0)
+ | ((self->settings.dce & IRCOMM_CTS) ? TIOCM_CTS : 0);
return put_user(result, value);
}
@@ -227,27 +232,27 @@ static int ircomm_tty_set_modem_info(struct ircomm_tty_cb *self,
if (error)
return error;
- old_rts = self->session.dte & IRCOMM_RTS;
- old_dtr = self->session.dte & IRCOMM_DTR;
+ old_rts = self->settings.dte & IRCOMM_RTS;
+ old_dtr = self->settings.dte & IRCOMM_DTR;
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS)
- self->session.dte |= IRCOMM_RTS;
+ self->settings.dte |= IRCOMM_RTS;
if (arg & TIOCM_DTR)
- self->session.dte |= IRCOMM_DTR;
+ self->settings.dte |= IRCOMM_DTR;
break;
case TIOCMBIC:
if (arg & TIOCM_RTS)
- self->session.dte &= ~IRCOMM_RTS;
+ self->settings.dte &= ~IRCOMM_RTS;
if (arg & TIOCM_DTR)
- self->session.dte &= ~IRCOMM_DTR;
+ self->settings.dte &= ~IRCOMM_DTR;
break;
case TIOCMSET:
- self->session.dte =
- ((self->session.dte & ~(IRCOMM_RTS | IRCOMM_DTR))
+ self->settings.dte =
+ ((self->settings.dte & ~(IRCOMM_RTS | IRCOMM_DTR))
| ((arg & TIOCM_RTS) ? IRCOMM_RTS : 0)
| ((arg & TIOCM_DTR) ? IRCOMM_DTR : 0));
break;
@@ -256,11 +261,11 @@ static int ircomm_tty_set_modem_info(struct ircomm_tty_cb *self,
return -EINVAL;
}
- if ((self->session.dte & IRCOMM_RTS) != old_rts)
- self->session.dte |= IRCOMM_DELTA_RTS;
+ if ((self->settings.dte & IRCOMM_RTS) != old_rts)
+ self->settings.dte |= IRCOMM_DELTA_RTS;
- if ((self->session.dte & IRCOMM_DTR) != old_dtr)
- self->session.dte |= IRCOMM_DELTA_DTR;
+ if ((self->settings.dte & IRCOMM_DTR) != old_dtr)
+ self->settings.dte |= IRCOMM_DELTA_DTR;
ircomm_param_request(self, IRCOMM_DTE, TRUE);
@@ -281,12 +286,12 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
if (!retinfo)
return -EFAULT;
- IRDA_DEBUG(1, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
memset(&info, 0, sizeof(info));
info.line = self->line;
info.flags = self->flags;
- info.baud_base = self->session.data_rate;
+ info.baud_base = self->settings.data_rate;
info.close_delay = self->close_delay;
info.closing_wait = self->closing_wait;
@@ -310,29 +315,33 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
*
*
*/
-static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *tty,
+static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
struct serial_struct *new_info)
{
#if 0
struct serial_struct new_serial;
- struct ircomm_tty_cb old_driver;
+ struct ircomm_tty_cb old_state, *state;
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
- old_driver = *driver;
+
+ state = self
+ old_state = *self;
if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != driver->comm->data_rate) ||
- (new_serial.close_delay != driver->close_delay) ||
+ if ((new_serial.baud_base != state->settings.data_rate) ||
+ (new_serial.close_delay != state->close_delay) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
- (driver->flags & ~ASYNC_USR_MASK)))
+ (self->flags & ~ASYNC_USR_MASK)))
return -EPERM;
- driver->flags = ((driver->flags & ~ASYNC_USR_MASK) |
+ state->flags = ((state->flags & ~ASYNC_USR_MASK) |
(new_serial.flags & ASYNC_USR_MASK));
- driver->custom_divisor = new_serial.custom_divisor;
+ self->flags = ((self->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ /* self->custom_divisor = new_serial.custom_divisor; */
goto check_and_exit;
}
@@ -341,15 +350,14 @@ static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *tty,
* At this point, we start making changes.....
*/
- if (self->session.data_rate != new_serial.baud_base) {
- self->session.data_rate.data_rate = new_serial.baud_base;
- if (driver->comm->state == IRCOMM_CONN)
- ircomm_control_request(driver->comm, DATA_RATE);
+ if (self->settings.data_rate != new_serial.baud_base) {
+ self->settings.data_rate = new_serial.baud_base;
+ ircomm_param_request(self, IRCOMM_DATA_RATE, TRUE);
}
- driver->close_delay = new_serial.close_delay * HZ/100;
- driver->closing_wait = new_serial.closing_wait * HZ/100;
- driver->custom_divisor = new_serial.custom_divisor;
+ self->close_delay = new_serial.close_delay * HZ/100;
+ self->closing_wait = new_serial.closing_wait * HZ/100;
+ /* self->custom_divisor = new_serial.custom_divisor; */
self->flags = ((self->flags & ~ASYNC_FLAGS) |
(new_serial.flags & ASYNC_FLAGS));
@@ -358,7 +366,7 @@ static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *tty,
check_and_exit:
if (self->flags & ASYNC_INITIALIZED) {
- if (((old_driver.flags & ASYNC_SPD_MASK) !=
+ if (((old_state.flags & ASYNC_SPD_MASK) !=
(self->flags & ASYNC_SPD_MASK)) ||
(old_driver.custom_divisor != driver->custom_divisor)) {
if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
@@ -388,6 +396,8 @@ int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file,
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
int ret = 0;
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
index dd17e2dd3..0e272947d 100644
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -6,10 +6,10 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Oct 9 09:22:27 1999
- * Modified at: Tue Nov 16 12:54:13 1999
+ * Modified at: Wed Jan 5 14:17:16 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1999-2000 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
@@ -62,6 +62,8 @@ extern int tekram_init(void);
extern int actisys_init(void);
extern int girbil_init(void);
+static void __irda_task_delete(struct irda_task *task);
+
static hashbin_t *dongles = NULL;
static hashbin_t *tasks = NULL;
@@ -94,14 +96,14 @@ int irda_device_proc_read(char *buf, char **start, off_t offset, int len,
int __init irda_device_init( void)
{
- dongles = hashbin_new(HB_LOCAL);
+ dongles = hashbin_new(HB_GLOBAL);
if (dongles == NULL) {
printk(KERN_WARNING
"IrDA: Can't allocate dongles hashbin!\n");
return -ENOMEM;
}
- tasks = hashbin_new(HB_LOCAL);
+ tasks = hashbin_new(HB_GLOBAL);
if (tasks == NULL) {
printk(KERN_WARNING
"IrDA: Can't allocate tasks hashbin!\n");
@@ -145,6 +147,9 @@ int __init irda_device_init( void)
#ifdef CONFIG_AIRPORT_DONGLE
airport_init();
#endif
+#ifdef CONFIG_OLD_BELKIN
+ old_belkin_init();
+#endif
return 0;
}
@@ -152,7 +157,7 @@ void irda_device_cleanup(void)
{
IRDA_DEBUG(4, __FUNCTION__ "()\n");
- hashbin_delete(tasks, NULL);
+ hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
hashbin_delete(dongles, NULL);
}
@@ -188,7 +193,7 @@ int irda_device_set_dtr_rts(struct net_device *dev, int dtr, int rts)
struct if_irda_req req;
int ret;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
if (!dev->do_ioctl) {
ERROR(__FUNCTION__ "(), do_ioctl not impl. by "
@@ -209,7 +214,7 @@ int irda_device_change_speed(struct net_device *dev, __u32 speed)
struct if_irda_req req;
int ret;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
if (!dev->do_ioctl) {
ERROR(__FUNCTION__ "(), do_ioctl not impl. by "
@@ -257,6 +262,21 @@ void irda_task_next_state(struct irda_task *task, TASK_STATE state)
task->state = state;
}
+static void __irda_task_delete(struct irda_task *task)
+{
+ del_timer(&task->timer);
+
+ kfree(task);
+}
+
+void irda_task_delete(struct irda_task *task)
+{
+ /* Unregister task */
+ hashbin_remove(tasks, (int) task, NULL);
+
+ __irda_task_delete(task);
+}
+
/*
* Function irda_task_kick (task)
*
@@ -267,9 +287,9 @@ void irda_task_next_state(struct irda_task *task, TASK_STATE state)
*/
int irda_task_kick(struct irda_task *task)
{
- int timeout;
- int ret = 0;
+ int finished = TRUE;
int count = 0;
+ int timeout;
IRDA_DEBUG(2, __FUNCTION__ "()\n");
@@ -281,13 +301,15 @@ int irda_task_kick(struct irda_task *task)
timeout = task->function(task);
if (count++ > 100) {
ERROR(__FUNCTION__ "(), error in task handler!\n");
- return -1;
+ irda_task_delete(task);
+ return TRUE;
}
} while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
if (timeout < 0) {
ERROR(__FUNCTION__ "(), Error executing task!\n");
- return -1;
+ irda_task_delete(task);
+ return TRUE;
}
/* Check if we are finished */
@@ -311,20 +333,18 @@ int irda_task_kick(struct irda_task *task)
irda_task_kick(task->parent);
}
}
- /* Unregister task */
- hashbin_remove(tasks, (int) task, NULL);
-
- kfree(task);
+ irda_task_delete(task);
} else if (timeout > 0) {
irda_start_timer(&task->timer, timeout, (void *) task,
irda_task_timer_expired);
- ret = 1;
+ finished = FALSE;
} else {
- IRDA_DEBUG(0, __FUNCTION__ "(), not finished, and no timeout!\n");
- ret = 1;
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), not finished, and no timeout!\n");
+ finished = FALSE;
}
- return ret;
+ return finished;
}
/*
@@ -335,25 +355,26 @@ int irda_task_kick(struct irda_task *task)
* called from interrupt context, so it's not possible to use
* schedule_timeout()
*/
-int irda_task_execute(void *instance, TASK_CALLBACK function,
- TASK_CALLBACK finished, struct irda_task *parent,
- void *param)
+struct irda_task *irda_task_execute(void *instance, TASK_CALLBACK function,
+ TASK_CALLBACK finished,
+ struct irda_task *parent, void *param)
{
struct irda_task *task;
+ int ret;
IRDA_DEBUG(2, __FUNCTION__ "()\n");
task = kmalloc(sizeof(struct irda_task), GFP_ATOMIC);
if (!task)
- return -ENOMEM;
+ return NULL;
- task->state = IRDA_TASK_INIT;
+ task->state = IRDA_TASK_INIT;
task->instance = instance;
task->function = function;
task->finished = finished;
- task->parent = parent;
- task->param = param;
- task->magic = IRDA_TASK_MAGIC;
+ task->parent = parent;
+ task->param = param;
+ task->magic = IRDA_TASK_MAGIC;
init_timer(&task->timer);
@@ -361,7 +382,11 @@ int irda_task_execute(void *instance, TASK_CALLBACK function,
hashbin_insert(tasks, (queue_t *) task, (int) task, NULL);
/* No time to waste, so lets get going! */
- return irda_task_kick(task);
+ ret = irda_task_kick(task);
+ if (ret)
+ return NULL;
+ else
+ return task;
}
/*
@@ -456,6 +481,8 @@ dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
if (!dongle)
return NULL;
+ memset(dongle, 0, sizeof(dongle_t));
+
/* Bind the registration info to this particular instance */
dongle->issue = reg;
dongle->dev = dev;
@@ -518,12 +545,13 @@ void irda_device_unregister_dongle(struct dongle_reg *dongle)
}
/*
- * Function irda_device_set_raw_mode (self, mode)
- *
- *
+ * Function irda_device_set_mode (self, mode)
*
+ * Set the Infrared device driver into mode where it sends and receives
+ * data without using IrLAP framing. Check out the particular device
+ * driver to find out which modes it support.
*/
-int irda_device_set_raw_mode(struct net_device* dev, int mode)
+int irda_device_set_mode(struct net_device* dev, int mode)
{
struct if_irda_req req;
int ret;
@@ -536,9 +564,9 @@ int irda_device_set_raw_mode(struct net_device* dev, int mode)
return -1;
}
- req.ifr_raw_mode = mode;
+ req.ifr_mode = mode;
- ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCSRAWMODE);
+ ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCSMODE);
return ret;
}
@@ -546,7 +574,7 @@ int irda_device_set_raw_mode(struct net_device* dev, int mode)
/*
* Function setup_dma (idev, buffer, count, mode)
*
- * Setup the DMA channel
+ * Setup the DMA channel. Commonly used by ISA FIR drivers
*
*/
void setup_dma(int channel, char *buffer, int count, int mode)
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
index ad6c01183..5f1140525 100644
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Thu Aug 21 00:02:07 1997
- * Modified at: Fri Nov 5 20:25:42 1999
+ * Modified at: Sat Dec 25 16:42:42 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
@@ -61,6 +61,7 @@ static __u32 service_handle;
extern char *lmp_reasons[];
static void __iriap_close(struct iriap_cb *self);
+static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode);
static void iriap_disconnect_indication(void *instance, void *sap,
LM_REASON reason, struct sk_buff *skb);
static void iriap_connect_indication(void *instance, void *sap,
@@ -82,8 +83,10 @@ static int iriap_data_indication(void *instance, void *sap,
*/
int __init iriap_init(void)
{
- __u16 hints;
struct ias_object *obj;
+ struct iriap_cb *server;
+ __u8 oct_seq[6];
+ __u16 hints;
/* Allocate master array */
iriap = hashbin_new(HB_LOCAL);
@@ -100,22 +103,32 @@ int __init iriap_init(void)
* Register some default services for IrLMP
*/
hints = irlmp_service_to_hint(S_COMPUTER);
- /*hints |= irlmp_service_to_hint(S_PNP);*/
service_handle = irlmp_register_service(hints);
- /*
- * Register the Device object with LM-IAS
- */
+ /* Register the Device object with LM-IAS */
obj = irias_new_object("Device", IAS_DEVICE_ID);
irias_add_string_attrib(obj, "DeviceName", "Linux");
+
+ oct_seq[0] = 0x01; /* Version 1 */
+ oct_seq[1] = 0x00; /* IAS support bits */
+ oct_seq[2] = 0x00; /* LM-MUX support bits */
+#ifdef CONFIG_IRDA_ULTRA
+ oct_seq[2] |= 0x04; /* Connectionless Data support */
+#endif
+ irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3);
irias_insert_object(obj);
/*
* Register server support with IrLMP so we can accept incoming
* connections
*/
- iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
-
+ server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
+ if (!server) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), unable to open server\n");
+ return -1;
+ }
+ iriap_register_lsap(server, LSAP_IAS, IAS_SERVER);
+
return 0;
}
@@ -142,10 +155,8 @@ struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv,
CONFIRM_CALLBACK callback)
{
struct iriap_cb *self;
- struct lsap_cb *lsap;
- notify_t notify;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
self = kmalloc(sizeof(struct iriap_cb), GFP_ATOMIC);
if (!self) {
@@ -157,36 +168,18 @@ struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv,
* Initialize instance
*/
memset(self, 0, sizeof(struct iriap_cb));
-
- irda_notify_init(&notify);
- notify.connect_confirm = iriap_connect_confirm;
- notify.connect_indication = iriap_connect_indication;
- notify.disconnect_indication = iriap_disconnect_indication;
- notify.data_indication = iriap_data_indication;
- notify.instance = self;
- if (mode == IAS_CLIENT)
- strcpy(notify.name, "IrIAS cli");
- else
- strcpy(notify.name, "IrIAS srv");
-
- lsap = irlmp_open_lsap(slsap_sel, &notify);
- if (lsap == NULL) {
- ERROR(__FUNCTION__ "(), Unable to allocated LSAP!\n");
- return NULL;
- }
- slsap_sel = lsap->slsap_sel;
self->magic = IAS_MAGIC;
- self->lsap = lsap;
- self->slsap_sel = slsap_sel;
self->mode = mode;
+ if (mode == IAS_CLIENT)
+ iriap_register_lsap(self, slsap_sel, mode);
self->confirm = callback;
self->priv = priv;
init_timer(&self->watchdog_timer);
- hashbin_insert(iriap, (queue_t *) self, slsap_sel, NULL);
+ hashbin_insert(iriap, (queue_t *) self, (int) self, NULL);
/* Initialize state machines */
iriap_next_client_state(self, S_DISCONNECT);
@@ -212,6 +205,9 @@ static void __iriap_close(struct iriap_cb *self)
del_timer(&self->watchdog_timer);
+ if (self->skb)
+ dev_kfree_skb(self->skb);
+
self->magic = 0;
kfree(self);
@@ -226,6 +222,8 @@ void iriap_close(struct iriap_cb *self)
{
struct iriap_cb *entry;
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;);
@@ -234,13 +232,39 @@ void iriap_close(struct iriap_cb *self)
self->lsap = NULL;
}
- entry = (struct iriap_cb *) hashbin_remove(iriap, self->slsap_sel,
- NULL);
+ entry = (struct iriap_cb *) hashbin_remove(iriap, (int) self, NULL);
ASSERT(entry == self, return;);
__iriap_close(self);
}
+static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode)
+{
+ notify_t notify;
+
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+ irda_notify_init(&notify);
+ notify.connect_confirm = iriap_connect_confirm;
+ notify.connect_indication = iriap_connect_indication;
+ notify.disconnect_indication = iriap_disconnect_indication;
+ notify.data_indication = iriap_data_indication;
+ notify.instance = self;
+ if (mode == IAS_CLIENT)
+ strcpy(notify.name, "IrIAS cli");
+ else
+ strcpy(notify.name, "IrIAS srv");
+
+ self->lsap = irlmp_open_lsap(slsap_sel, &notify, 0);
+ if (self->lsap == NULL) {
+ ERROR(__FUNCTION__ "(), Unable to allocated LSAP!\n");
+ return -1;
+ }
+ self->slsap_sel = self->lsap->slsap_sel;
+
+ return 0;
+}
+
/*
* Function iriap_disconnect_indication (handle, reason)
*
@@ -281,6 +305,7 @@ static void iriap_disconnect_indication(void *instance, void *sap,
IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as server\n");
iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION,
NULL);
+ iriap_close(self);
}
if (userdata)
@@ -465,6 +490,10 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
IRDA_DEBUG(0, __FUNCTION__
"(), charset %s, not supported\n",
ias_charset_types[charset]);
+
+ /* Aborting, close connection! */
+ iriap_disconnect_request(self);
+ dev_kfree_skb(skb);
return;
/* break; */
}
@@ -487,7 +516,7 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
value = irias_new_octseq_value(fp+n, value_len);
break;
default:
- value = &missing;
+ value = irias_new_missing_value();
break;
}
@@ -499,6 +528,11 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
*/
if (self->confirm)
self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
+ else {
+ IRDA_DEBUG(0, __FUNCTION__ "(), missing handler!\n");
+ irias_delete_value(value);
+ }
+ dev_kfree_skb(skb);
}
/*
@@ -527,10 +561,10 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
/*
* We must adjust the size of the response after the length of the
- * value. We add 9 bytes because of the 6 bytes for the frame and
- * max 3 bytes for the value coding.
+ * value. We add 32 bytes because of the 6 bytes for the frame and
+ * max 5 bytes for the value coding.
*/
- skb = dev_alloc_skb(value->len + self->max_header_size + 9);
+ skb = dev_alloc_skb(value->len + self->max_header_size + 32);
if (!skb)
return;
@@ -552,7 +586,7 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
tmp_be16 = cpu_to_be16(obj_id);
memcpy(fp+n, &tmp_be16, 2); n += 2;
- switch(value->type) {
+ switch (value->type) {
case IAS_STRING:
skb_put(skb, 3 + value->len);
fp[n++] = value->type;
@@ -577,7 +611,7 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
break;
case IAS_MISSING:
IRDA_DEBUG( 3, __FUNCTION__ ": sending IAS_MISSING\n");
- skb_put( skb, 1);
+ skb_put(skb, 1);
fp[n++] = value->type;
break;
default:
@@ -622,16 +656,14 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self,
memcpy(attr, fp+n, attr_len); n+=attr_len;
attr[attr_len] = '\0';
+ /* We do not need the buffer anymore */
dev_kfree_skb(skb);
- /*
- * Now, do some advanced parsing! :-)
- */
IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr);
obj = irias_find_object(name);
if (obj == NULL) {
- IRDA_DEBUG(0, "LM-IAS: Object not found\n");
+ IRDA_DEBUG(2, "LM-IAS: Object %s not found\n", name);
iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN,
&missing);
return;
@@ -640,20 +672,16 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self,
attrib = irias_find_attrib(obj, attr);
if (attrib == NULL) {
- IRDA_DEBUG(0, "LM-IAS: Attribute %s not found\n", attr);
+ IRDA_DEBUG(2, "LM-IAS: Attribute %s not found\n", attr);
iriap_getvaluebyclass_response(self, obj->id,
IAS_ATTRIB_UNKNOWN, &missing);
return;
}
- IRDA_DEBUG(4, "LM-IAS: found %s\n", attrib->name);
-
- /*
- * We have a match; send the value.
- */
+ /* We have a match; send the value. */
iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS,
attrib->value);
-
+
return;
}
@@ -668,7 +696,7 @@ void iriap_send_ack(struct iriap_cb *self)
struct sk_buff *skb;
__u8 *frame;
- IRDA_DEBUG(6, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;);
@@ -683,7 +711,25 @@ void iriap_send_ack(struct iriap_cb *self)
frame = skb->data;
/* Build frame */
- frame[0] = IAP_LST | self->operation;
+ frame[0] = IAP_LST | IAP_ACK | self->operation;
+
+ irlmp_data_request(self->lsap, skb);
+}
+
+void iriap_connect_request(struct iriap_cb *self)
+{
+ int ret;
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IAS_MAGIC, return;);
+
+ ret = irlmp_connect_request(self->lsap, LSAP_IAS,
+ self->saddr, self->daddr,
+ NULL, NULL);
+ if (ret < 0) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n");
+ self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
+ }
}
/*
@@ -693,8 +739,8 @@ void iriap_send_ack(struct iriap_cb *self)
*
*/
static void iriap_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size, __u8 header_size,
+ struct qos_info *qos, __u32 max_seg_size,
+ __u8 max_header_size,
struct sk_buff *userdata)
{
struct iriap_cb *self;
@@ -705,7 +751,8 @@ static void iriap_connect_confirm(void *instance, void *sap,
ASSERT(self->magic == IAS_MAGIC, return;);
ASSERT(userdata != NULL, return;);
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ self->max_data_size = max_seg_size;
+ self->max_header_size = max_header_size;
del_timer(&self->watchdog_timer);
@@ -719,18 +766,43 @@ static void iriap_connect_confirm(void *instance, void *sap,
*
*/
static void iriap_connect_indication(void *instance, void *sap,
- struct qos_info *qos, __u32 max_sdu_size,
- __u8 header_size,
+ struct qos_info *qos, __u32 max_seg_size,
+ __u8 max_header_size,
struct sk_buff *userdata)
{
- struct iriap_cb *self;
+ struct iriap_cb *self, *new;
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
self = (struct iriap_cb *) instance;
ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;);
+
+ /* Start new server */
+ new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
+ if (!new) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), open failed\n");
+ dev_kfree_skb(userdata);
+ return;
+ }
+
+ /* Now attach up the new "socket" */
+ new->lsap = irlmp_dup(self->lsap, new);
+ if (!new->lsap) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), dup failed!\n");
+ return;
+ }
+
+ new->max_data_size = max_seg_size;
+ new->max_header_size = max_header_size;
- iriap_do_server_event(self, IAP_LM_CONNECT_INDICATION, userdata);
+ /* Clean up the original one to keep it in listen state */
+ self->lsap->dlsap_sel = LSAP_ANY;
+ self->lsap->lsap_state = LSAP_DISCONNECTED;
+ /* FIXME: refcount in irlmp might get wrong */
+
+ iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, userdata);
}
/*
@@ -746,7 +818,7 @@ static int iriap_data_indication(void *instance, void *sap,
__u8 *frame;
__u8 opcode;
- IRDA_DEBUG( 4, __FUNCTION__ "()\n");
+ IRDA_DEBUG(3, __FUNCTION__ "()\n");
self = (struct iriap_cb *) instance;
@@ -768,12 +840,14 @@ static int iriap_data_indication(void *instance, void *sap,
if (~opcode & IAP_LST) {
WARNING(__FUNCTION__ "(), IrIAS multiframe commands or "
"results is not implemented yet!\n");
+ dev_kfree_skb(skb);
return 0;
}
/* Check for ack frames since they don't contain any data */
if (opcode & IAP_ACK) {
IRDA_DEBUG(0, __FUNCTION__ "() Got ack frame!\n");
+ dev_kfree_skb(skb);
return 0;
}
@@ -782,9 +856,10 @@ static int iriap_data_indication(void *instance, void *sap,
switch (opcode) {
case GET_INFO_BASE:
IRDA_DEBUG(0, "IrLMP GetInfoBaseDetails not implemented!\n");
+ dev_kfree_skb(skb);
break;
case GET_VALUE_BY_CLASS:
- iriap_do_call_event(self, IAP_RECV_F_LST, skb);
+ iriap_do_call_event(self, IAP_RECV_F_LST, NULL);
switch (frame[1]) {
case IAS_SUCCESS:
@@ -800,8 +875,9 @@ static int iriap_data_indication(void *instance, void *sap,
* no to use self anymore after calling confirm
*/
if (self->confirm)
- self->confirm(IAS_CLASS_UNKNOWN, 0, NULL,
+ self->confirm(IAS_CLASS_UNKNOWN, 0, NULL,
self->priv);
+ dev_kfree_skb(skb);
break;
case IAS_ATTRIB_UNKNOWN:
WARNING(__FUNCTION__ "(), No such attribute!\n");
@@ -815,12 +891,14 @@ static int iriap_data_indication(void *instance, void *sap,
if (self->confirm)
self->confirm(IAS_CLASS_UNKNOWN, 0, NULL,
self->priv);
+ dev_kfree_skb(skb);
break;
}
break;
default:
IRDA_DEBUG(0, __FUNCTION__ "(), Unknown op-code: %02x\n",
opcode);
+ dev_kfree_skb(skb);
break;
}
return 0;
diff --git a/net/irda/iriap_event.c b/net/irda/iriap_event.c
index cc9d0c11a..eb8463b73 100644
--- a/net/irda/iriap_event.c
+++ b/net/irda/iriap_event.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Thu Aug 21 00:02:07 1997
- * Modified at: Sun Oct 31 22:13:00 1999
+ * Modified at: Sat Dec 25 21:09:47 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
@@ -42,29 +42,29 @@ static void state_s_calling (struct iriap_cb *self, IRIAP_EVENT event,
static void state_s_outstanding (struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb);
static void state_s_replying (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void state_s_wait_active (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void state_r_disconnect (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void state_r_call (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void state_r_waiting (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void state_r_wait_active (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void state_r_receiving (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void state_r_execute (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void state_r_returning (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
+ struct sk_buff *skb);
static void (*iriap_state[])(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb) = {
+ struct sk_buff *skb) = {
/* Client FSM */
state_s_disconnect,
state_s_connecting,
@@ -141,7 +141,7 @@ void iriap_do_call_event(struct iriap_cb *self, IRIAP_EVENT event,
}
void iriap_do_server_event(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;);
@@ -168,18 +168,15 @@ void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event,
static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- int ret;
-
ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;);
switch (event) {
case IAP_CALL_REQUEST_GVBC:
iriap_next_client_state(self, S_CONNECTING);
+ ASSERT(self->skb == NULL, return;);
self->skb = skb;
- ret = irlmp_connect_request(self->lsap, LSAP_IAS,
- self->saddr, self->daddr,
- NULL, NULL);
+ iriap_connect_request(self);
break;
case IAP_LM_DISCONNECT_INDICATION:
break;
@@ -258,15 +255,18 @@ static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event,
switch (event) {
case IAP_CALL_REQUEST:
- irlmp_data_request(self->lsap, self->skb);
+ skb = self->skb;
+ self->skb = NULL;
+
+ irlmp_data_request(self->lsap, skb);
iriap_next_call_state(self, S_OUTSTANDING);
break;
default:
IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
- if (skb)
- dev_kfree_skb(skb);
}
/*
@@ -297,7 +297,6 @@ static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event,
iriap_send_ack(self);
/*LM_Idle_request(idle); */
- dev_kfree_skb(skb);
iriap_next_call_state(self, S_WAIT_FOR_CALL);
break;
default:
@@ -324,7 +323,7 @@ static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event,
*
*/
static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
}
@@ -400,14 +399,13 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
- IRDA_DEBUG(4, "state_r_call()\n");
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
switch (event) {
case IAP_LM_DISCONNECT_INDICATION:
/* Abort call */
iriap_next_server_state(self, R_DISCONNECT);
- iriap_next_r_connect_state(self, R_WAITING);
-
+ iriap_next_r_connect_state(self, R_WAITING);
break;
default:
IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n");
@@ -431,8 +429,8 @@ static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event,
IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
}
-static void state_r_wait_active(struct iriap_cb *self,
- IRIAP_EVENT event, struct sk_buff *skb)
+static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
+ struct sk_buff *skb)
{
IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
}
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index c83bb855b..17ad3801d 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Thu Oct 1 22:50:04 1998
- * Modified at: Sat Oct 9 17:11:16 1999
+ * Modified at: Wed Dec 15 11:23:16 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -34,7 +34,7 @@ hashbin_t *objects = NULL;
/*
* Used when a missing value needs to be returned
*/
-struct ias_value missing = { IAS_MISSING, 0, 0, {0}};
+struct ias_value missing = { IAS_MISSING, 0, 0, {0}};
/*
* Function strdup (str)
@@ -72,8 +72,8 @@ struct ias_object *irias_new_object( char *name, int id)
IRDA_DEBUG( 4, __FUNCTION__ "()\n");
- obj = (struct ias_object *) kmalloc( sizeof( struct ias_object),
- GFP_ATOMIC);
+ obj = (struct ias_object *) kmalloc(sizeof(struct ias_object),
+ GFP_ATOMIC);
if (obj == NULL) {
IRDA_DEBUG(0, __FUNCTION__ "(), Unable to allocate object!\n");
return NULL;
@@ -364,7 +364,7 @@ struct ias_value *irias_new_integer_value(int integer)
{
struct ias_value *value;
- value = kmalloc(sizeof( struct ias_value), GFP_ATOMIC);
+ value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
if (value == NULL) {
WARNING(__FUNCTION__ "(), Unable to kmalloc!\n");
return NULL;
@@ -419,7 +419,7 @@ struct ias_value *irias_new_octseq_value(__u8 *octseq , int len)
WARNING(__FUNCTION__ "(), Unable to kmalloc!\n");
return NULL;
}
- memset(value, 0, sizeof( struct ias_value));
+ memset(value, 0, sizeof(struct ias_value));
value->type = IAS_OCT_SEQ;
value->len = len;
@@ -433,6 +433,23 @@ struct ias_value *irias_new_octseq_value(__u8 *octseq , int len)
return value;
}
+struct ias_value *irias_new_missing_value(void)
+{
+ struct ias_value *value;
+
+ value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
+ if (value == NULL) {
+ WARNING(__FUNCTION__ "(), Unable to kmalloc!\n");
+ return NULL;
+ }
+ memset(value, 0, sizeof(struct ias_value));
+
+ value->type = IAS_MISSING;
+ value->len = 0;
+
+ return value;
+}
+
/*
* Function irias_delete_value (value)
*
diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c
index 4faa8edf5..355bae955 100644
--- a/net/irda/irlan/irlan_client.c
+++ b/net/irda/irlan/irlan_client.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun Oct 31 19:44:41 1999
+ * Modified at: Tue Dec 14 15:47:02 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
* slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
@@ -584,16 +584,7 @@ void irlan_client_get_value_confirm(int result, __u16 obj_id,
NULL);
return;
}
- break;
- case IAS_STRING:
- IRDA_DEBUG(2, __FUNCTION__ "(), got string %s\n",
- value->t.string);
- break;
- case IAS_OCT_SEQ:
- IRDA_DEBUG(2, __FUNCTION__ "(), OCT_SEQ not implemented\n");
- break;
- case IAS_MISSING:
- IRDA_DEBUG(2, __FUNCTION__ "(), MISSING not implemented\n");
+ irias_delete_value(value);
break;
default:
IRDA_DEBUG(2, __FUNCTION__ "(), unknown type!\n");
diff --git a/net/irda/irlan/irlan_client_event.c b/net/irda/irlan/irlan_client_event.c
index 3a1aac699..a06b18582 100644
--- a/net/irda/irlan/irlan_client_event.c
+++ b/net/irda/irlan/irlan_client_event.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun Oct 31 19:41:55 1999
+ * Modified at: Sun Dec 26 21:52:24 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
@@ -194,7 +194,7 @@ static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
ASSERT(self != NULL, return -1;);
- switch(event) {
+ switch (event) {
case IRLAN_CONNECT_COMPLETE:
/* Send getinfo cmd */
irlan_get_provider_info(self);
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 64593e319..9d276e0a1 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun Oct 31 19:43:50 1999
+ * Modified at: Sun Dec 26 21:53:10 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
@@ -705,7 +705,6 @@ void irlan_get_provider_info(struct irlan_cb *self)
frame[0] = CMD_GET_PROVIDER_INFO;
frame[1] = 0x00; /* Zero parameters */
- /* irttp_data_request(self->client.tsap_ctrl, skb); */
irlan_ctrl_data_request(self, skb);
}
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 85c75b846..c2037ad74 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Thu Oct 15 08:37:58 1998
- * Modified at: Sat Oct 30 12:58:30 1999
+ * Modified at: Thu Nov 4 14:50:52 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
* slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
@@ -348,6 +348,7 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev)
return;
read_lock(&in_dev->lock);
if (in_dev->ifa_list)
+
arp_send(ARPOP_REQUEST, ETH_P_ARP,
in_dev->ifa_list->ifa_address,
dev,
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index 09257bd45..1c2958c4b 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -6,7 +6,7 @@
* Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Tue Nov 16 10:01:06 1999
+ * Modified at: Tue Dec 14 09:26:44 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
@@ -131,22 +131,14 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos)
irlap_next_state(self, LAP_OFFLINE);
/* Initialize transmit queue */
- skb_queue_head_init(&self->tx_list);
+ skb_queue_head_init(&self->txq);
+ skb_queue_head_init(&self->txq_ultra);
skb_queue_head_init(&self->wx_list);
/* My unique IrLAP device address! */
get_random_bytes(&self->saddr, sizeof(self->saddr));
memcpy(dev->dev_addr, &self->saddr, 4);
- /*
- * Generate random connection address for this session, which must
- * be 7 bits wide and different from 0x00 and 0xfe
- */
- while ((self->caddr == 0x00) || (self->caddr == 0xfe)) {
- get_random_bytes(&self->caddr, sizeof(self->caddr));
- self->caddr &= 0xfe;
- }
-
init_timer(&self->slot_timer);
init_timer(&self->query_timer);
init_timer(&self->discovery_timer);
@@ -157,6 +149,8 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos)
init_timer(&self->media_busy_timer);
irlap_apply_default_connection_parameters(self);
+
+ self->N3 = 3; /* # connections attemts to try before giving up */
irlap_next_state(self, LAP_NDM);
@@ -308,7 +302,8 @@ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
* IrLMP for further processing
*
*/
-inline void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb)
+void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb,
+ int unreliable)
{
/* Hide LAP header from IrLMP layer */
skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
@@ -322,38 +317,9 @@ inline void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb)
}
}
#endif
- irlmp_link_data_indication(self->notify.instance, LAP_RELIABLE, skb);
+ irlmp_link_data_indication(self->notify.instance, skb, unreliable);
}
-/*
- * Function irlap_unit_data_indication (self, skb)
- *
- * Received some data that was sent unreliable
- *
- */
-void irlap_unit_data_indication(struct irlap_cb *self, struct sk_buff *skb)
-{
- IRDA_DEBUG(1, __FUNCTION__ "()\n");
-
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == LAP_MAGIC, return;);
- ASSERT(skb != NULL, return;);
-
- /* Hide LAP header from IrLMP layer */
- skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
-
-#ifdef CONFIG_IRDA_COMPRESSION
- if (self->qos_tx.compression.value) {
-
- skb = irlap_decompress_frame(self, skb);
- if (!skb) {
- IRDA_DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
- return;
- }
- }
-#endif
- irlmp_link_data_indication(self->notify.instance, LAP_UNRELIABLE, skb);
-}
/*
* Function irlap_data_request (self, skb)
@@ -361,12 +327,14 @@ void irlap_unit_data_indication(struct irlap_cb *self, struct sk_buff *skb)
* Queue data for transmission, must wait until XMIT state
*
*/
-inline void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
- int reliable)
+void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
+ int unreliable)
{
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
+ IRDA_DEBUG(3, __FUNCTION__ "()\n");
+
#ifdef CONFIG_IRDA_COMPRESSION
if (self->qos_tx.compression.value) {
skb = irlap_compress_frame(self, skb);
@@ -376,7 +344,6 @@ inline void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
}
}
#endif
-
ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
return;);
skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
@@ -385,12 +352,10 @@ inline void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
* Must set frame format now so that the rest of the code knows
* if its dealing with an I or an UI frame
*/
- if (reliable)
- skb->data[1] = I_FRAME;
- else {
- IRDA_DEBUG(4, __FUNCTION__ "(), queueing unreliable frame\n");
+ if (unreliable)
skb->data[1] = UI_FRAME;
- }
+ else
+ skb->data[1] = I_FRAME;
/*
* Send event if this frame only if we are in the right state
@@ -401,18 +366,67 @@ inline void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
* Check if the transmit queue contains some unsent frames,
* and if so, make sure they are sent first
*/
- if (!skb_queue_empty(&self->tx_list)) {
- skb_queue_tail(&self->tx_list, skb);
- skb = skb_dequeue(&self->tx_list);
+ if (!skb_queue_empty(&self->txq)) {
+ skb_queue_tail(&self->txq, skb);
+ skb = skb_dequeue(&self->txq);
ASSERT(skb != NULL, return;);
}
irlap_do_event(self, SEND_I_CMD, skb, NULL);
} else
- skb_queue_tail(&self->tx_list, skb);
+ skb_queue_tail(&self->txq, skb);
}
/*
+ * Function irlap_unitdata_request (self, skb)
+ *
+ * Send Ultra data. This is data that must be sent outside any connection
+ *
+ */
+#ifdef CONFIG_IRDA_ULTRA
+void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb)
+{
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
+
+ IRDA_DEBUG(3, __FUNCTION__ "()\n");
+
+ ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
+ return;);
+ skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+
+ skb->data[0] = CBROADCAST;
+ skb->data[1] = UI_FRAME;
+
+ skb_queue_tail(&self->txq_ultra, skb);
+
+ irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
+}
+#endif /*CONFIG_IRDA_ULTRA */
+
+/*
+ * Function irlap_udata_indication (self, skb)
+ *
+ * Receive Ultra data. This is data that is received outside any connection
+ *
+ */
+#ifdef CONFIG_IRDA_ULTRA
+void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
+{
+ IRDA_DEBUG(1, __FUNCTION__ "()\n");
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
+ ASSERT(skb != NULL, return;);
+
+ /* Hide LAP header from IrLMP layer */
+ skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+
+ irlmp_link_unitdata_indication(self->notify.instance, skb);
+}
+#endif /* CONFIG_IRDA_ULTRA */
+
+/*
* Function irlap_disconnect_request (void)
*
* Request to disconnect connection by service user
@@ -425,7 +439,7 @@ void irlap_disconnect_request(struct irlap_cb *self)
ASSERT(self->magic == LAP_MAGIC, return;);
/* Don't disconnect until all data frames are successfully sent */
- if (skb_queue_len(&self->tx_list) > 0) {
+ if (skb_queue_len(&self->txq) > 0) {
self->disconnect_pending = TRUE;
return;
@@ -466,7 +480,7 @@ void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
/* Flush queues */
irlap_flush_all_queues(self);
- switch(reason) {
+ switch (reason) {
case LAP_RESET_INDICATION:
IRDA_DEBUG(1, __FUNCTION__ "(), Sending reset request!\n");
irlap_do_event(self, RESET_REQUEST, NULL, NULL);
@@ -479,8 +493,7 @@ void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
reason, NULL);
break;
default:
- IRDA_DEBUG(1, __FUNCTION__ "(), Reason %d not implemented!\n",
- reason);
+ ERROR(__FUNCTION__ "(), Unknown reason %d\n", reason);
}
}
@@ -504,48 +517,47 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery)
(discovery->nslots == 8) || (discovery->nslots == 16),
return;);
+ /* Discovery is only possible in NDM mode */
+ if (self->state != LAP_NDM) {
+ IRDA_DEBUG(4, __FUNCTION__
+ "(), discovery only possible in NDM mode\n");
+ irlap_discovery_confirm(self, NULL);
+ return;
+ }
+
/* Check if last discovery request finished in time */
if (self->discovery_log != NULL) {
hashbin_delete(self->discovery_log, (FREE_FUNC) kfree);
self->discovery_log = NULL;
}
-
- /*
- * Discovery is only possible in NDM mode
- */
- if (self->state == LAP_NDM) {
- self->discovery_log= hashbin_new(HB_LOCAL);
-
- info.S = discovery->nslots; /* Number of slots */
- info.s = 0; /* Current slot */
-
- self->discovery_cmd = discovery;
- info.discovery = discovery;
-
- /* Check if the slot timeout is within limits */
- if (sysctl_slot_timeout < 20) {
- ERROR(__FUNCTION__
- "(), to low value for slot timeout!\n");
- sysctl_slot_timeout = 20;
- }
- /*
- * Highest value is actually 8, but we allow higher since
- * some devices seems to require it.
- */
- if (sysctl_slot_timeout > 160) {
- ERROR(__FUNCTION__
- "(), to high value for slot timeout!\n");
- sysctl_slot_timeout = 160;
- }
-
- self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
-
- irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
- } else {
- IRDA_DEBUG(4, __FUNCTION__
- "(), discovery only possible in NDM mode\n");
- irlap_discovery_confirm(self, NULL);
- }
+
+ self->discovery_log= hashbin_new(HB_LOCAL);
+
+ info.S = discovery->nslots; /* Number of slots */
+ info.s = 0; /* Current slot */
+
+ self->discovery_cmd = discovery;
+ info.discovery = discovery;
+
+ /* Check if the slot timeout is within limits */
+ if (sysctl_slot_timeout < 20) {
+ ERROR(__FUNCTION__
+ "(), to low value for slot timeout!\n");
+ sysctl_slot_timeout = 20;
+ }
+ /*
+ * Highest value is actually 8, but we allow higher since
+ * some devices seems to require it.
+ */
+ if (sysctl_slot_timeout > 160) {
+ ERROR(__FUNCTION__
+ "(), to high value for slot timeout!\n");
+ sysctl_slot_timeout = 160;
+ }
+
+ self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
+
+ irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
}
/*
@@ -790,17 +802,16 @@ void irlap_initiate_connection_state(struct irlap_cb *self)
*/
void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos)
{
+ __u32 min_turn_time;
__u32 speed;
- __u32 usecs;
- __u32 bytes ;
/* Get QoS values. */
speed = qos->baud_rate.value;
- usecs = qos->min_turn_time.value;
+ min_turn_time = qos->min_turn_time.value;
/* No need to calculate XBOFs for speeds over 115200 bps */
if (speed > 115200) {
- self->mtt_required = usecs;
+ self->mtt_required = min_turn_time;
return;
}
@@ -809,9 +820,7 @@ void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos)
* min turn time, so now we must calculate how many chars (XBOF's) we
* must send for the requested time period (min turn time)
*/
- bytes = speed * usecs / 10000000;
-
- self->xbofs_delay = bytes;
+ self->xbofs_delay = irlap_min_turn_time_in_bytes(speed, min_turn_time);
}
/*
@@ -828,9 +837,12 @@ void irlap_flush_all_queues(struct irlap_cb *self)
ASSERT(self->magic == LAP_MAGIC, return;);
/* Free transmission queue */
- while ((skb = skb_dequeue(&self->tx_list)) != NULL)
+ while ((skb = skb_dequeue(&self->txq)) != NULL)
dev_kfree_skb(skb);
+ while ((skb = skb_dequeue(&self->txq_ultra)) != NULL)
+ dev_kfree_skb(skb);
+
/* Free sliding window buffered packets */
while ((skb = skb_dequeue(&self->wx_list)) != NULL)
dev_kfree_skb(skb);
@@ -872,7 +884,7 @@ void irlap_init_comp_qos_capabilities(struct irlap_cb *self)
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
-
+
/*
* Find out which compressors we support. We do this be checking that
* the corresponding compressor for each bit set in the QoS bits has
@@ -888,17 +900,17 @@ void irlap_init_comp_qos_capabilities(struct irlap_cb *self)
IRDA_DEBUG(4, __FUNCTION__
"(), bit %d is set by defalt\n", 8-i);
comp = hashbin_find(irlap_compressors,
- compression[msb_index(mask)],
+ compressions[msb_index(mask)],
NULL);
if (!comp) {
/* Protocol not supported, so clear the bit */
IRDA_DEBUG(4, __FUNCTION__ "(), Compression "
- "protocol %d has not been loaded!\n",
- compression[msb_index(mask)]);
+ "protocol %d has not been loaded!\n",
+ compressions[msb_index(mask)]);
self->qos_rx.compression.bits &= ~mask;
IRDA_DEBUG(4, __FUNCTION__
- "(), comp bits 0x%02x\n",
- self->qos_rx.compression.bits);
+ "(), comp bits 0x%02x\n",
+ self->qos_rx.compression.bits);
}
}
/* Try the next bit */
@@ -955,17 +967,11 @@ void irlap_init_qos_capabilities(struct irlap_cb *self,
#endif
}
- /*
- * Make the intersection between IrLAP and drivers QoS
- * capabilities
- */
-
/* Use 500ms in IrLAP for now */
- self->qos_rx.max_turn_time.bits &= 0x03;
self->qos_rx.max_turn_time.bits &= 0x01;
/* Set data size */
- /* self->qos_rx.data_size.bits &= 0x03; */
+ /*self->qos_rx.data_size.bits &= 0x03;*/
/* Set disconnect time */
self->qos_rx.link_disc_time.bits &= 0x07;
@@ -988,21 +994,47 @@ void irlap_apply_default_connection_parameters(struct irlap_cb *self)
irlap_change_speed(self, 9600, TRUE);
+ /* Set mbusy when going to NDM state */
+ irda_device_set_media_busy(self->netdev, TRUE);
+
/* Default value in NDM */
self->bofs_count = 11;
- /* Use these until connection has been made */
+ /*
+ * Generate random connection address for this session, which must
+ * be 7 bits wide and different from 0x00 and 0xfe
+ */
+ while ((self->caddr == 0x00) || (self->caddr == 0xfe)) {
+ get_random_bytes(&self->caddr, sizeof(self->caddr));
+ self->caddr &= 0xfe;
+ }
+
+ /* Use default values until connection has been negitiated */
self->slot_timeout = sysctl_slot_timeout;
self->final_timeout = FINAL_TIMEOUT;
self->poll_timeout = POLL_TIMEOUT;
self->wd_timeout = WD_TIMEOUT;
+ /* Set some default values */
+ self->qos_tx.baud_rate.value = 9600;
+ self->qos_rx.baud_rate.value = 9600;
+ self->qos_tx.max_turn_time.value = 0;
+ self->qos_rx.max_turn_time.value = 0;
+ self->qos_tx.min_turn_time.value = 0;
+ self->qos_rx.min_turn_time.value = 0;
self->qos_tx.data_size.value = 64;
+ self->qos_rx.data_size.value = 64;
+ self->qos_tx.window_size.value = 1;
+ self->qos_rx.window_size.value = 1;
self->qos_tx.additional_bofs.value = 11;
+ self->qos_rx.additional_bofs.value = 11;
+ self->qos_tx.link_disc_time.value = 0;
+ self->qos_rx.link_disc_time.value = 0;
irlap_flush_all_queues(self);
self->disconnect_pending = FALSE;
+ self->connect_pending = FALSE;
}
/*
@@ -1011,56 +1043,62 @@ void irlap_apply_default_connection_parameters(struct irlap_cb *self)
* Initialize IrLAP with the negotiated QoS values
*
*/
-void irlap_apply_connection_parameters(struct irlap_cb *self,
- struct qos_info *qos)
+void irlap_apply_connection_parameters(struct irlap_cb *self)
{
IRDA_DEBUG(4, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
- irlap_change_speed(self, qos->baud_rate.value, FALSE);
+ irlap_change_speed(self, self->qos_tx.baud_rate.value, FALSE);
- self->window_size = qos->window_size.value;
- self->window = qos->window_size.value;
- self->bofs_count = qos->additional_bofs.value;
+ self->window_size = self->qos_tx.window_size.value;
+ self->window = self->qos_tx.window_size.value;
+ self->bofs_count = self->qos_tx.additional_bofs.value;
/*
* Calculate how many bytes it is possible to transmit before the
- * link must be turned around wb = baud * mtt/1000 * 1/2
+ * link must be turned around
*/
- self->window_bytes = qos->baud_rate.value
- * qos->max_turn_time.value / 10000;
- IRDA_DEBUG(4, "Setting window_bytes = %d\n", self->window_bytes);
-
+ self->line_capacity =
+ irlap_max_line_capacity(self->qos_tx.baud_rate.value,
+ self->qos_tx.max_turn_time.value);
/*
* Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to
* 3 seconds otherwise. See page 71 in IrLAP for more details.
* TODO: these values should be calculated from the final timer
* as well
*/
- if (qos->link_disc_time.value == 3)
+ ASSERT(self->qos_tx.max_turn_time.value != 0, return;);
+ if (self->qos_tx.link_disc_time.value == 3)
self->N1 = 0;
else
- self->N1 = 3000 / qos->max_turn_time.value;
+ self->N1 = 3000 / self->qos_tx.max_turn_time.value;
IRDA_DEBUG(4, "Setting N1 = %d\n", self->N1);
- self->N2 = qos->link_disc_time.value * 1000 / qos->max_turn_time.value;
+
+ self->N2 = self->qos_tx.link_disc_time.value * 1000 /
+ self->qos_tx.max_turn_time.value;
IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2);
/*
* Initialize timeout values, some of the rules are listed on
* page 92 in IrLAP.
*/
- self->poll_timeout = qos->max_turn_time.value * HZ / 1000;
- self->final_timeout = qos->max_turn_time.value * HZ / 1000;
+ self->poll_timeout = self->qos_tx.max_turn_time.value * HZ / 1000;
self->wd_timeout = self->poll_timeout * 2;
+ /*
+ * Be careful to keep our promises to the peer device about how long
+ * time it can keep the pf bit. So here we must use the rx_qos value
+ */
+ self->final_timeout = self->qos_rx.max_turn_time.value * HZ / 1000;
+
#ifdef CONFIG_IRDA_COMPRESSION
- if (qos->compression.value) {
+ if (self->qos_tx.compression.value) {
IRDA_DEBUG(1, __FUNCTION__ "(), Initializing compression\n");
- irda_set_compression(self, qos->compression.value);
+ irda_set_compression(self, self->qos_tx.compression.value);
irlap_compressor_init(self, 0);
}
@@ -1087,7 +1125,7 @@ void irlap_set_local_busy(struct irlap_cb *self, int status)
#ifdef CONFIG_PROC_FS
/*
- * Function irlap_proc_read (buf, start, offset, len)
+ * Function irlap_proc_read (buf, start, offset, len, unused)
*
* Give some info to the /proc file system
*
@@ -1110,24 +1148,28 @@ int irlap_proc_read(char *buf, char **start, off_t offset, int len)
len += sprintf(buf+len, "irlap%d ", i++);
len += sprintf(buf+len, "state: %s\n",
- irlap_state[ self->state]);
+ irlap_state[self->state]);
len += sprintf(buf+len, " caddr: %#02x, ", self->caddr);
len += sprintf(buf+len, "saddr: %#08x, ", self->saddr);
len += sprintf(buf+len, "daddr: %#08x\n", self->daddr);
len += sprintf(buf+len, " win size: %d, ",
- self->window_size);
+ self->window_size);
len += sprintf(buf+len, "win: %d, ", self->window);
- len += sprintf(buf+len, "win bytes: %d, ", self->window_bytes);
+#if CONFIG_IRDA_DYNAMIC_WINDOW
+ len += sprintf(buf+len, "line capacity: %d, ",
+ self->line_capacity);
len += sprintf(buf+len, "bytes left: %d\n", self->bytes_left);
-
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
len += sprintf(buf+len, " tx queue len: %d ",
- skb_queue_len(&self->tx_list));
+ skb_queue_len(&self->txq));
len += sprintf(buf+len, "win queue len: %d ",
- skb_queue_len(&self->wx_list));
- len += sprintf(buf+len, "rbusy: %s\n", self->remote_busy ?
- "TRUE" : "FALSE");
+ skb_queue_len(&self->wx_list));
+ len += sprintf(buf+len, "rbusy: %s", self->remote_busy ?
+ "TRUE" : "FALSE");
+ len += sprintf(buf+len, " mbusy: %s\n", self->media_busy ?
+ "TRUE" : "FALSE");
len += sprintf(buf+len, " retrans: %d ", self->retry_count);
len += sprintf(buf+len, "vs: %d ", self->vs);
@@ -1137,42 +1179,42 @@ int irlap_proc_read(char *buf, char **start, off_t offset, int len)
len += sprintf(buf+len, " qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n");
len += sprintf(buf+len, " tx\t%d\t",
- self->qos_tx.baud_rate.value);
+ self->qos_tx.baud_rate.value);
len += sprintf(buf+len, "%d\t",
- self->qos_tx.max_turn_time.value);
+ self->qos_tx.max_turn_time.value);
len += sprintf(buf+len, "%d\t",
- self->qos_tx.data_size.value);
+ self->qos_tx.data_size.value);
len += sprintf(buf+len, "%d\t",
- self->qos_tx.window_size.value);
+ self->qos_tx.window_size.value);
len += sprintf(buf+len, "%d\t",
- self->qos_tx.additional_bofs.value);
+ self->qos_tx.additional_bofs.value);
len += sprintf(buf+len, "%d\t",
- self->qos_tx.min_turn_time.value);
+ self->qos_tx.min_turn_time.value);
len += sprintf(buf+len, "%d\t",
- self->qos_tx.link_disc_time.value);
+ self->qos_tx.link_disc_time.value);
#ifdef CONFIG_IRDA_COMPRESSION
len += sprintf(buf+len, "%d",
- self->qos_tx.compression.value);
+ self->qos_tx.compression.value);
#endif
len += sprintf(buf+len, "\n");
len += sprintf(buf+len, " rx\t%d\t",
- self->qos_rx.baud_rate.value);
+ self->qos_rx.baud_rate.value);
len += sprintf(buf+len, "%d\t",
- self->qos_rx.max_turn_time.value);
+ self->qos_rx.max_turn_time.value);
len += sprintf(buf+len, "%d\t",
- self->qos_rx.data_size.value);
+ self->qos_rx.data_size.value);
len += sprintf(buf+len, "%d\t",
- self->qos_rx.window_size.value);
+ self->qos_rx.window_size.value);
len += sprintf(buf+len, "%d\t",
- self->qos_rx.additional_bofs.value);
+ self->qos_rx.additional_bofs.value);
len += sprintf(buf+len, "%d\t",
- self->qos_rx.min_turn_time.value);
+ self->qos_rx.min_turn_time.value);
len += sprintf(buf+len, "%d\t",
- self->qos_rx.link_disc_time.value);
+ self->qos_rx.link_disc_time.value);
#ifdef CONFIG_IRDA_COMPRESSION
len += sprintf(buf+len, "%d",
- self->qos_rx.compression.value);
+ self->qos_rx.compression.value);
#endif
len += sprintf(buf+len, "\n");
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index 7ddadc761..08501162e 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -1,12 +1,12 @@
/*********************************************************************
*
* Filename: irlap_event.c
- * Version: 0.8
+ * Version: 0.9
* Description: IrLAP state machine implementation
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Aug 16 00:59:29 1997
- * Modified at: Tue Nov 16 12:33:41 1999
+ * Modified at: Sat Dec 25 21:07:57 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
@@ -85,6 +85,7 @@ static const char *irlap_event[] = {
"RESET_REQUEST",
"RESET_RESPONSE",
"SEND_I_CMD",
+ "SEND_UI_FRAME",
"RECV_DISCOVERY_XID_CMD",
"RECV_DISCOVERY_XID_RSP",
"RECV_SNRM_CMD",
@@ -92,14 +93,20 @@ static const char *irlap_event[] = {
"RECV_TEST_RSP",
"RECV_UA_RSP",
"RECV_DM_RSP",
+ "RECV_RD_RSP",
"RECV_I_CMD",
"RECV_I_RSP",
"RECV_UI_FRAME",
"RECV_FRMR_RSP",
"RECV_RR_CMD",
"RECV_RR_RSP",
- "RECV_RNR_FRAME",
- "RECV_DISC_FRAME",
+ "RECV_RNR_CMD",
+ "RECV_RNR_RSP",
+ "RECV_REJ_CMD",
+ "RECV_REJ_RSP",
+ "RECV_SREJ_CMD",
+ "RECV_SREJ_RSP",
+ "RECV_DISC_CMD",
"SLOT_TIMER_EXPIRED",
"QUERY_TIMER_EXPIRED",
"FINAL_TIMER_EXPIRED",
@@ -173,7 +180,7 @@ void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
* Send out the RR frames faster if our own transmit queue is empty, or
* if the peer is busy. The effect is a much faster conversation
*/
- if ((skb_queue_len(&self->tx_list) == 0) || (self->remote_busy)) {
+ if ((skb_queue_len(&self->txq) == 0) || (self->remote_busy)) {
if (self->fast_RR == TRUE) {
/*
* Assert that the fast poll timer has not reached the
@@ -200,8 +207,9 @@ void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
} else
self->fast_RR = FALSE;
- IRDA_DEBUG(4, __FUNCTION__ "(), Timeout=%d\n", timeout);
-#endif
+ IRDA_DEBUG(3, __FUNCTION__ "(), timeout=%d (%ld)\n", timeout, jiffies);
+#endif /* CONFIG_IRDA_FAST_RR */
+
if (timeout == 0)
irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
else
@@ -223,11 +231,11 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
if (!self || self->magic != LAP_MAGIC)
return;
- IRDA_DEBUG(4, __FUNCTION__ "(), event = %s, state = %s\n",
- irlap_event[event], irlap_state[self->state]);
+ IRDA_DEBUG(3, __FUNCTION__ "(), event = %s, state = %s\n",
+ irlap_event[event], irlap_state[self->state]);
ret = (*state[self->state])(self, event, skb, info);
-
+
/*
* Check if there are any pending events that needs to be executed
*/
@@ -239,9 +247,9 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
* try to disconnect link if we send any data frames, since
* that will change the state away form XMIT
*/
- if (skb_queue_len(&self->tx_list)) {
+ if (skb_queue_len(&self->txq)) {
/* Try to send away all queued data frames */
- while ((skb = skb_dequeue(&self->tx_list)) != NULL) {
+ while ((skb = skb_dequeue(&self->txq)) != NULL) {
ret = (*state[self->state])(self, SEND_I_CMD,
skb, NULL);
if (ret == -EPROTO)
@@ -282,10 +290,11 @@ void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state)
if (!self || self->magic != LAP_MAGIC)
return;
- IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[ state]);
+ IRDA_DEBUG(4, "next LAP state = %s\n", irlap_state[state]);
self->state = state;
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
/*
* If we are swithing away from a XMIT state then we are allowed to
* transmit a maximum number of bytes again when we enter the XMIT
@@ -293,7 +302,8 @@ void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state)
* we cannot do this when swithing into the XMIT state :-)
*/
if ((state != LAP_XMIT_P) && (state != LAP_XMIT_S))
- self->bytes_left = self->window_bytes;
+ self->bytes_left = self->line_capacity;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
}
/*
@@ -307,7 +317,8 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
{
discovery_t *discovery_rsp;
int ret = 0;
-
+ int i;
+
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == LAP_MAGIC, return -1;);
@@ -317,7 +328,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
if (self->media_busy) {
IRDA_DEBUG(0, __FUNCTION__
- "(), CONNECT_REQUEST: media busy!\n");
+ "(), CONNECT_REQUEST: media busy!\n");
/* Always switch state before calling upper layers */
irlap_next_state(self, LAP_NDM);
@@ -343,9 +354,8 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
irlap_connect_indication(self, skb);
} else {
- IRDA_DEBUG(0, __FUNCTION__
- "(), SNRM frame does not contain"
- " and I field!\n");
+ IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame does not "
+ "contain an I field!\n");
dev_kfree_skb(skb);
}
break;
@@ -355,10 +365,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
if (self->media_busy) {
IRDA_DEBUG(0, __FUNCTION__ "(), media busy!\n");
/* irlap->log.condition = MEDIA_BUSY; */
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
+
/* This will make IrLMP try again */
irlap_discovery_confirm(self, NULL);
return 0;
@@ -405,6 +412,32 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
}
dev_kfree_skb(skb);
break;
+#ifdef CONFIG_IRDA_ULTRA
+ case SEND_UI_FRAME:
+ /* Only allowed to repeat an operation twice */
+ for (i=0; ((i<2) && (self->media_busy == FALSE)); i++) {
+ skb = skb_dequeue(&self->txq_ultra);
+ if (skb)
+ irlap_send_ui_frame(self, skb, CBROADCAST,
+ CMD_FRAME);
+ else
+ break;
+ }
+ if (i == 2) {
+ /* Force us to listen 500 ms again */
+ irda_device_set_media_busy(self->netdev, TRUE);
+ }
+ break;
+ case RECV_UI_FRAME:
+ /* Only accept broadcast frames in NDM mode */
+ if (info->caddr != CBROADCAST) {
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), not a broadcast frame!\n");
+ dev_kfree_skb(skb);
+ } else
+ irlap_unitdata_indication(self, skb);
+ break;
+#endif /* CONFIG_IRDA_ULTRA */
case RECV_TEST_CMD:
/* Remove test frame header */
skb_pull(skb, sizeof(struct test_frame));
@@ -413,7 +446,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
* Send response. This skb will not be sent out again, and
* will only be used to send out the same info as the cmd
*/
- irlap_send_test_frame(self, info->daddr, skb);
+ irlap_send_test_frame(self, CBROADCAST, info->daddr, skb);
dev_kfree_skb(skb);
break;
case RECV_TEST_RSP:
@@ -422,8 +455,8 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
break;
default:
IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
- irlap_event[event]);
-
+ irlap_event[event]);
+
if (skb)
dev_kfree_skb(skb);
@@ -447,28 +480,29 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event,
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == LAP_MAGIC, return -1;);
- switch(event) {
+ switch (event) {
case RECV_DISCOVERY_XID_RSP:
ASSERT(info != NULL, return -1;);
ASSERT(info->discovery != NULL, return -1;);
IRDA_DEBUG(4, __FUNCTION__ "(), daddr=%08x\n",
- info->discovery->daddr);
+ info->discovery->daddr);
if (!self->discovery_log) {
WARNING(__FUNCTION__ "(), discovery log is gone! "
"maybe the discovery timeout has been set to "
"short?\n");
+ dev_kfree_skb(skb);
break;
}
hashbin_insert(self->discovery_log,
(queue_t *) info->discovery,
info->discovery->daddr, NULL);
- dev_kfree_skb(skb);
-
/* Keep state */
- irlap_next_state(self, LAP_QUERY);
+ /* irlap_next_state(self, LAP_QUERY); */
+
+ dev_kfree_skb(skb);
break;
case SLOT_TIMER_EXPIRED:
if (self->s < self->S) {
@@ -500,8 +534,8 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event,
}
break;
default:
- IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d, %s\n", event,
- irlap_event[event]);
+ IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
+ irlap_event[event]);
if (skb)
dev_kfree_skb(skb);
@@ -565,10 +599,10 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event,
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
- irlap_event[event]);
+ irlap_event[event]);
- if ( skb)
- dev_kfree_skb( skb);
+ if (skb)
+ dev_kfree_skb(skb);
ret = -1;
break;
@@ -595,7 +629,6 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event,
switch (event) {
case CONNECT_RESPONSE:
- /* skb_pull(skb, 11); */
skb_pull(skb, sizeof(struct snrm_frame));
ASSERT(self->netdev != NULL, return -1;);
@@ -616,7 +649,7 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event,
* Applying the parameters now will make sure we change speed
* after we have sent the next frame
*/
- irlap_apply_connection_parameters(self, &self->qos_tx);
+ irlap_apply_connection_parameters(self);
/*
* Sending this frame will force a speed change after it has
@@ -631,10 +664,15 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event,
*/
irlap_start_wd_timer(self, self->wd_timeout);
irlap_next_state(self, LAP_NRM_S);
+
+ dev_kfree_skb(skb);
break;
case RECV_DISCOVERY_XID_CMD:
- IRDA_DEBUG(3, __FUNCTION__ "(), event RECV_DISCOVER_XID_CMD!\n");
+ IRDA_DEBUG(3, __FUNCTION__
+ "(), event RECV_DISCOVER_XID_CMD!\n");
irlap_next_state(self, LAP_NDM);
+
+ dev_kfree_skb(skb);
break;
case DISCONNECT_REQUEST:
irlap_send_dm_frame(self);
@@ -671,7 +709,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == LAP_MAGIC, return -1;);
- switch(event) {
+ switch (event) {
case FINAL_TIMER_EXPIRED:
if (self->retry_count < self->N3) {
/*
@@ -694,7 +732,6 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_final_timer(self, self->final_timeout);
self->retry_count++;
break;
-
case RECV_SNRM_CMD:
IRDA_DEBUG(4, __FUNCTION__ "(), SNRM battle!\n");
@@ -716,7 +753,9 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
irlap_qos_negotiate(self, skb);
irlap_send_ua_response_frame(self, &self->qos_rx);
- irlap_apply_connection_parameters(self, &self->qos_tx);
+ irlap_apply_connection_parameters(self);
+
+ irlap_next_state(self, LAP_NRM_S);
irlap_connect_confirm(self, skb);
/*
@@ -725,8 +764,6 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
* to use twice the value (note 3 IrLAP p. 60).
*/
irlap_start_wd_timer(self, self->wd_timeout);
-
- irlap_next_state(self, LAP_NRM_S);
} else {
/* We just ignore the other device! */
dev_kfree_skb(skb);
@@ -749,7 +786,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
irlap_qos_negotiate(self, skb);
- irlap_apply_connection_parameters(self, &self->qos_tx);
+ irlap_apply_connection_parameters(self);
self->retry_count = 0;
/* This frame will actually force the speed change */
@@ -760,22 +797,20 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
irlap_connect_confirm(self, skb);
break;
-
- case RECV_DISC_FRAME:
+ case RECV_DM_RSP: /* FALLTHROUGH */
+ case RECV_DISC_CMD:
del_timer(&self->final_timer);
irlap_next_state(self, LAP_NDM);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+ dev_kfree_skb(skb);
break;
-
- /* DM handled in irlap_frame.c, irlap_driver_rcv() */
default:
- IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
- irlap_event[event]);
-
+ IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
+ irlap_event[event]);
if (skb)
dev_kfree_skb(skb);
-
+
ret = -1;
break;
}
@@ -815,16 +850,17 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
* Only send frame if send-window > 0.
*/
if ((self->window > 0) && (!self->remote_busy)) {
-
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
/*
* Test if we have transmitted more bytes over the
* link than its possible to do with the current
* speed and turn-around-time.
*/
- if ((skb->len+self->bofs_count) > self->bytes_left) {
- IRDA_DEBUG(4, __FUNCTION__ "(), Not allowed to "
- "transmit more bytes!\n");
- skb_queue_head(&self->tx_list, skb);
+ if (skb->len > self->bytes_left) {
+ IRDA_DEBUG(4, __FUNCTION__
+ "(), Not allowed to transmit more "
+ "bytes!\n");
+ skb_queue_head(&self->txq, skb);
/*
* We should switch state to LAP_NRM_P, but
@@ -836,14 +872,14 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
*/
return -EPROTO;
}
- self->bytes_left -= (skb->len + self->bofs_count);
-
+ self->bytes_left -= skb->len;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
/*
* Send data with poll bit cleared only if window > 1
* and there is more frames after this one to be sent
*/
if ((self->window > 1) &&
- skb_queue_len( &self->tx_list) > 0)
+ skb_queue_len( &self->txq) > 0)
{
irlap_send_data_primary(self, skb);
irlap_next_state(self, LAP_XMIT_P);
@@ -860,11 +896,11 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
#ifdef CONFIG_IRDA_FAST_RR
/* Peer may want to reply immediately */
self->fast_RR = FALSE;
-#endif
+#endif /* CONFIG_IRDA_FAST_RR */
} else {
IRDA_DEBUG(4, __FUNCTION__
- "(), Unable to send! remote busy?\n");
- skb_queue_head(&self->tx_list, skb);
+ "(), Unable to send! remote busy?\n");
+ skb_queue_head(&self->txq, skb);
/*
* The next ret is important, because it tells
@@ -874,6 +910,8 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
}
break;
case POLL_TIMER_EXPIRED:
+ IRDA_DEBUG(3, __FUNCTION__ "(), POLL_TIMER_EXPIRED (%ld)\n",
+ jiffies);
irlap_send_rr_frame(self, CMD_FRAME);
irlap_start_final_timer(self, self->final_timeout);
irlap_next_state(self, LAP_NRM_P);
@@ -889,7 +927,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
break;
default:
IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
- irlap_event[event]);
+ irlap_event[event]);
if (skb)
dev_kfree_skb(skb);
@@ -916,16 +954,17 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event,
ASSERT(self->magic == LAP_MAGIC, return -1;);
switch (event) {
- case RECV_UA_RSP:
+ case RECV_UA_RSP: /* FALLTHROUGH */
+ case RECV_DM_RSP:
del_timer(&self->final_timer);
irlap_apply_default_connection_parameters(self);
/* Always switch state before calling upper layers */
irlap_next_state(self, LAP_NDM);
-
+
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
-
+ dev_kfree_skb(skb);
break;
case FINAL_TIMER_EXPIRED:
if (self->retry_count < self->N3) {
@@ -937,9 +976,7 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event,
} else {
irlap_apply_default_connection_parameters(self);
- /*
- * Always switch state before calling upper layers
- */
+ /* Always switch state before calling upper layers */
irlap_next_state(self, LAP_NDM);
irlap_disconnect_indication(self, LAP_NO_RESPONSE);
@@ -983,7 +1020,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
* to transmitt
*/
self->fast_RR = FALSE;
-#endif
+#endif /* CONFIG_IRDA_FAST_RR */
ASSERT( info != NULL, return -1;);
ns_status = irlap_validate_ns_received(self, info->ns);
@@ -993,9 +1030,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
* Check for expected I(nformation) frame
*/
if ((ns_status == NS_EXPECTED) && (nr_status == NR_EXPECTED)) {
- /*
- * poll bit cleared?
- */
+ /* poll bit cleared? */
if (!info->pf) {
self->vr = (self->vr + 1) % 8;
@@ -1007,7 +1042,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_P);
- irlap_data_indication(self, skb);
+ irlap_data_indication(self, skb, FALSE);
} else {
del_timer(&self->final_timer);
@@ -1031,7 +1066,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
*/
irlap_next_state(self, LAP_XMIT_P);
- irlap_data_indication(self, skb);
+ irlap_data_indication(self, skb, FALSE);
/* This is the last frame */
irlap_start_poll_timer(self, self->poll_timeout);
@@ -1039,9 +1074,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
break;
}
- /*
- * Unexpected next to send (Ns)
- */
+ /* Unexpected next to send (Ns) */
if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
{
if (!info->pf) {
@@ -1055,7 +1088,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state */
irlap_next_state(self, LAP_NRM_P);
} else {
- IRDA_DEBUG( 4, __FUNCTION__
+ IRDA_DEBUG(4, __FUNCTION__
"(), missing or duplicate frame!\n");
/* Update Nr received */
@@ -1092,7 +1125,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_P);
- irlap_data_indication(self, skb);
+ irlap_data_indication(self, skb, FALSE);
} else {
/*
* Do not resend frames until the last
@@ -1110,7 +1143,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state, do not move this line!*/
irlap_next_state(self, LAP_NRM_P);
- irlap_data_indication(self, skb);
+ irlap_data_indication(self, skb, FALSE);
}
break;
}
@@ -1121,7 +1154,8 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
if ((ns_status == NS_UNEXPECTED) &&
(nr_status == NR_UNEXPECTED))
{
- IRDA_DEBUG( 4, "IrLAP: unexpected nr and ns!\n");
+ IRDA_DEBUG(4, __FUNCTION__
+ "(), unexpected nr and ns!\n");
if (info->pf) {
/* Resend rejected frames */
irlap_resend_rejected_frames(self, CMD_FRAME);
@@ -1137,6 +1171,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
self->ack_required = FALSE;
}
+ dev_kfree_skb(skb);
break;
}
@@ -1148,7 +1183,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
del_timer(&self->final_timer);
irlap_next_state(self, LAP_RESET_WAIT);
-
+
irlap_disconnect_indication(self, LAP_RESET_INDICATION);
self->xmitflag = TRUE;
} else {
@@ -1158,6 +1193,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
self->xmitflag = FALSE;
}
+ dev_kfree_skb(skb);
break;
}
IRDA_DEBUG(1, __FUNCTION__ "(), Not implemented!\n");
@@ -1166,13 +1202,13 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
irlap_event[ event], ns_status, nr_status);
break;
case RECV_UI_FRAME:
- /* poll bit cleared? */
+ /* Poll bit cleared? */
if (!info->pf) {
- irlap_unit_data_indication(self, skb);
+ irlap_data_indication(self, skb, TRUE);
irlap_next_state(self, LAP_NRM_P);
} else {
del_timer(&self->final_timer);
- irlap_unit_data_indication(self, skb);
+ irlap_data_indication(self, skb, TRUE);
irlap_start_poll_timer(self, self->poll_timeout);
}
break;
@@ -1226,7 +1262,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
irlap_next_state(self, LAP_NRM_P);
} else if (ret == NR_INVALID) {
IRDA_DEBUG(1, __FUNCTION__ "(), Received RR with "
- "invalid nr !\n");
+ "invalid nr !\n");
del_timer(&self->final_timer);
irlap_next_state(self, LAP_RESET_WAIT);
@@ -1234,15 +1270,9 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
irlap_disconnect_indication(self, LAP_RESET_INDICATION);
self->xmitflag = TRUE;
}
- if (skb)
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
break;
- case RECV_RNR_FRAME:
- IRDA_DEBUG(4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, "
- "nr=%d, va=%d, vs=%d, vr=%d\n",
- self->retry_count, info->nr, self->va, self->vs,
- self->vr);
-
+ case RECV_RNR_RSP:
ASSERT(info != NULL, return -1;);
/* Stop final timer */
@@ -1251,21 +1281,18 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Update Nr received */
irlap_update_nr_received(self, info->nr);
-
irlap_next_state(self, LAP_XMIT_P);
/* Start poll timer */
irlap_start_poll_timer(self, self->poll_timeout);
- if (skb)
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
break;
case RECV_FRMR_RSP:
del_timer(&self->final_timer);
self->xmitflag = TRUE;
irlap_next_state(self, LAP_RESET_WAIT);
irlap_reset_indication(self);
- if (skb)
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
break;
case FINAL_TIMER_EXPIRED:
/*
@@ -1274,8 +1301,10 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
* of receiving a frame (page 45, IrLAP). Check that
* we only do this once for each frame.
*/
- if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
- IRDA_DEBUG(4, "FINAL_TIMER_EXPIRED when receiving a "
+ if (irda_device_is_receiving(self->netdev) &&
+ !self->add_wait)
+ {
+ IRDA_DEBUG(1, "FINAL_TIMER_EXPIRED when receiving a "
"frame! Waiting a little bit more!\n");
irlap_start_final_timer(self, MSECS_TO_JIFFIES(300));
@@ -1299,7 +1328,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
self->retry_count++;
IRDA_DEBUG(4, "irlap_state_nrm_p: FINAL_TIMER_EXPIRED:"
- " retry_count=%d\n", self->retry_count);
+ " retry_count=%d\n", self->retry_count);
/* Keep state */
} else if (self->retry_count == self->N1) {
irlap_status_indication(STATUS_NO_ACTIVITY);
@@ -1310,7 +1339,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
self->retry_count++;
IRDA_DEBUG(4, "retry count = N1; retry_count=%d\n",
- self->retry_count);
+ self->retry_count);
/* Keep state */
} else if (self->retry_count >= self->N2) {
irlap_apply_default_connection_parameters(self);
@@ -1320,30 +1349,38 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
irlap_disconnect_indication(self, LAP_NO_RESPONSE);
}
break;
- case RECV_DISC_FRAME: /* FIXME: Check how this is in the standard! */
- IRDA_DEBUG(1, __FUNCTION__ "(), RECV_DISC_FRAME()\n");
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_ua_response_frame(self, NULL);
-
- del_timer(&self->final_timer);
- /* del_timer( &self->poll_timer); */
+ case RECV_REJ_RSP:
+ irlap_update_nr_received(self, info->nr);
+ if (self->remote_busy) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rr_frame(self, CMD_FRAME);
+ } else
+ irlap_resend_rejected_frames(self, CMD_FRAME);
+ irlap_start_final_timer(self, self->final_timeout);
+ dev_kfree_skb(skb);
+ break;
+ case RECV_SREJ_RSP:
+ irlap_update_nr_received(self, info->nr);
+ if (self->remote_busy) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rr_frame(self, CMD_FRAME);
+ } else
+ irlap_resend_rejected_frame(self, CMD_FRAME);
+ irlap_start_final_timer(self, self->final_timeout);
+ dev_kfree_skb(skb);
+ break;
+ case RECV_RD_RSP:
+ IRDA_DEBUG(0, __FUNCTION__ "(), RECV_RD_RSP\n");
+ irlap_next_state(self, LAP_PCLOSE);
+ irlap_send_disc_frame(self);
irlap_flush_all_queues(self);
- irlap_apply_default_connection_parameters(self);
-
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- if (skb)
- dev_kfree_skb(skb);
-
+ irlap_start_final_timer(self, self->final_timeout);
+ self->retry_count = 0;
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n",
- irlap_event[event]);
-
+ irlap_event[event]);
if (skb)
dev_kfree_skb(skb);
@@ -1392,7 +1429,7 @@ static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event,
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n",
- irlap_event[event]);
+ irlap_event[event]);
if (skb)
dev_kfree_skb(skb);
@@ -1420,7 +1457,7 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
ASSERT(self->magic == LAP_MAGIC, return -1;);
switch (event) {
- case RECV_DISC_FRAME:
+ case RECV_DISC_CMD:
del_timer(&self->final_timer);
irlap_apply_default_connection_parameters(self);
@@ -1429,6 +1466,8 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
irlap_next_state(self, LAP_NDM);
irlap_disconnect_indication(self, LAP_NO_RESPONSE);
+
+ dev_kfree_skb(skb);
break;
case RECV_UA_RSP:
del_timer(&self->final_timer);
@@ -1443,6 +1482,8 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
irlap_next_state(self, LAP_XMIT_P);
irlap_start_poll_timer(self, self->poll_timeout);
+
+ dev_kfree_skb(skb);
break;
case FINAL_TIMER_EXPIRED:
if (self->retry_count < 3) {
@@ -1478,15 +1519,14 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_wd_timer(self, self->wd_timeout);
irlap_next_state(self, LAP_NDM);
} else {
- IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame contained an I "
- "field!\n");
- dev_kfree_skb(skb);
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), SNRM frame contained an I field!\n");
}
+ dev_kfree_skb(skb);
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n",
- irlap_event[event]);
-
+ irlap_event[event]);
if (skb)
dev_kfree_skb(skb);
@@ -1508,7 +1548,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
{
int ret = 0;
- IRDA_DEBUG(4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
+ IRDA_DEBUG(4, __FUNCTION__ "(), event=%s\n", irlap_event[event]);
ASSERT(self != NULL, return -ENODEV;);
ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
@@ -1519,13 +1559,14 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
* Send frame only if send window > 1
*/
if ((self->window > 0) && (!self->remote_busy)) {
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
/*
* Test if we have transmitted more bytes over the
* link than its possible to do with the current
* speed and turn-around-time.
*/
- if ((skb->len+self->bofs_count) > self->bytes_left) {
- skb_queue_head(&self->tx_list, skb);
+ if (skb->len > self->bytes_left) {
+ skb_queue_head(&self->txq, skb);
/*
* Switch to NRM_S, this is only possible
* when we are in secondary mode, since we
@@ -1536,14 +1577,14 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
return -EPROTO; /* Try again later */
}
- self->bytes_left -= (skb->len + self->bofs_count);
-
+ self->bytes_left -= skb->len;
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
/*
* Send data with final bit cleared only if window > 1
* and there is more frames to be sent
*/
if ((self->window > 1) &&
- skb_queue_len(&self->tx_list) > 0)
+ skb_queue_len(&self->txq) > 0)
{
irlap_send_data_secondary(self, skb);
irlap_next_state(self, LAP_XMIT_S);
@@ -1558,14 +1599,20 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
ret = -EPROTO;
}
} else {
- IRDA_DEBUG(1, __FUNCTION__ "(), Unable to send!\n");
- skb_queue_head( &self->tx_list, skb);
+ IRDA_DEBUG(2, __FUNCTION__ "(), Unable to send!\n");
+ skb_queue_head(&self->txq, skb);
ret = -EPROTO;
}
break;
+ case DISCONNECT_REQUEST:
+ irlap_send_rd_frame(self);
+ irlap_flush_all_queues(self);
+ irlap_start_wd_timer(self, self->wd_timeout);
+ irlap_next_state(self, LAP_SCLOSE);
+ break;
default:
- IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n",
- irlap_event[event]);
+ IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
+ irlap_event[event]);
if (skb)
dev_kfree_skb(skb);
@@ -1598,8 +1645,8 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
case RECV_I_CMD: /* Optimize for the common case */
/* FIXME: must check for remote_busy below */
IRDA_DEBUG(4, __FUNCTION__ "(), event=%s nr=%d, vs=%d, ns=%d, "
- "vr=%d, pf=%d\n", irlap_event[event], info->nr,
- self->vs, info->ns, self->vr, info->pf);
+ "vr=%d, pf=%d\n", irlap_event[event], info->nr,
+ self->vs, info->ns, self->vr, info->pf);
self->retry_count = 0;
@@ -1624,18 +1671,19 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
* Starting WD-timer here is optional, but
* not recommended. Note 6 IrLAP p. 83
*/
- /* irda_start_timer(WD_TIMER, self->wd_timeout); */
-
+#if 0
+ irda_start_timer(WD_TIMER, self->wd_timeout);
+#endif
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_S);
- irlap_data_indication( self, skb);
+ irlap_data_indication(self, skb, FALSE);
break;
} else {
self->vr = (self->vr + 1) % 8;
/* Update Nr received */
- irlap_update_nr_received( self, info->nr);
+ irlap_update_nr_received(self, info->nr);
/*
* We should wait before sending RR, and
@@ -1650,10 +1698,10 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
* we decide if we should send a RR frame
* or not
*/
- irlap_data_indication(self, skb);
+ irlap_data_indication(self, skb, FALSE);
/* Any pending data requests? */
- if ((skb_queue_len(&self->tx_list) > 0) &&
+ if ((skb_queue_len(&self->txq) > 0) &&
(self->window > 0))
{
self->ack_required = TRUE;
@@ -1714,7 +1762,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_S);
- irlap_data_indication(self, skb);
+ irlap_data_indication(self, skb, FALSE);
irlap_start_wd_timer(self, self->wd_timeout);
break;
}
@@ -1731,16 +1779,19 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_S);
- irlap_data_indication(self, skb);
+ irlap_data_indication(self, skb, FALSE);
irlap_start_wd_timer(self, self->wd_timeout);
}
+ break;
}
if (ret == NR_INVALID) {
IRDA_DEBUG(0, "NRM_S, NR_INVALID not implemented!\n");
+ dev_kfree_skb(skb);
}
if (ret == NS_INVALID) {
IRDA_DEBUG(0, "NRM_S, NS_INVALID not implemented!\n");
+ dev_kfree_skb(skb);
}
break;
case RECV_UI_FRAME:
@@ -1748,22 +1799,22 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
* poll bit cleared?
*/
if (!info->pf) {
- irlap_unit_data_indication(self, skb);
+ irlap_data_indication(self, skb, TRUE);
irlap_next_state(self, LAP_NRM_S); /* Keep state */
} else {
/*
* Any pending data requests?
*/
- if ((skb_queue_len(&self->tx_list) > 0) &&
+ if ((skb_queue_len(&self->txq) > 0) &&
(self->window > 0) && !self->remote_busy)
{
- irlap_unit_data_indication(self, skb);
+ irlap_data_indication(self, skb, TRUE);
del_timer(&self->wd_timer);
irlap_next_state(self, LAP_XMIT_S);
} else {
- irlap_unit_data_indication(self, skb);
+ irlap_data_indication(self, skb, TRUE);
irlap_wait_min_turn_around(self, &self->qos_tx);
@@ -1785,7 +1836,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
*/
nr_status = irlap_validate_nr_received(self, info->nr);
if (nr_status == NR_EXPECTED) {
- if ((skb_queue_len( &self->tx_list) > 0) &&
+ if ((skb_queue_len( &self->txq) > 0) &&
(self->window > 0)) {
self->remote_busy = FALSE;
@@ -1809,18 +1860,17 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
} else if (nr_status == NR_UNEXPECTED) {
self->remote_busy = FALSE;
irlap_update_nr_received(self, info->nr);
- irlap_resend_rejected_frames( self, RSP_FRAME);
+ irlap_resend_rejected_frames(self, RSP_FRAME);
irlap_start_wd_timer(self, self->wd_timeout);
/* Keep state */
irlap_next_state(self, LAP_NRM_S);
} else {
- IRDA_DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n");
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), invalid nr not implemented!\n");
}
- if (skb)
- dev_kfree_skb(skb);
-
+ dev_kfree_skb(skb);
break;
case RECV_SNRM_CMD:
/* SNRM frame is not allowed to contain an I-field */
@@ -1831,10 +1881,31 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
irlap_reset_indication(self);
} else {
- IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame contained an "
- "I-field!\n");
- dev_kfree_skb(skb);
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), SNRM frame contained an I-field!\n");
+
}
+ dev_kfree_skb(skb);
+ break;
+ case RECV_REJ_CMD:
+ irlap_update_nr_received(self, info->nr);
+ if (self->remote_busy) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rr_frame(self, CMD_FRAME);
+ } else
+ irlap_resend_rejected_frames(self, CMD_FRAME);
+ irlap_start_wd_timer(self, self->wd_timeout);
+ dev_kfree_skb(skb);
+ break;
+ case RECV_SREJ_CMD:
+ irlap_update_nr_received(self, info->nr);
+ if (self->remote_busy) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rr_frame(self, CMD_FRAME);
+ } else
+ irlap_resend_rejected_frame(self, CMD_FRAME);
+ irlap_start_wd_timer(self, self->wd_timeout);
+ dev_kfree_skb(skb);
break;
case WD_TIMER_EXPIRED:
/*
@@ -1842,7 +1913,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
* disconnect time (note 2 in IrLAP p. 82)
*/
IRDA_DEBUG(1, __FUNCTION__ "(), retry_count = %d\n",
- self->retry_count);
+ self->retry_count);
if ((self->retry_count < (self->N2/2)) &&
(self->retry_count != self->N1/2)) {
@@ -1862,7 +1933,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
irlap_disconnect_indication(self, LAP_NO_RESPONSE);
}
break;
- case RECV_DISC_FRAME:
+ case RECV_DISC_CMD:
/* Always switch state before calling upper layers */
irlap_next_state(self, LAP_NDM);
@@ -1873,9 +1944,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
irlap_apply_default_connection_parameters(self);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- if (skb)
- dev_kfree_skb(skb);
-
+ dev_kfree_skb(skb);
break;
case RECV_DISCOVERY_XID_CMD:
irlap_wait_min_turn_around(self, &self->qos_tx);
@@ -1883,6 +1952,8 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
self->ack_required = TRUE;
irlap_start_wd_timer(self, self->wd_timeout);
irlap_next_state(self, LAP_NRM_S);
+
+ dev_kfree_skb(skb);
break;
case RECV_TEST_CMD:
/* Remove test frame header */
@@ -1892,13 +1963,16 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_wd_timer(self, self->wd_timeout);
/* Send response (info will be copied) */
- irlap_send_test_frame(self, info->daddr, skb);
+ irlap_send_test_frame(self, self->caddr, info->daddr, skb);
dev_kfree_skb(skb);
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n",
- event, irlap_event[event]);
- ret = -1;
+ event, irlap_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
+
+ ret = -EINVAL;
break;
}
return ret;
@@ -1910,10 +1984,53 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
*
*
*/
-static int irlap_state_sclose( struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
+static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
+ struct sk_buff *skb, struct irlap_info *info)
{
- IRDA_DEBUG( 0, __FUNCTION__ "(), Not implemented!\n");
+ int ret = 0;
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ ASSERT(self != NULL, return -ENODEV;);
+ ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+
+ switch (event) {
+ case RECV_DISC_CMD:
+ /* Always switch state before calling upper layers */
+ irlap_next_state(self, LAP_NDM);
+
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_ua_response_frame(self, NULL);
+ del_timer(&self->wd_timer);
+ irlap_apply_default_connection_parameters(self);
+
+ irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+ dev_kfree_skb(skb);
+ break;
+ case RECV_DM_RSP:
+ /* Always switch state before calling upper layers */
+ irlap_next_state(self, LAP_NDM);
+
+ del_timer(&self->wd_timer);
+ irlap_apply_default_connection_parameters(self);
+
+ irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+ dev_kfree_skb(skb);
+ break;
+ case WD_TIMER_EXPIRED:
+ irlap_apply_default_connection_parameters(self);
+
+ irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+ break;
+ default:
+ IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n",
+ event, irlap_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
+
+ ret = -EINVAL;
+ break;
+ }
return -1;
}
@@ -1924,31 +2041,34 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event,
{
int ret = 0;
- IRDA_DEBUG(1, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
+ IRDA_DEBUG(1, __FUNCTION__ "(), event=%s\n", irlap_event[event]);
- ASSERT( self != NULL, return -ENODEV;);
- ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+ ASSERT(self != NULL, return -ENODEV;);
+ ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
- switch(event) {
+ switch (event) {
case RESET_RESPONSE:
- irlap_send_ua_response_frame( self, &self->qos_rx);
- irlap_initiate_connection_state( self);
- irlap_start_wd_timer( self, WD_TIMEOUT);
- irlap_flush_all_queues( self);
+ irlap_send_ua_response_frame(self, &self->qos_rx);
+ irlap_initiate_connection_state(self);
+ irlap_start_wd_timer(self, WD_TIMEOUT);
+ irlap_flush_all_queues(self);
- irlap_next_state( self, LAP_NRM_S);
+ irlap_next_state(self, LAP_NRM_S);
break;
case DISCONNECT_REQUEST:
- irlap_wait_min_turn_around( self, &self->qos_tx);
- /* irlap_send_rd_frame(self); */
- irlap_start_wd_timer( self, WD_TIMEOUT);
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rd_frame(self);
+ irlap_start_wd_timer(self, WD_TIMEOUT);
+ irlap_next_state(self, LAP_SCLOSE);
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n",
- event, irlap_event[event]);
- ret = -1;
+ event, irlap_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
+
+ ret = -EINVAL;
break;
}
-
return ret;
}
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 5aa489cc2..830fe6ef7 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -1,16 +1,16 @@
/*********************************************************************
*
* Filename: irlap_frame.c
- * Version: 0.9
+ * Version: 1.0
* Description: Build and transmit IrLAP frames
- * Status: Experimental.
+ * Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Aug 19 10:27:26 1997
- * Modified at: Fri Nov 5 09:45:58 1999
+ * Modified at: Wed Jan 5 08:59:04 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Resrved.
+ * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
+ * 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
@@ -46,8 +46,8 @@
* Function irlap_insert_info (self, skb)
*
* Insert minimum turnaround time and speed information into the skb. We
- * need to do this since it's per packet relevant information.
- *
+ * need to do this since it's per packet relevant information. Safe to
+ * have this function inlined since it's only called from one place
*/
static inline void irlap_insert_info(struct irlap_cb *self,
struct sk_buff *skb)
@@ -66,7 +66,7 @@ static inline void irlap_insert_info(struct irlap_cb *self,
self->mtt_required = 0;
/*
- * Delay equals negotiated BOFs count plus the number of BOFs to
+ * Delay equals negotiated BOFs count, plus the number of BOFs to
* force the negotiated minimum turnaround time
*/
cb->xbofs = self->bofs_count+self->xbofs_delay;
@@ -83,13 +83,6 @@ static inline void irlap_insert_info(struct irlap_cb *self,
*/
void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb)
{
- /* Make sure data is not larger than max data size plus LAP header */
- if (skb->len > 2050) {
- ERROR(__FUNCTION__ "(), size=%d of sk_buff to big!\n",
- (int) skb->len);
- return;
- }
-
/* Some common init stuff */
skb->dev = self->netdev;
skb->h.raw = skb->nh.raw = skb->mac.raw = skb->data;
@@ -120,8 +113,7 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
if (!skb)
return;
- skb_put(skb, 2);
- frame = (struct snrm_frame *) skb->data;
+ frame = (struct snrm_frame *) skb_put(skb, 2);
/* Insert connection address field */
if (qos)
@@ -216,8 +208,7 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
if (!skb)
return;
- skb_put(skb, 10);
- frame = (struct ua_frame *) skb->data;
+ frame = (struct ua_frame *) skb_put(skb, 10);
/* Build UA response */
frame->caddr = self->caddr;
@@ -257,8 +248,7 @@ void irlap_send_dm_frame( struct irlap_cb *self)
if (!skb)
return;
- skb_put( skb, 2);
- frame = skb->data;
+ frame = skb_put( skb, 2);
if (self->state == LAP_NDM)
frame[0] = CBROADCAST;
@@ -286,12 +276,11 @@ void irlap_send_disc_frame(struct irlap_cb *self)
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
- skb = dev_alloc_skb(32);
+ skb = dev_alloc_skb(16);
if (!skb)
return;
- skb_put(skb, 2);
- frame = skb->data;
+ frame = skb_put(skb, 2);
frame[0] = self->caddr | CMD_FRAME;
frame[1] = DISC_CMD | PF_BIT;
@@ -313,7 +302,8 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
__u32 bcast = BROADCAST;
__u8 *info;
- IRDA_DEBUG(4, __FUNCTION__ "(), s=%d, S=%d, command=%d\n", s, S, command);
+ IRDA_DEBUG(4, __FUNCTION__ "(), s=%d, S=%d, command=%d\n", s, S,
+ command);
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
@@ -369,24 +359,23 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
* EXTENSION bit is set in the first byte.
*/
if (!command || (frame->slotnr == 0xff)) {
- int i;
+ int len;
- if (discovery->hints.byte[0] & HINT_EXTENSION)
- info = skb_put(skb, 3+discovery->name_len);
- else
- info = skb_put(skb, 2+discovery->name_len);
-
- i = 0;
- info[i++] = discovery->hints.byte[0];
- if (discovery->hints.byte[0] & HINT_EXTENSION)
- info[i++] = discovery->hints.byte[1];
-
- info[i++] = discovery->charset;
-
- memcpy(&info[i++], discovery->nickname, discovery->name_len);
- }
- ASSERT(self->netdev != NULL, return;);
+ if (discovery->hints.byte[0] & HINT_EXTENSION) {
+ info = skb_put(skb, 2);
+ info[0] = discovery->hints.byte[0];
+ info[1] = discovery->hints.byte[1];
+ } else {
+ info = skb_put(skb, 1);
+ info[0] = discovery->hints.byte[0];
+ }
+ info = skb_put(skb, 1);
+ info[0] = discovery->charset;
+ len = IRDA_MIN(discovery->name_len, skb_tailroom(skb));
+ info = skb_put(skb, len);
+ memcpy(info, discovery->nickname, len);
+ }
irlap_queue_xmit(self, skb);
}
@@ -417,13 +406,15 @@ static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self,
/* Make sure frame is addressed to us */
if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), frame is not addressed to us!\n");
dev_kfree_skb(skb);
- IRDA_DEBUG(0, __FUNCTION__ "(), frame is not addressed to us!\n");
return;
}
if ((discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {
WARNING(__FUNCTION__ "(), kmalloc failed!\n");
+ dev_kfree_skb(skb);
return;
}
memset(discovery, 0, sizeof(discovery_t));
@@ -449,7 +440,7 @@ static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self,
text = (char *) &discovery_info[2];
}
/*
- * Terminate string, should be safe since this is where the
+ * Terminate info string, should be safe since this is where the
* FCS bytes resides.
*/
skb->data[skb->len] = '\0';
@@ -483,7 +474,8 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
/* Make sure frame is addressed to us */
if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
- IRDA_DEBUG(0, __FUNCTION__ "(), frame is not addressed to us!\n");
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), frame is not addressed to us!\n");
dev_kfree_skb(skb);
return;
}
@@ -503,6 +495,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
break;
default:
/* Error!! */
+ dev_kfree_skb(skb);
return;
}
info->s = xid->slotnr;
@@ -519,6 +512,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC);
if (!discovery) {
WARNING(__FUNCTION__ "(), unable to malloc!\n");
+ dev_kfree_skb(skb);
return;
}
@@ -562,7 +556,7 @@ void irlap_send_rr_frame(struct irlap_cb *self, int command)
struct sk_buff *skb;
__u8 *frame;
- skb = dev_alloc_skb(32);
+ skb = dev_alloc_skb(16);
if (!skb)
return;
@@ -577,6 +571,29 @@ void irlap_send_rr_frame(struct irlap_cb *self, int command)
}
/*
+ * Function irlap_send_rd_frame (self)
+ *
+ * Request disconnect. Used by a secondary station to request the
+ * disconnection of the link.
+ */
+void irlap_send_rd_frame(struct irlap_cb *self)
+{
+ struct sk_buff *skb;
+ __u8 *frame;
+
+ skb = dev_alloc_skb(16);
+ if (!skb)
+ return;
+
+ frame = skb_put(skb, 2);
+
+ frame[0] = self->caddr;
+ frame[1] = RD_RSP | PF_BIT;
+
+ irlap_queue_xmit(self, skb);
+}
+
+/*
* Function irlap_recv_rr_frame (skb, info)
*
* Received RR (Receive Ready) frame from peer station, no harm in
@@ -608,8 +625,7 @@ void irlap_send_frmr_frame( struct irlap_cb *self, int command)
if (!skb)
return;
- skb_put( skb, 2);
- frame = skb->data;
+ frame = skb_put( skb, 2);
frame[0] = self->caddr;
frame[0] |= (command) ? CMD_FRAME : 0;
@@ -620,7 +636,7 @@ void irlap_send_frmr_frame( struct irlap_cb *self, int command)
frame[2] = 0;
- IRDA_DEBUG( 4, __FUNCTION__ "(), vr=%d, %ld\n",self->vr, jiffies);
+ IRDA_DEBUG(4, __FUNCTION__ "(), vr=%d, %ld\n",self->vr, jiffies);
irlap_queue_xmit(self, skb);
}
@@ -631,20 +647,57 @@ void irlap_send_frmr_frame( struct irlap_cb *self, int command)
* Received RNR (Receive Not Ready) frame from peer station
*
*/
-static void irlap_recv_rnr_frame( struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info)
+static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb,
+ struct irlap_info *info, int command)
{
- __u8 *frame;
+ info->nr = skb->data[1] >> 5;
- ASSERT( skb != NULL, return;);
- ASSERT( info != NULL, return;);
+ IRDA_DEBUG(4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies);
- frame = skb->data;
- info->nr = frame[1] >> 5;
+ if (command)
+ irlap_do_event(self, RECV_RNR_CMD, skb, info);
+ else
+ irlap_do_event(self, RECV_RNR_RSP, skb, info);
+}
+
+static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb,
+ struct irlap_info *info, int command)
+{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ info->nr = skb->data[1] >> 5;
+
+ /* Check if this is a command or a response frame */
+ if (command)
+ irlap_do_event(self, RECV_REJ_CMD, skb, info);
+ else
+ irlap_do_event(self, RECV_REJ_RSP, skb, info);
+}
+
+static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb,
+ struct irlap_info *info, int command)
+{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ info->nr = skb->data[1] >> 5;
+
+ /* Check if this is a command or a response frame */
+ if (command)
+ irlap_do_event(self, RECV_SREJ_CMD, skb, info);
+ else
+ irlap_do_event(self, RECV_SREJ_RSP, skb, info);
+}
- IRDA_DEBUG( 4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies);
+static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb,
+ struct irlap_info *info, int command)
+{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
- irlap_do_event( self, RECV_RNR_FRAME, skb, info);
+ /* Check if this is a command or a response frame */
+ if (command)
+ irlap_do_event(self, RECV_DISC_CMD, skb, info);
+ else
+ irlap_do_event(self, RECV_RD_RSP, skb, info);
}
/*
@@ -653,8 +706,9 @@ static void irlap_recv_rnr_frame( struct irlap_cb *self, struct sk_buff *skb,
* Received UA (Unnumbered Acknowledgement) frame
*
*/
-static void irlap_recv_ua_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info)
+static inline void irlap_recv_ua_frame(struct irlap_cb *self,
+ struct sk_buff *skb,
+ struct irlap_info *info)
{
irlap_do_event(self, RECV_UA_RSP, skb, info);
}
@@ -701,8 +755,8 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
irlap_send_i_frame( self, tx_skb, CMD_FRAME);
} else {
- IRDA_DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n");
- irlap_send_ui_frame(self, skb, CMD_FRAME);
+ IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
+ irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
self->window -= 1;
}
}
@@ -765,12 +819,12 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
del_timer(&self->poll_timer);
if (self->ack_required) {
- irlap_send_ui_frame(self, skb, CMD_FRAME);
+ irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
irlap_send_rr_frame(self, CMD_FRAME);
self->ack_required = FALSE;
} else {
skb->data[1] |= PF_BIT;
- irlap_send_ui_frame(self, skb, CMD_FRAME);
+ irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
}
self->window = self->window_size;
irlap_start_final_timer(self, self->final_timeout);
@@ -824,12 +878,12 @@ void irlap_send_data_secondary_final(struct irlap_cb *self,
irlap_send_i_frame(self, tx_skb, RSP_FRAME);
} else {
if (self->ack_required) {
- irlap_send_ui_frame(self, skb, RSP_FRAME);
+ irlap_send_ui_frame(self, skb, self->caddr, RSP_FRAME);
irlap_send_rr_frame(self, RSP_FRAME);
self->ack_required = FALSE;
} else {
skb->data[1] |= PF_BIT;
- irlap_send_ui_frame(self, skb, RSP_FRAME);
+ irlap_send_ui_frame(self, skb, self->caddr, RSP_FRAME);
}
self->window = self->window_size;
@@ -874,7 +928,7 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
irlap_send_i_frame(self, tx_skb, RSP_FRAME);
} else {
- irlap_send_ui_frame(self, skb, RSP_FRAME);
+ irlap_send_ui_frame(self, skb, self->caddr, RSP_FRAME);
self->window -= 1;
}
}
@@ -882,13 +936,11 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
/*
* Function irlap_resend_rejected_frames (nr)
*
- * Resend frames which has not been acknowledged. TODO: check that the
- * traversal of the list is atomic, i.e that no-one tries to insert or
- * remove frames from the list while we travers it!
- *
- * FIXME: It is not safe to traverse a this list without locking it!
+ * Resend frames which has not been acknowledged. Should be safe to
+ * traverse the list without locking it since this function will only be
+ * called from interrupt context (BH)
*/
-void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
+void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
{
struct sk_buff *tx_skb;
struct sk_buff *skb;
@@ -900,10 +952,9 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
/* Initialize variables */
skb = tx_skb = NULL;
- /*
- * Resend all unacknowledged frames
- */
count = skb_queue_len(&self->wx_list);
+
+ /* Resend unacknowledged frame(s) */
skb = skb_peek(&self->wx_list);
while (skb != NULL) {
irlap_wait_min_turn_around(self, &self->qos_tx);
@@ -913,13 +964,9 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
*/
/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
tx_skb = skb_copy(skb, GFP_ATOMIC);
- if (tx_skb == NULL) {
- /* Unlink tx_skb from list */
- tx_skb->next = tx_skb->prev = NULL;
- tx_skb->list = NULL;
-
- dev_kfree_skb(skb);
- return;
+ if (!tx_skb) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
+ return;
}
/* Unlink tx_skb from list */
tx_skb->next = tx_skb->prev = NULL;
@@ -948,22 +995,21 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
* If our skb is the last buffer in the list, then
* we are finished, if not, move to the next sk-buffer
*/
- if (skb == skb_peek_tail( &self->wx_list))
+ if (skb == skb_peek_tail(&self->wx_list))
skb = NULL;
else
skb = skb->next;
}
+#if 0 /* Not yet */
/*
* We can now fill the window with additinal data frames
*/
- return; /* Skip this for now, DB */
-
- while (skb_queue_len( &self->tx_list) > 0) {
+ while (skb_queue_len( &self->txq) > 0) {
IRDA_DEBUG(0, __FUNCTION__ "(), sending additional frames!\n");
- if ((skb_queue_len( &self->tx_list) > 0) &&
+ if ((skb_queue_len( &self->txq) > 0) &&
(self->window > 0)) {
- skb = skb_dequeue( &self->tx_list);
+ skb = skb_dequeue( &self->txq);
ASSERT(skb != NULL, return;);
/*
@@ -971,7 +1017,7 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
* bit cleared
*/
if ((self->window > 1) &&
- skb_queue_len(&self->tx_list) > 0)
+ skb_queue_len(&self->txq) > 0)
{
irlap_send_data_primary(self, skb);
} else {
@@ -979,6 +1025,52 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
}
}
}
+#endif
+}
+
+void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
+{
+ struct sk_buff *tx_skb;
+ struct sk_buff *skb;
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
+
+ /* Initialize variables */
+ skb = tx_skb = NULL;
+
+ /* Resend unacknowledged frame(s) */
+ skb = skb_peek(&self->wx_list);
+ if (skb != NULL) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+
+ /* We copy the skb to be retransmitted since we will have to
+ * modify it. Cloning will confuse packet sniffers
+ */
+ /* tx_skb = skb_clone( skb, GFP_ATOMIC); */
+ tx_skb = skb_copy(skb, GFP_ATOMIC);
+ if (!tx_skb) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
+ return;
+ }
+ /* Unlink tx_skb from list */
+ tx_skb->next = tx_skb->prev = NULL;
+ tx_skb->list = NULL;
+
+ /*
+ * make sure the skb->sk accounting of memory usage is sane
+ */
+ if (skb->sk != NULL)
+ skb_set_owner_w(tx_skb, skb->sk);
+
+ /* Clear old Nr field + poll bit */
+ tx_skb->data[1] &= 0x0f;
+
+ /* Set poll/final bit */
+ tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
+
+ irlap_send_i_frame(self, tx_skb, command);
+ }
}
/*
@@ -988,21 +1080,16 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
*
*/
void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
- int command)
+ __u8 caddr, int command)
{
- __u8 *frame;
-
IRDA_DEBUG(4, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
ASSERT(skb != NULL, return;);
- frame = skb->data;
-
/* Insert connection address */
- frame[0] = self->caddr;
- frame[0] |= (command) ? CMD_FRAME : 0;
+ skb->data[0] = caddr | ((command) ? CMD_FRAME : 0);
irlap_queue_xmit(self, skb);
}
@@ -1055,13 +1142,9 @@ static inline void irlap_recv_i_frame(struct irlap_cb *self,
static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
struct irlap_info *info)
{
- __u8 *frame;
-
IRDA_DEBUG( 4, __FUNCTION__ "()\n");
- frame = skb->data;
-
- info->pf = frame[1] & PF_BIT; /* Final bit */
+ info->pf = skb->data[1] & PF_BIT; /* Final bit */
irlap_do_event(self, RECV_UI_FRAME, skb, info);
}
@@ -1088,7 +1171,7 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb,
frame = skb->data;
info->nr = frame[2] >> 5; /* Next to receive */
- info->pf = frame[2] & PF_BIT; /* Final bit */
+ info->pf = frame[2] & PF_BIT; /* Final bit */
info->ns = (frame[2] >> 1) & 0x07; /* Next to send */
w = frame[3] & 0x01;
@@ -1122,7 +1205,7 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb,
* Send a test frame response
*
*/
-void irlap_send_test_frame(struct irlap_cb *self, __u32 daddr,
+void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr,
struct sk_buff *cmd)
{
struct sk_buff *skb;
@@ -1133,22 +1216,20 @@ void irlap_send_test_frame(struct irlap_cb *self, __u32 daddr,
if (!skb)
return;
- skb_put(skb, sizeof(struct test_frame));
+ /* Broadcast frames must include saddr and daddr fields */
+ if (caddr == CBROADCAST) {
+ frame = (struct test_frame *)
+ skb_put(skb, sizeof(struct test_frame));
- frame = (struct test_frame *) skb->data;
-
- /* Build header */
- if (self->state == LAP_NDM)
- frame->caddr = CBROADCAST; /* Send response */
- else
- frame->caddr = self->caddr;
+ /* Insert the swapped addresses */
+ frame->saddr = cpu_to_le32(self->saddr);
+ frame->daddr = cpu_to_le32(daddr);
+ } else
+ frame = (struct test_frame *) skb_put(skb, LAP_MAX_HEADER);
+ frame->caddr = caddr;
frame->control = TEST_RSP;
- /* Insert the swapped addresses */
- frame->saddr = cpu_to_le32(self->saddr);
- frame->daddr = cpu_to_le32(daddr);
-
/* Copy info */
info = skb_put(skb, cmd->len);
memcpy(info, cmd->data, cmd->len);
@@ -1164,28 +1245,34 @@ void irlap_send_test_frame(struct irlap_cb *self, __u32 daddr,
* Receive a test frame
*
*/
-void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info, int command)
+static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
+ struct irlap_info *info, int command)
{
struct test_frame *frame;
IRDA_DEBUG(2, __FUNCTION__ "()\n");
- if (skb->len < sizeof(struct test_frame)) {
- IRDA_DEBUG(0, __FUNCTION__ "() test frame to short!\n");
- return;
- }
-
frame = (struct test_frame *) skb->data;
+
+ /* Broadcast frames must carry saddr and daddr fields */
+ if (info->caddr == CBROADCAST) {
+ if (skb->len < sizeof(struct test_frame)) {
+ IRDA_DEBUG(0, __FUNCTION__
+ "() test frame to short!\n");
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ /* Read and swap addresses */
+ info->daddr = le32_to_cpu(frame->saddr);
+ info->saddr = le32_to_cpu(frame->daddr);
- /* Read and swap addresses */
- info->daddr = le32_to_cpu(frame->saddr);
- info->saddr = le32_to_cpu(frame->daddr);
-
- /* Make sure frame is addressed to us */
- if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
- dev_kfree_skb(skb);
- return;
+ /* Make sure frame is addressed to us */
+ if ((info->saddr != self->saddr) &&
+ (info->saddr != BROADCAST)) {
+ dev_kfree_skb(skb);
+ return;
+ }
}
if (command)
@@ -1261,18 +1348,19 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
irlap_recv_rr_frame(self, skb, &info, command);
break;
case RNR:
- irlap_recv_rnr_frame(self, skb, &info);
+ irlap_recv_rnr_frame(self, skb, &info, command);
break;
case REJ:
- IRDA_DEBUG( 0, "*** REJ frame received! ***\n");
+ irlap_recv_rej_frame(self, skb, &info, command);
break;
case SREJ:
- IRDA_DEBUG( 0, "*** SREJ frame received! ***\n");
+ irlap_recv_srej_frame(self, skb, &info, command);
break;
default:
WARNING(__FUNCTION__
"() Unknown S-frame %02x received!\n",
info.control);
+ dev_kfree_skb(skb);
break;
}
return 0;
@@ -1291,11 +1379,10 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
irlap_recv_snrm_cmd(self, skb, &info);
break;
case DM_RSP:
- IRDA_DEBUG( 0, "DM rsp frame received!\n");
- irlap_next_state(self, LAP_NDM);
+ irlap_do_event(self, RECV_DM_RSP, skb, &info);
break;
- case DISC_CMD:
- irlap_do_event(self, RECV_DISC_FRAME, skb, &info);
+ case DISC_CMD: /* And RD_RSP since they have the same value */
+ irlap_recv_disc_frame(self, skb, &info, command);
break;
case TEST_CMD:
irlap_recv_test_frame(self, skb, &info, command);
@@ -1312,7 +1399,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
default:
WARNING(__FUNCTION__ "(), Unknown frame %02x received!\n",
info.control);
- dev_kfree_skb( skb);
+ dev_kfree_skb(skb);
break;
}
return 0;
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index c83d62f44..5be0298a9 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -1,15 +1,15 @@
/*********************************************************************
*
* Filename: irlmp.c
- * Version: 0.9
+ * Version: 1.0
* Description: IrDA Link Management Protocol (LMP) layer
* Status: Stable.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 17 20:54:32 1997
- * Modified at: Sat Oct 9 17:00:49 1999
+ * Modified at: Wed Jan 5 11:26:03 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
+ * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -69,20 +69,19 @@ int irlmp_proc_read(char *buf, char **start, off_t offst, int len);
/*
* Function irlmp_init (void)
*
- * Create (allocate) the main IrLMP structure and the pointer array
- * which will contain pointers to each instance of a LSAP.
+ * Create (allocate) the main IrLMP structure
+ *
*/
int __init irlmp_init(void)
{
/* Initialize the irlmp structure. */
- if ( irlmp == NULL) {
- irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
- if ( irlmp == NULL)
- return -ENOMEM;
- }
- memset( irlmp, 0, sizeof(struct irlmp_cb));
+ irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
+ if (irlmp == NULL)
+ return -ENOMEM;
+ memset(irlmp, 0, sizeof(struct irlmp_cb));
irlmp->magic = LMP_MAGIC;
+ spin_lock_init(&irlmp->lock);
irlmp->clients = hashbin_new(HB_GLOBAL);
irlmp->services = hashbin_new(HB_GLOBAL);
@@ -90,7 +89,7 @@ int __init irlmp_init(void)
irlmp->unconnected_lsaps = hashbin_new(HB_GLOBAL);
irlmp->cachelog = hashbin_new(HB_GLOBAL);
- irlmp->free_lsap_sel = 0x10; /* Servers use 0x00-0x0f */
+ irlmp->free_lsap_sel = 0x10; /* Reserved 0x00-0x0f */
#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
irlmp->cache.valid = FALSE;
#endif
@@ -134,7 +133,7 @@ void irlmp_cleanup(void)
* Register with IrLMP and create a local LSAP,
* returns handle to LSAP.
*/
-struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify)
+struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid)
{
struct lsap_cb *self;
@@ -142,40 +141,33 @@ struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify)
ASSERT(irlmp != NULL, return NULL;);
ASSERT(irlmp->magic == LMP_MAGIC, return NULL;);
- /*
- * Does the client care which Source LSAP selector it gets?
- */
+ /* Does the client care which Source LSAP selector it gets? */
if (slsap_sel == LSAP_ANY) {
- /*
- * Find unused LSAP
- */
slsap_sel = irlmp_find_free_slsap();
- if ( slsap_sel == 0)
- return NULL;
- } else {
- /*
- * Client wants specific LSAP, so check if it's already
- * in use
- */
- if (irlmp_slsap_inuse(slsap_sel)) {
+ if (!slsap_sel)
return NULL;
- }
- }
+ } else if (irlmp_slsap_inuse(slsap_sel))
+ return NULL;
- /*
- * Allocate new instance of a LSAP connection
- */
+ /* Allocate new instance of a LSAP connection */
self = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
if (self == NULL) {
- printk( KERN_ERR "IrLMP: Can't allocate memory for "
- "LSAP control block!\n");
+ ERROR(__FUNCTION__ "(), can't allocate memory");
return NULL;
}
memset(self, 0, sizeof(struct lsap_cb));
self->magic = LMP_LSAP_MAGIC;
self->slsap_sel = slsap_sel;
- self->dlsap_sel = LSAP_ANY;
+
+ /* Fix connectionless LSAP's */
+ if (slsap_sel == LSAP_CONNLESS) {
+#ifdef CONFIG_IRDA_ULTRA
+ self->dlsap_sel = LSAP_CONNLESS;
+ self->pid = pid;
+#endif /* CONFIG_IRDA_ULTRA */
+ } else
+ self->dlsap_sel = LSAP_ANY;
self->connected = FALSE;
init_timer(&self->watchdog_timer);
@@ -185,9 +177,7 @@ struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify)
irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
- /*
- * Insert into queue of unconnected LSAPs
- */
+ /* Insert into queue of unconnected LSAPs */
hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) self, (int) self,
NULL);
@@ -209,9 +199,12 @@ static void __irlmp_close_lsap(struct lsap_cb *self)
/*
* Set some of the variables to preset values
*/
- self->magic = ~LMP_LSAP_MAGIC;
+ self->magic = 0;
del_timer(&self->watchdog_timer); /* Important! */
+ if (self->conn_skb)
+ dev_kfree_skb(self->conn_skb);
+
#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
ASSERT(irlmp != NULL, return;);
irlmp->cache.valid = FALSE;
@@ -249,7 +242,7 @@ void irlmp_close_lsap(struct lsap_cb *self)
}
if (!lsap) {
IRDA_DEBUG(0, __FUNCTION__
- "(), Looks like somebody has removed me already!\n");
+ "(), Looks like somebody has removed me already!\n");
return;
}
__irlmp_close_lsap(self);
@@ -373,7 +366,6 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
skb_push(skb, LMP_CONTROL_HEADER);
self->dlsap_sel = dlsap_sel;
- self->tmp_skb = skb;
/*
* Find the link to where we should try to connect since there may
@@ -384,9 +376,18 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
* device with the given daddr
*/
if (!saddr) {
- discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
- if (discovery)
+ if (daddr != DEV_ADDR_ANY)
+ discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
+ else {
+ IRDA_DEBUG(2, __FUNCTION__ "(), no daddr\n");
+ discovery = (discovery_t *)
+ hashbin_get_first(irlmp->cachelog);
+ }
+
+ if (discovery) {
saddr = discovery->saddr;
+ daddr = discovery->daddr;
+ }
}
lap = hashbin_find(irlmp->links, saddr, NULL);
if (lap == NULL) {
@@ -447,22 +448,17 @@ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
ASSERT(self->lap != NULL, return;);
IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
- self->slsap_sel, self->dlsap_sel);
-
+ self->slsap_sel, self->dlsap_sel);
+
self->qos = *self->lap->qos;
max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
- IRDA_DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
-
lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
-
max_header_size = LMP_HEADER + lap_header_size;
- IRDA_DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n", max_header_size);
-
/* Hide LMP_CONTROL_HEADER header from layer above */
skb_pull(skb, LMP_CONTROL_HEADER);
-
+
if (self->notify.connect_indication)
self->notify.connect_indication(self->notify.instance, self,
&self->qos, max_seg_size,
@@ -484,9 +480,9 @@ int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata)
self->connected = TRUE;
IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
- self->slsap_sel, self->dlsap_sel);
+ self->slsap_sel, self->dlsap_sel);
- /* Make room for MUX control header ( 3 bytes) */
+ /* Make room for MUX control header (3 bytes) */
ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
skb_push(userdata, LMP_CONTROL_HEADER);
@@ -519,7 +515,8 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
max_header_size = LMP_HEADER + lap_header_size;
- IRDA_DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n", max_header_size);
+ IRDA_DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n",
+ max_header_size);
/* Hide LMP_CONTROL_HEADER header from layer above */
skb_pull(skb, LMP_CONTROL_HEADER);
@@ -637,13 +634,12 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
struct lsap_cb *lsap;
IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);
-
ASSERT(self != NULL, return;);
ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
ASSERT(self->connected == TRUE, return;);
IRDA_DEBUG(3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
- self->slsap_sel, self->dlsap_sel);
+ self->slsap_sel, self->dlsap_sel);
self->connected = FALSE;
self->dlsap_sel = LSAP_ANY;
@@ -670,9 +666,12 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
/*
* Inform service user
*/
- if (self->notify.disconnect_indication) {
+ if (self->notify.disconnect_indication)
self->notify.disconnect_indication(self->notify.instance,
self, reason, userdata);
+ else {
+ IRDA_DEBUG(0, __FUNCTION__ "(), no handler\n");
+ dev_kfree_skb(userdata);
}
}
@@ -687,9 +686,7 @@ void irlmp_do_discovery(int nslots)
struct lap_cb *lap;
/* Make sure the value is sane */
- if ((nslots != 1) && (nslots != 6) &&
- (nslots != 8) && (nslots != 16))
- {
+ if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
WARNING(__FUNCTION__
"(), invalid value for number of slots!\n");
nslots = sysctl_discovery_slots = 8;
@@ -918,13 +915,15 @@ int irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb)
* Got data from LAP layer so pass it up to upper layer
*
*/
-inline void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb)
+void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb)
{
/* Hide LMP header from layer above */
skb_pull(skb, LMP_HEADER);
if (self->notify.data_indication)
self->notify.data_indication(self->notify.instance, self, skb);
+ else
+ dev_kfree_skb(skb);
}
/*
@@ -933,17 +932,17 @@ inline void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb)
*
*
*/
-inline void irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb)
+int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb)
{
IRDA_DEBUG(4, __FUNCTION__ "()\n");
- ASSERT(skb != NULL, return;);
+ ASSERT(skb != NULL, return -1;);
/* Make room for MUX header */
- ASSERT(skb_headroom(skb) >= LMP_HEADER, return;);
+ ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
skb_push(skb, LMP_HEADER);
- irlmp_do_lsap_event(self, LM_UDATA_REQUEST, skb);
+ return irlmp_do_lsap_event(self, LM_UDATA_REQUEST, skb);
}
/*
@@ -964,30 +963,83 @@ void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
skb_pull(skb, LMP_HEADER);
if (self->notify.udata_indication)
- self->notify.udata_indication(self->notify.instance, self, skb);
+ self->notify.udata_indication(self->notify.instance, self,
+ skb);
+ else
+ dev_kfree_skb(skb);
}
/*
- * Function irlmp_connection_less_data_request (skb)
+ * Function irlmp_connless_data_request (self, skb)
*
- * Send out of connection UI frames
+ *
*
*/
-void irlmp_connectionless_data_request( struct sk_buff *skb)
+#ifdef CONFIG_IRDA_ULTRA
+int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG( 1, __FUNCTION__ "(), Sorry not implemented\n");
+ struct sk_buff *clone_skb;
+ struct lap_cb *lap;
+
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+ ASSERT(skb != NULL, return -1;);
+
+ /* Make room for MUX and PID header */
+ ASSERT(skb_headroom(skb) >= LMP_HEADER+LMP_PID_HEADER, return -1;);
+
+ /* Insert protocol identifier */
+ skb_push(skb, LMP_PID_HEADER);
+ skb->data[0] = self->pid;
+
+ /* Connectionless sockets must use 0x70 */
+ skb_push(skb, LMP_HEADER);
+ skb->data[0] = skb->data[1] = LSAP_CONNLESS;
+
+ /* Try to send Connectionless packets out on all links */
+ lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
+ while (lap != NULL) {
+ ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
+
+ clone_skb = skb_clone(skb, GFP_ATOMIC);
+ if (!clone_skb)
+ return -ENOMEM;
+
+ irlap_unitdata_request(lap->irlap, clone_skb);
+
+ lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
+ }
+ dev_kfree_skb(skb);
+
+ return 0;
}
+#endif /* CONFIG_IRDA_ULTRA */
/*
- * Function irlmp_connection_less_data_indication (skb)
+ * Function irlmp_connless_data_indication (self, skb)
*
- *
+ * Receive unreliable data outside any connection. Mostly used by Ultra
*
*/
-void irlmp_connectionless_data_indication(struct sk_buff *skb)
+#ifdef CONFIG_IRDA_ULTRA
+void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
{
- IRDA_DEBUG( 1, __FUNCTION__ "()\n");
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+ ASSERT(skb != NULL, return;);
+
+ /* Hide LMP and PID header from layer above */
+ skb_pull(skb, LMP_HEADER+LMP_PID_HEADER);
+
+ if (self->notify.udata_indication)
+ self->notify.udata_indication(self->notify.instance, self,
+ skb);
+ else
+ dev_kfree_skb(skb);
}
+#endif /* CONFIG_IRDA_ULTRA */
void irlmp_status_request(void)
{
@@ -1310,8 +1362,14 @@ int irlmp_slsap_inuse(__u8 slsap_sel)
IRDA_DEBUG(4, __FUNCTION__ "()\n");
+#ifdef CONFIG_IRDA_ULTRA
+ /* Accept all bindings to the connectionless LSAP */
+ if (slsap_sel == LSAP_CONNLESS)
+ return FALSE;
+#endif /* CONFIG_IRDA_ULTRA */
+
/* Valid values are between 0 and 127 */
- if (slsap_sel > 127)
+ if (slsap_sel > LSAP_MAX)
return TRUE;
/*
@@ -1359,8 +1417,8 @@ __u8 irlmp_find_free_slsap(void)
while (irlmp_slsap_inuse(irlmp->free_lsap_sel)) {
irlmp->free_lsap_sel++;
- /* Check if we need to wraparound */
- if (irlmp->free_lsap_sel > 127) {
+ /* Check if we need to wraparound (0x70-0x7f are reserved) */
+ if (irlmp->free_lsap_sel > LSAP_MAX) {
irlmp->free_lsap_sel = 10;
/* Make sure we terminate the loop */
@@ -1431,7 +1489,7 @@ __u32 irlmp_get_daddr(struct lsap_cb *self)
#ifdef CONFIG_PROC_FS
/*
- * Function irlmp_proc_read (buf, start, offset, len)
+ * Function irlmp_proc_read (buf, start, offset, len, unused)
*
* Give some info to the /proc file system
*
@@ -1474,6 +1532,7 @@ int irlmp_proc_read(char *buf, char **start, off_t offset, int len)
len += sprintf(buf+len, "saddr: %#08x, daddr: %#08x, ",
lap->saddr, lap->daddr);
+ len += sprintf(buf+len, "refcount: %d", lap->refcount);
len += sprintf(buf+len, "\n");
len += sprintf(buf+len, "\nConnected LSAPs:\n");
@@ -1495,7 +1554,6 @@ int irlmp_proc_read(char *buf, char **start, off_t offset, int len)
lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
}
-
restore_flags(flags);
return len;
diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c
index 122affe25..ace20d70e 100644
--- a/net/irda/irlmp_event.c
+++ b/net/irda/irlmp_event.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Tue Oct 5 13:47:53 1999
+ * Modified at: Tue Dec 14 23:04:16 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
@@ -23,6 +23,7 @@
*
********************************************************************/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <net/irda/irda.h>
@@ -121,7 +122,7 @@ int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event,
ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
IRDA_DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
- irlmp_event[ event], irlmp_state[ self->lsap_state]);
+ irlmp_event[event], irlmp_state[ self->lsap_state]);
return (*lsap_state[self->lsap_state]) (self, event, skb);
}
@@ -139,8 +140,8 @@ void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event,
ASSERT(self->magic == LMP_LAP_MAGIC, return;);
IRDA_DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
- irlmp_event[event],
- irlmp_state[self->lap_state]);
+ irlmp_event[event],
+ irlmp_state[self->lap_state]);
(*lap_state[self->lap_state]) (self, event, skb);
}
@@ -221,19 +222,23 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
case LM_LAP_CONNECT_REQUEST:
IRDA_DEBUG(4, __FUNCTION__ "() LS_CONNECT_REQUEST\n");
+ irlmp_next_lap_state(self, LAP_U_CONNECT);
+ self->refcount++;
+
/* FIXME: need to set users requested QoS */
irlap_connect_request(self->irlap, self->daddr, NULL, 0);
-
- irlmp_next_lap_state(self, LAP_U_CONNECT);
break;
case LM_LAP_DISCONNECT_INDICATION:
IRDA_DEBUG(4, __FUNCTION__
- "(), Error LM_LAP_DISCONNECT_INDICATION\n");
+ "(), Error LM_LAP_DISCONNECT_INDICATION\n");
- irlmp_next_lap_state( self, LAP_STANDBY);
+ irlmp_next_lap_state(self, LAP_STANDBY);
break;
default:
- IRDA_DEBUG(4, __FUNCTION__ "(), Unknown event\n");
+ IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+ irlmp_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
}
@@ -245,8 +250,8 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
* since the IrLAP connection does not exist, we must first start an
* IrLAP connection. We are now waiting response from IrLAP.
* */
-static void irlmp_state_u_connect( struct lap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
+static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
+ struct sk_buff *skb)
{
struct lsap_cb *lsap;
struct lsap_cb *lsap_current;
@@ -254,23 +259,41 @@ static void irlmp_state_u_connect( struct lap_cb *self, IRLMP_EVENT event,
IRDA_DEBUG(2, __FUNCTION__ "(), event=%s\n", irlmp_event[event]);
switch (event) {
+ case LM_LAP_CONNECT_INDICATION:
+ /* It's important to switch state first, to avoid IrLMP to
+ * think that the link is free since IrLMP may then start
+ * discovery before the connection is properly set up. DB.
+ */
+ irlmp_next_lap_state(self, LAP_ACTIVE);
+
+ /* Just accept connection TODO, this should be fixed */
+ irlap_connect_response(self->irlap, skb);
+
+ lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+ while (lsap != NULL) {
+ irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
+ lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
+ }
+ break;
+ case LM_LAP_CONNECT_REQUEST:
+ /* Already trying to connect */
+ self->refcount++;
+ break;
case LM_LAP_CONNECT_CONFIRM:
/* For all lsap_ce E Associated do LS_Connect_confirm */
irlmp_next_lap_state(self, LAP_ACTIVE);
lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
while (lsap != NULL) {
- irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, skb);
+ irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
- }
+ }
break;
case LM_LAP_DISCONNECT_INDICATION:
- IRDA_DEBUG(2, __FUNCTION__ "(), IRLAP_DISCONNECT_INDICATION\n");
-
irlmp_next_lap_state(self, LAP_STANDBY);
+ self->refcount = 0;
/* Send disconnect event to all LSAPs using this link */
-
lsap = (struct lsap_cb *) hashbin_get_first( self->lsaps);
while (lsap != NULL ) {
ASSERT(lsap->magic == LMP_LSAP_MAGIC, return;);
@@ -278,7 +301,7 @@ static void irlmp_state_u_connect( struct lap_cb *self, IRLMP_EVENT event,
lsap_current = lsap;
/* Be sure to stay one item ahead */
- lsap = (struct lsap_cb *) hashbin_get_next( self->lsaps);
+ lsap = (struct lsap_cb *) hashbin_get_next(self->lsaps);
irlmp_do_lsap_event(lsap_current,
LM_LAP_DISCONNECT_INDICATION,
NULL);
@@ -287,13 +310,15 @@ static void irlmp_state_u_connect( struct lap_cb *self, IRLMP_EVENT event,
case LM_LAP_DISCONNECT_REQUEST:
IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
- irlmp_next_lap_state(self, LAP_STANDBY);
-
- /* FIXME */
-/* irlap_disconnect_request( self->irlap); */
+ self->refcount--;
+ if (self->refcount == 0)
+ irlmp_next_lap_state(self, LAP_STANDBY);
break;
default:
- IRDA_DEBUG(4, __FUNCTION__ "(), Unknown event\n");
+ IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+ irlmp_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
}
@@ -310,11 +335,12 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
struct lsap_cb *lsap;
struct lsap_cb *lsap_current;
- IRDA_DEBUG( 4, __FUNCTION__ "()\n");
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
- switch( event) {
+ switch (event) {
case LM_LAP_CONNECT_REQUEST:
- IRDA_DEBUG( 4, __FUNCTION__ "(), LS_CONNECT_REQUEST\n");
+ IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_REQUEST\n");
+ self->refcount++;
/*
* LAP connection allready active, just bounce back! Since we
@@ -324,7 +350,7 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
*/
lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
while (lsap != NULL) {
- irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, skb);
+ irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
}
@@ -336,11 +362,13 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
/* Be sure to stay one item ahead */
lsap = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps);
irlmp_do_lsap_event(lsap_current,
- LM_LAP_CONNECT_CONFIRM, skb);
+ LM_LAP_CONNECT_CONFIRM, NULL);
}
/* Keep state */
break;
case LM_LAP_DISCONNECT_REQUEST:
+ self->refcount--;
+
/*
* Need to find out if we should close IrLAP or not. If there
* is only one LSAP connection left on this link, that LSAP
@@ -363,6 +391,7 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
break;
case LM_LAP_DISCONNECT_INDICATION:
irlmp_next_lap_state(self, LAP_STANDBY);
+ self->refcount = 0;
/*
* Inform all connected LSAP's using this link
@@ -381,7 +410,9 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
}
break;
default:
- IRDA_DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
+ IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
}
@@ -409,8 +440,21 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
switch (event) {
+#ifdef CONFIG_IRDA_ULTRA
+ case LM_UDATA_INDICATION:
+ irlmp_connless_data_indication(self, skb);
+ break;
+#endif /* CONFIG_IRDA_ULTRA */
case LM_CONNECT_REQUEST:
IRDA_DEBUG(4, __FUNCTION__ "(), LM_CONNECT_REQUEST\n");
+
+ if (self->conn_skb) {
+ WARNING(__FUNCTION__
+ "(), busy with another request!\n");
+ return -EBUSY;
+ }
+ self->conn_skb = skb;
+
irlmp_next_lsap_state(self, LSAP_SETUP_PEND);
irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
@@ -421,10 +465,20 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
case LM_CONNECT_INDICATION:
irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
- irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, skb);
+ if (self->conn_skb) {
+ WARNING(__FUNCTION__
+ "(), busy with another request!\n");
+ return -EBUSY;
+ }
+ self->conn_skb = skb;
+
+ irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
break;
default:
- IRDA_DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
+ IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
+ irlmp_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
return ret;
@@ -471,7 +525,10 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
break;
default:
- IRDA_DEBUG( 4, __FUNCTION__ "(), Unknown event\n");
+ IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+ irlmp_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
return ret;
@@ -499,21 +556,28 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
break;
case LM_CONNECT_RESPONSE:
IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, "
- "no indication issued yet\n");
+ "no indication issued yet\n");
/* Keep state */
break;
case LM_DISCONNECT_REQUEST:
IRDA_DEBUG(0, __FUNCTION__ "(), LM_DISCONNECT_REQUEST, "
- "not yet bound to IrLAP connection\n");
+ "not yet bound to IrLAP connection\n");
/* Keep state */
break;
case LM_LAP_CONNECT_CONFIRM:
IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_CONFIRM\n");
irlmp_next_lsap_state(self, LSAP_CONNECT);
+
+ skb = self->conn_skb;
+ self->conn_skb = NULL;
+
irlmp_connect_indication(self, skb);
break;
default:
- IRDA_DEBUG( 4, __FUNCTION__ "Unknown event %d\n", event);
+ IRDA_DEBUG(0, __FUNCTION__ "Unknown event %s\n",
+ irlmp_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
return ret;
@@ -541,11 +605,9 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
case LM_DATA_REQUEST: /* Optimize for the common case */
irlmp_send_data_pdu(self->lap, self->dlsap_sel,
self->slsap_sel, FALSE, skb);
- /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
break;
case LM_DATA_INDICATION: /* Optimize for the common case */
irlmp_data_indication(self, skb);
- /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
break;
case LM_UDATA_REQUEST:
ASSERT(skb != NULL, return -1;);
@@ -554,21 +616,20 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
break;
case LM_UDATA_INDICATION:
irlmp_udata_indication(self, skb);
- /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
break;
case LM_CONNECT_REQUEST:
IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_REQUEST, "
- "error, LSAP already connected\n");
+ "error, LSAP already connected\n");
/* Keep state */
break;
case LM_CONNECT_RESPONSE:
IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, "
- "error, LSAP allready connected\n");
+ "error, LSAP allready connected\n");
/* Keep state */
break;
case LM_DISCONNECT_REQUEST:
- irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
- self->slsap_sel, DISCONNECT, skb);
+ irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, self->slsap_sel,
+ DISCONNECT, skb);
irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
/* Try to close the LAP connection if its still there */
@@ -603,7 +664,10 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
irlmp_disconnect_indication(self, reason, skb);
break;
default:
- IRDA_DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
+ IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+ irlmp_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
return ret;
@@ -673,7 +737,10 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
break;
default:
- IRDA_DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
+ IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+ irlmp_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
return ret;
@@ -700,9 +767,14 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
switch (event) {
case LM_LAP_CONNECT_CONFIRM:
+ ASSERT(self->conn_skb != NULL, return -1;);
+
+ skb = self->conn_skb;
+ self->conn_skb = NULL;
+
irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
- self->slsap_sel, CONNECT_CMD,
- self->tmp_skb);
+ self->slsap_sel, CONNECT_CMD, skb);
+
irlmp_next_lsap_state(self, LSAP_SETUP);
break;
case LM_WATCHDOG_TIMEOUT:
@@ -710,21 +782,24 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
ASSERT(self->lap != NULL, return -1;);
irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
- irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+ irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
- irlmp_disconnect_indication( self, LM_CONNECT_FAILURE, NULL);
+ irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
break;
case LM_LAP_DISCONNECT_INDICATION: /* LS_Disconnect.indication */
del_timer( &self->watchdog_timer);
- irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+ irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
- reason = irlmp_convert_lap_reason( self->lap->reason);
+ reason = irlmp_convert_lap_reason(self->lap->reason);
irlmp_disconnect_indication(self, reason, NULL);
break;
default:
- IRDA_DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
+ IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+ irlmp_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
break;
}
return ret;
diff --git a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c
index 7a71005bf..c9bca1ea2 100644
--- a/net/irda/irlmp_frame.c
+++ b/net/irda/irlmp_frame.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Aug 19 02:09:59 1997
- * Modified at: Thu Jul 8 12:12:02 1999
+ * Modified at: Mon Dec 13 13:41:12 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
@@ -45,9 +45,9 @@ inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
if (expedited) {
IRDA_DEBUG(4, __FUNCTION__ "(), sending expedited data\n");
- irlap_data_request(self->irlap, skb, FALSE);
- } else
irlap_data_request(self->irlap, skb, TRUE);
+ } else
+ irlap_data_request(self->irlap, skb, FALSE);
}
/*
@@ -60,8 +60,8 @@ void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
{
__u8 *frame;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
ASSERT(self != NULL, return;);
ASSERT(self->magic == LMP_LAP_MAGIC, return;);
ASSERT(skb != NULL, return;);
@@ -78,8 +78,7 @@ void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
else
frame[3] = 0x00; /* rsvd */
- ASSERT(self->irlap != NULL, return;);
- irlap_data_request(self->irlap, skb, TRUE);
+ irlap_data_request(self->irlap, skb, FALSE);
}
/*
@@ -88,14 +87,16 @@ void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
* Used by IrLAP to pass received data frames to IrLMP layer
*
*/
-void irlmp_link_data_indication(struct lap_cb *self, int reliable,
- struct sk_buff *skb)
+void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
+ int unreliable)
{
struct lsap_cb *lsap;
__u8 slsap_sel; /* Source (this) LSAP address */
__u8 dlsap_sel; /* Destination LSAP address */
__u8 *fp;
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
ASSERT(self != NULL, return;);
ASSERT(self->magic == LMP_LAP_MAGIC, return;);
ASSERT(skb->len > 2, return;);
@@ -107,15 +108,16 @@ void irlmp_link_data_indication(struct lap_cb *self, int reliable,
* destination LSAP of received frame is source LSAP in our view
*/
slsap_sel = fp[0] & LSAP_MASK;
- dlsap_sel = fp[1];
+ dlsap_sel = fp[1];
/*
* Check if this is an incoming connection, since we must deal with
* it in a different way than other established connections.
*/
if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
- IRDA_DEBUG(3,"Incoming connection, source LSAP=%d, dest LSAP=%d\n",
- slsap_sel, dlsap_sel);
+ IRDA_DEBUG(3, __FUNCTION__ "(), incoming connection, "
+ "source LSAP=%d, dest LSAP=%d\n",
+ slsap_sel, dlsap_sel);
/* Try to find LSAP among the unconnected LSAPs */
lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD,
@@ -148,7 +150,7 @@ void irlmp_link_data_indication(struct lap_cb *self, int reliable,
* Check if we received a control frame?
*/
if (fp[0] & CONTROL_BIT) {
- switch(fp[2]) {
+ switch (fp[2]) {
case CONNECT_CMD:
lsap->lap = self;
irlmp_do_lsap_event(lsap, LM_CONNECT_INDICATION, skb);
@@ -157,35 +159,107 @@ void irlmp_link_data_indication(struct lap_cb *self, int reliable,
irlmp_do_lsap_event(lsap, LM_CONNECT_CONFIRM, skb);
break;
case DISCONNECT:
- IRDA_DEBUG( 4, __FUNCTION__ "(), Disconnect indication!\n");
+ IRDA_DEBUG(4, __FUNCTION__
+ "(), Disconnect indication!\n");
irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION,
skb);
break;
case ACCESSMODE_CMD:
- IRDA_DEBUG( 0, "Access mode cmd not implemented!\n");
+ IRDA_DEBUG(0, "Access mode cmd not implemented!\n");
+ dev_kfree_skb(skb);
break;
case ACCESSMODE_CNF:
- IRDA_DEBUG( 0, "Access mode cnf not implemented!\n");
+ IRDA_DEBUG(0, "Access mode cnf not implemented!\n");
+ dev_kfree_skb(skb);
break;
default:
- IRDA_DEBUG( 0, __FUNCTION__
- "(), Unknown control frame %02x\n", fp[2]);
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), Unknown control frame %02x\n", fp[2]);
+ dev_kfree_skb(skb);
break;
}
- } else if (reliable == LAP_RELIABLE) {
+ } else if (unreliable) {
/* Optimize and bypass the state machine if possible */
if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
- irlmp_data_indication(lsap, skb);
+ irlmp_udata_indication(lsap, skb);
else
- irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb);
- } else if (reliable == LAP_UNRELIABLE) {
+ irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
+ } else {
/* Optimize and bypass the state machine if possible */
if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
irlmp_data_indication(lsap, skb);
else
- irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
+ irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb);
+ }
+}
+
+/*
+ * Function irlmp_link_unitdata_indication (self, skb)
+ *
+ *
+ *
+ */
+#ifdef CONFIG_IRDA_ULTRA
+void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
+{
+ struct lsap_cb *lsap;
+ __u8 slsap_sel; /* Source (this) LSAP address */
+ __u8 dlsap_sel; /* Destination LSAP address */
+ __u8 pid; /* Protocol identifier */
+ __u8 *fp;
+
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+ ASSERT(skb->len > 2, return;);
+
+ fp = skb->data;
+
+ /*
+ * The next statements may be confusing, but we do this so that
+ * destination LSAP of received frame is source LSAP in our view
+ */
+ slsap_sel = fp[0] & LSAP_MASK;
+ dlsap_sel = fp[1];
+ pid = fp[2];
+
+ if (pid & 0x80) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), extension in PID not supp!\n");
+ dev_kfree_skb(skb);
+
+ return;
+ }
+
+ /* Check if frame is addressed to the connectionless LSAP */
+ if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), dropping frame!\n");
+ dev_kfree_skb(skb);
+
+ return;
+ }
+
+ lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
+ while (lsap != NULL) {
+ /*
+ * Check if source LSAP and dest LSAP selectors and PID match.
+ */
+ if ((lsap->slsap_sel == slsap_sel) &&
+ (lsap->dlsap_sel == dlsap_sel) &&
+ (lsap->pid == pid))
+ {
+ break;
+ }
+ lsap = (struct lsap_cb *) hashbin_get_next(irlmp->unconnected_lsaps);
+ }
+ if (lsap)
+ irlmp_connless_data_indication(lsap, skb);
+ else {
+ IRDA_DEBUG(0, __FUNCTION__ "(), found no matching LSAP!\n");
+ dev_kfree_skb(skb);
}
}
+#endif /* CONFIG_IRDA_ULTRA */
/*
* Function irlmp_link_disconnect_indication (reason, userdata)
@@ -207,7 +281,9 @@ void irlmp_link_disconnect_indication(struct lap_cb *lap,
lap->daddr = DEV_ADDR_ANY;
/* FIXME: must do something with the userdata if any */
-
+ if (userdata)
+ dev_kfree_skb(userdata);
+
/*
* Inform station state machine
*/
@@ -251,6 +327,10 @@ void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
ASSERT(self->magic == LMP_LAP_MAGIC, return;);
ASSERT(qos != NULL, return;);
+ /* Don't need use the userdata for now */
+ if (userdata)
+ dev_kfree_skb(userdata);
+
/* Copy QoS settings for this session */
self->qos = qos;
@@ -270,9 +350,10 @@ void irlmp_link_discovery_indication(struct lap_cb *self,
ASSERT(self->magic == LMP_LAP_MAGIC, return;);
irlmp_add_discovery(irlmp->cachelog, discovery);
+
+#if 0 /* This will just cause a lot of connection collisions */
/* Just handle it the same way as a discovery confirm */
-#if 0
irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
#endif
}
@@ -369,5 +450,3 @@ static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel,
/* Sorry not found! */
return NULL;
}
-
-
diff --git a/net/irda/irmod.c b/net/irda/irmod.c
index ca6c9d3ba..c26433f80 100644
--- a/net/irda/irmod.c
+++ b/net/irda/irmod.c
@@ -6,10 +6,10 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Dec 15 13:55:39 1997
- * Modified at: Sun Nov 14 08:57:52 1999
+ * Modified at: Wed Jan 5 15:12:41 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1997, 1999-2000 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
@@ -140,6 +140,7 @@ EXPORT_SYMBOL(irias_add_string_attrib);
EXPORT_SYMBOL(irias_insert_object);
EXPORT_SYMBOL(irias_new_object);
EXPORT_SYMBOL(irias_delete_object);
+EXPORT_SYMBOL(irias_delete_value);
EXPORT_SYMBOL(irias_find_object);
EXPORT_SYMBOL(irias_find_attrib);
EXPORT_SYMBOL(irias_new_integer_value);
@@ -194,6 +195,7 @@ EXPORT_SYMBOL(irda_device_unregister_dongle);
EXPORT_SYMBOL(irda_task_execute);
EXPORT_SYMBOL(irda_task_kick);
EXPORT_SYMBOL(irda_task_next_state);
+EXPORT_SYMBOL(irda_task_delete);
EXPORT_SYMBOL(async_wrap_skb);
EXPORT_SYMBOL(async_unwrap_char);
@@ -330,8 +332,7 @@ void irda_execute_as_process( void *self, TODO_CALLBACK callback, __u32 param)
struct irmanager_event event;
/* Make sure irmanager is running */
- if ( !irda.in_use) {
- printk( KERN_ERR "irmanager is not running!\n");
+ if (!irda.in_use) {
return;
}
@@ -370,7 +371,6 @@ void irmanager_notify( struct irmanager_event *event)
/* Make sure irmanager is running */
if (!irda.in_use) {
- printk( KERN_ERR "irmanager is not running!\n");
return;
}
@@ -525,6 +525,24 @@ void irda_mod_dec_use_count(void)
#endif
}
+/*
+ * Function irda_proc_modcount (inode, fill)
+ *
+ * Use by the proc file system functions to prevent the irda module
+ * being removed while the use is standing in the net/irda directory
+ */
+void irda_proc_modcount(struct inode *inode, int fill)
+{
+#ifdef MODULE
+#ifdef CONFIG_PROC_FS
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+#endif /* CONFIG_PROC_FS */
+#endif /* MODULE */
+}
+
#ifdef MODULE
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c
index 91a7a6f85..1d26d8f19 100644
--- a/net/irda/irqueue.c
+++ b/net/irda/irqueue.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Jun 9 13:29:31 1998
- * Modified at: Tue Oct 5 09:02:15 1999
+ * Modified at: Sun Dec 12 13:48:22 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no>
@@ -88,13 +88,13 @@ int hashbin_clear( hashbin_t* hashbin, FREE_FUNC free_func)
/*
* Free the entries in the hashbin
*/
- for ( i = 0; i < HASHBIN_SIZE; i ++ ) {
- queue = dequeue_first( (queue_t**) &hashbin->hb_queue[ i]);
- while( queue ) {
- if ( free_func)
- (*free_func)( queue );
+ for (i = 0; i < HASHBIN_SIZE; i ++ ) {
+ queue = dequeue_first( (queue_t**) &hashbin->hb_queue[i]);
+ while (queue) {
+ if (free_func)
+ (*free_func)(queue);
queue = dequeue_first(
- (queue_t**) &hashbin->hb_queue[ i]);
+ (queue_t**) &hashbin->hb_queue[i]);
}
}
hashbin->hb_size = 0;
@@ -210,7 +210,7 @@ void hashbin_unlock(hashbin_t* hashbin, __u32 hashv, char* name,
* Insert an entry into the hashbin
*
*/
-void hashbin_insert( hashbin_t* hashbin, queue_t* entry, __u32 hashv, char* name)
+void hashbin_insert(hashbin_t* hashbin, queue_t* entry, __u32 hashv, char* name)
{
unsigned long flags = 0;
int bin;
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 862360b4a..46c2ae85e 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -3,13 +3,13 @@
* Filename: irttp.c
* Version: 1.2
* Description: Tiny Transport Protocol (TTP) implementation
- * Status: Experimental.
+ * Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:31 1997
- * Modified at: Tue Oct 19 21:40:00 1999
+ * Modified at: Wed Jan 5 11:31:27 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
+ * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -144,6 +144,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
return NULL;
}
memset(self, 0, sizeof(struct tsap_cb));
+ spin_lock_init(&self->lock);
init_timer(&self->todo_timer);
@@ -166,7 +167,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
/*
* Create LSAP at IrLMP layer
*/
- lsap = irlmp_open_lsap(stsap_sel, &ttp_notify);
+ lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);
if (lsap == NULL) {
WARNING(__FUNCTION__ "(), unable to allocate LSAP!!\n");
return NULL;
@@ -326,7 +327,7 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
* TxMaxSduSize
*/
if ((self->tx_max_sdu_size != 0) &&
- (self->tx_max_sdu_size != SAR_UNBOUND) &&
+ (self->tx_max_sdu_size != TTP_SAR_UNBOUND) &&
(skb->len > self->tx_max_sdu_size))
{
ERROR(__FUNCTION__ "(), SAR enabled, "
@@ -365,7 +366,7 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
/* Check if we can accept more data from client */
if ((!self->tx_sdu_busy) &&
- (skb_queue_len(&self->tx_queue) > HIGH_THRESHOLD)) {
+ (skb_queue_len(&self->tx_queue) > TTP_HIGH_THRESHOLD)) {
/* Tx queue filling up, so stop client */
self->tx_sdu_busy = TRUE;
@@ -446,7 +447,7 @@ static void irttp_run_tx_queue(struct tsap_cb *self)
/* Check if we can accept more frames from client */
if ((self->tx_sdu_busy) &&
- (skb_queue_len(&self->tx_queue) < LOW_THRESHOLD))
+ (skb_queue_len(&self->tx_queue) < TTP_LOW_THRESHOLD))
{
self->tx_sdu_busy = FALSE;
@@ -477,7 +478,7 @@ void irttp_give_credit(struct tsap_cb *self)
ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n",
- self->send_credit, self->avail_credit, self->remote_credit);
+ self->send_credit, self->avail_credit, self->remote_credit);
/* Give credit to peer */
tx_skb = dev_alloc_skb(64);
@@ -533,9 +534,11 @@ static int irttp_udata_indication(void *instance, void *sap,
ASSERT(skb != NULL, return -1;);
/* Just pass data to layer above */
- if (self->notify.udata_indication) {
- self->notify.udata_indication(self->notify.instance, self, skb);
- }
+ if (self->notify.udata_indication)
+ self->notify.udata_indication(self->notify.instance, self,skb);
+ else
+ dev_kfree_skb(skb);
+
self->stats.rx_packets++;
return 0;
@@ -573,8 +576,10 @@ static int irttp_data_indication(void *instance, void *sap,
* more bit, so the defragment routing knows what to do
*/
skb_queue_tail(&self->rx_queue, skb);
- } else
+ } else {
self->send_credit += n; /* Dataless flowdata TTP-PDU */
+ dev_kfree_skb(skb);
+ }
irttp_run_rx_queue(self);
@@ -582,7 +587,7 @@ static int irttp_data_indication(void *instance, void *sap,
* Give avay some credits to peer?
*/
if ((skb_queue_empty(&self->tx_queue)) &&
- (self->remote_credit < LOW_THRESHOLD) &&
+ (self->remote_credit < TTP_LOW_THRESHOLD) &&
(self->avail_credit > 0))
{
/* Schedule to start immediately after this thread */
@@ -830,7 +835,7 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
lsap = (struct lsap_cb *) sap;
- self->max_seg_size = max_seg_size;
+ self->max_seg_size = max_seg_size - TTP_HEADER;;
self->max_header_size = max_header_size+TTP_HEADER;
IRDA_DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel);
@@ -873,7 +878,8 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
self->notify.connect_indication(self->notify.instance, self,
qos, self->tx_max_sdu_size,
self->max_header_size, skb);
- }
+ } else
+ dev_kfree_skb(skb);
}
/*
@@ -895,7 +901,7 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
IRDA_DEBUG(4, __FUNCTION__ "(), Source TSAP selector=%02x\n",
- self->stsap_sel);
+ self->stsap_sel);
/* Any userdata supplied? */
if (userdata == NULL) {
@@ -1093,7 +1099,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
*
*/
void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason,
- struct sk_buff *userdata)
+ struct sk_buff *skb)
{
struct tsap_cb *self;
@@ -1106,11 +1112,22 @@ void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason,
self->connected = FALSE;
- if (!self->notify.disconnect_indication)
+ /* Check if client has already tried to close the TSAP */
+ if (self->close_pend) {
+ irttp_close_tsap(self);
return;
+ }
- self->notify.disconnect_indication(self->notify.instance, self, reason,
- userdata);
+ /* No need to notify the client if has already tried to disconnect */
+ if (self->disconnect_pend)
+ return;
+
+ if (self->notify.disconnect_indication)
+ self->notify.disconnect_indication(self->notify.instance, self,
+ reason, skb);
+ else
+ if (skb)
+ dev_kfree_skb(skb);
}
/*
@@ -1124,6 +1141,12 @@ void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb)
{
int err;
+ /* Check if client has already tried to close the TSAP */
+ if (self->close_pend || self->disconnect_pend) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
err = self->notify.data_indication(self->notify.instance, self, skb);
/* Usually the layer above will notify that it's input queue is
@@ -1157,8 +1180,8 @@ void irttp_run_rx_queue(struct tsap_cb *self)
struct sk_buff *skb;
int more = 0;
- IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n",
- self->send_credit, self->avail_credit, self->remote_credit);
+ IRDA_DEBUG(2, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n",
+ self->send_credit, self->avail_credit, self->remote_credit);
if (irda_lock(&self->rx_queue_lock) == FALSE)
return;
@@ -1183,7 +1206,7 @@ void irttp_run_rx_queue(struct tsap_cb *self)
* immediately. This can be requested by clients that
* implements byte streams without any message boundaries
*/
- if (self->rx_max_sdu_size == SAR_DISABLE) {
+ if (self->rx_max_sdu_size == TTP_SAR_DISABLE) {
irttp_do_data_indication(self, skb);
self->rx_sdu_size = 0;
@@ -1209,7 +1232,7 @@ void irttp_run_rx_queue(struct tsap_cb *self)
* This is the last fragment, so time to reassemble!
*/
if ((self->rx_sdu_size <= self->rx_max_sdu_size) ||
- (self->rx_max_sdu_size == SAR_UNBOUND))
+ (self->rx_max_sdu_size == TTP_SAR_UNBOUND))
{
/*
* A little optimizing. Only queue the fragment if
@@ -1285,10 +1308,10 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
ASSERT(self != NULL, return NULL;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
- IRDA_DEBUG(4, __FUNCTION__ "(), self->rx_sdu_size=%d\n",
- self->rx_sdu_size);
+ IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n",
+ self->rx_sdu_size);
- skb = dev_alloc_skb(self->rx_sdu_size);
+ skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
if (!skb)
return NULL;
@@ -1308,11 +1331,12 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
dev_kfree_skb(frag);
}
- IRDA_DEBUG(4, __FUNCTION__ "(), frame len=%d\n", n);
- /* Set the new length */
+ IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
- IRDA_DEBUG(4, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
+ IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
ASSERT(n <= self->rx_sdu_size, return NULL;);
+
+ /* Set the new length */
skb_trim(skb, n);
self->rx_sdu_size = 0;
@@ -1331,7 +1355,7 @@ static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb)
struct sk_buff *frag;
__u8 *frame;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
@@ -1340,22 +1364,9 @@ static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb)
/*
* Split frame into a number of segments
*/
- while (skb->len > 0) {
- /*
- * Instead of making the last segment, we just
- * queue what is left of the original skb
- */
- if (skb->len < self->max_seg_size) {
- IRDA_DEBUG(4, __FUNCTION__
- "(), queuing last segment\n");
+ while (skb->len > self->max_seg_size) {
+ IRDA_DEBUG(2, __FUNCTION__ "(), fragmenting ...\n");
- frame = skb_push(skb, TTP_HEADER);
- frame[0] = 0x00; /* Clear more bit */
- skb_queue_tail(&self->tx_queue, skb);
-
- return;
- }
-
/* Make new segment */
frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
if (!frag)
@@ -1363,19 +1374,28 @@ static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb)
skb_reserve(frag, self->max_header_size);
- /*
- * Copy data from the original skb into this fragment. We
- * first insert the TTP header with the more bit set
- */
- frame = skb_put(frag, self->max_seg_size+TTP_HEADER);
+ /* Copy data from the original skb into this fragment. */
+ memcpy(skb_put(frag, self->max_seg_size), skb->data,
+ self->max_seg_size);
+
+ /* Insert TTP header, with the more bit set */
+ frame = skb_push(frag, TTP_HEADER);
frame[0] = TTP_MORE;
- memcpy(frag->data+1, skb->data, self->max_seg_size);
/* Hide the copied data from the original skb */
skb_pull(skb, self->max_seg_size);
-
+
+ /* Queue fragment */
skb_queue_tail(&self->tx_queue, frag);
}
+ /* Queue what is left of the original skb */
+ IRDA_DEBUG(2, __FUNCTION__ "(), queuing last segment\n");
+
+ frame = skb_push(skb, TTP_HEADER);
+ frame[0] = 0x00; /* Clear more bit */
+
+ /* Queue fragment */
+ skb_queue_tail(&self->tx_queue, skb);
}
/*
@@ -1422,7 +1442,7 @@ static void irttp_todo_expired(unsigned long data)
irttp_run_tx_queue(self);
/* Give avay some credits to peer? */
- if ((self->remote_credit < LOW_THRESHOLD) &&
+ if ((self->remote_credit < TTP_LOW_THRESHOLD) &&
(self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
{
irttp_give_credit(self);
@@ -1477,7 +1497,7 @@ static void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
#ifdef CONFIG_PROC_FS
/*
- * Function irttp_proc_read (buf, start, offset, len)
+ * Function irttp_proc_read (buf, start, offset, len, unused)
*
* Give some info to the /proc file system
*/
diff --git a/net/irda/parameters.c b/net/irda/parameters.c
index c6fd97e1e..19f76eae4 100644
--- a/net/irda/parameters.c
+++ b/net/irda/parameters.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Jun 7 10:25:11 1999
- * Modified at: Fri Nov 5 08:20:38 1999
+ * Modified at: Tue Dec 14 16:03:57 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -88,7 +88,7 @@ static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi,
ret = (*func)(self, &p, PV_GET);
/* Extract values anyway, since handler may need them */
- irda_param_pack(buf, "bb", p.pi, &p.pl);
+ irda_param_pack(buf, "bb", p.pi, p.pl);
if (ret < 0)
return ret;
diff --git a/net/irda/qos.c b/net/irda/qos.c
index df6ba6421..2c2c39b85 100644
--- a/net/irda/qos.c
+++ b/net/irda/qos.c
@@ -1,13 +1,12 @@
/*********************************************************************
- *
- *
+ *
* Filename: qos.c
* Version: 1.0
* Description: IrLAP QoS parameter negotiation
- * Status: Experimental.
+ * Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Sep 9 00:00:26 1997
- * Modified at: Tue Nov 16 09:50:19 1999
+ * Modified at: Sun Dec 12 13:47:09 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
@@ -52,18 +51,32 @@ static int irlap_param_window_size(void *instance, param_t *param, int get);
static int irlap_param_additional_bofs(void *instance, param_t *parm, int get);
static int irlap_param_min_turn_time(void *instance, param_t *param, int get);
-__u32 min_turn_time[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
-__u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
- 1152000, 4000000, 16000000 }; /* bps */
-__u32 data_size[] = { 64, 128, 256, 512, 1024, 2048 }; /* bytes */
-__u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 }; /* bytes */
-__u32 max_turn_time[] = { 500, 250, 100, 50 }; /* ms */
-__u32 link_disc_time[] = { 3, 8, 12, 16, 20, 25, 30, 40 }; /* secs */
+__u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
+__u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
+ 1152000, 4000000, 16000000 }; /* bps */
+__u32 data_sizes[] = { 64, 128, 256, 512, 1024, 2048 }; /* bytes */
+__u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 }; /* bytes */
+__u32 max_turn_times[] = { 500, 250, 100, 50 }; /* ms */
+__u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 }; /* secs */
#ifdef CONFIG_IRDA_COMPRESSION
-__u32 compression[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT };
+__u32 compressions[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT };
#endif
+__u32 max_line_capacities[10][4] = {
+ /* 500 ms 250 ms 100 ms 50 ms (max turn time) */
+ { 100, 0, 0, 0 }, /* 2400 bps */
+ { 400, 0, 0, 0 }, /* 9600 bps */
+ { 800, 0, 0, 0 }, /* 19200 bps */
+ { 1600, 0, 0, 0 }, /* 38400 bps */
+ { 2360, 0, 0, 0 }, /* 57600 bps */
+ { 4800, 2400, 960, 480 }, /* 115200 bps */
+ { 28800, 11520, 5760, 2880 }, /* 576000 bps */
+ { 57600, 28800, 11520, 5760 }, /* 1152000 bps */
+ { 200000, 100000, 40000, 20000 }, /* 4000000 bps */
+ { 800000, 400000, 160000, 80000 }, /* 16000000 bps */
+};
+
static pi_minor_info_t pi_minor_call_table_type_0[] = {
{ NULL, 0 },
/* 01 */{ irlap_param_baud_rate, PV_INTEGER | PV_LITTLE_ENDIAN },
@@ -150,6 +163,69 @@ void irda_init_max_qos_capabilies(struct qos_info *qos)
}
/*
+ * Function irlap_adjust_qos_settings (qos)
+ *
+ * Adjust QoS settings in case some values are not possible to use because
+ * of other settings
+ */
+void irlap_adjust_qos_settings(struct qos_info *qos)
+{
+ __u32 line_capacity;
+ int index;
+
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+ /*
+ * Not allowed to use a max turn time less than 500 ms if the baudrate
+ * is less than 115200
+ */
+ if ((qos->baud_rate.value < 115200) &&
+ (qos->max_turn_time.value < 500))
+ {
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), adjusting max turn time from %d to 500 ms\n",
+ qos->max_turn_time.value);
+ qos->max_turn_time.value = 500;
+ }
+
+ /*
+ * The data size must be adjusted according to the baud rate and max
+ * turn time
+ */
+ index = value_index(qos->data_size.value, data_sizes);
+ line_capacity = irlap_max_line_capacity(qos->baud_rate.value,
+ qos->max_turn_time.value);
+
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
+ while ((qos->data_size.value > line_capacity) && (index > 0)) {
+ qos->data_size.value = data_sizes[index--];
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), redusing data size to %d\n",
+ qos->data_size.value);
+ }
+#else /* Use method descibed in section 6.6.11 of IrLAP */
+ while (irlap_requested_line_capacity(qos) > line_capacity) {
+ ASSERT(index != 0, return;);
+
+ /* Must be able to send at least one frame */
+ if (qos->window_size.value > 1) {
+ qos->window_size.value--;
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), redusing window size to %d\n",
+ qos->window_size.value);
+ } else if (index > 1) {
+ qos->data_size.value = data_sizes[index--];
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), redusing data size to %d\n",
+ qos->data_size.value);
+ } else {
+ WARNING(__FUNCTION__ "(), nothing more we can do!\n");
+ }
+ }
+#endif CONFIG_IRDA_DYNAMIC_WINDOW
+}
+
+/*
* Function irlap_negotiate (qos_device, qos_session, skb)
*
* Negotiate QoS values, not really that much negotiation :-)
@@ -176,24 +252,26 @@ int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb)
/* Convert the negotiated bits to values */
irda_qos_bits_to_value(&self->qos_tx);
irda_qos_bits_to_value(&self->qos_rx);
-
+
+ irlap_adjust_qos_settings(&self->qos_tx);
+
IRDA_DEBUG(2, "Setting BAUD_RATE to %d bps.\n",
- self->qos_tx.baud_rate.value);
+ self->qos_tx.baud_rate.value);
IRDA_DEBUG(2, "Setting DATA_SIZE to %d bytes\n",
- self->qos_tx.data_size.value);
+ self->qos_tx.data_size.value);
IRDA_DEBUG(2, "Setting WINDOW_SIZE to %d\n",
- self->qos_tx.window_size.value);
+ self->qos_tx.window_size.value);
IRDA_DEBUG(2, "Setting XBOFS to %d\n",
- self->qos_tx.additional_bofs.value);
+ self->qos_tx.additional_bofs.value);
IRDA_DEBUG(2, "Setting MAX_TURN_TIME to %d ms.\n",
- self->qos_tx.max_turn_time.value);
+ self->qos_tx.max_turn_time.value);
IRDA_DEBUG(2, "Setting MIN_TURN_TIME to %d usecs.\n",
- self->qos_tx.min_turn_time.value);
+ self->qos_tx.min_turn_time.value);
IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n",
- self->qos_tx.link_disc_time.value);
+ self->qos_tx.link_disc_time.value);
#ifdef CONFIG_IRDA_COMPRESSION
IRDA_DEBUG(2, "Setting COMPRESSION to %d\n",
- self->qos_tx.compression.value);
+ self->qos_tx.compression.value);
#endif
return ret;
}
@@ -278,7 +356,8 @@ static int irlap_param_baud_rate(void *instance, param_t *param, int get)
if (get) {
param->pv.i = self->qos_rx.baud_rate.bits;
- IRDA_DEBUG(2, __FUNCTION__ "(), baud rate = 0x%02x\n", param->pv.i);
+ IRDA_DEBUG(2, __FUNCTION__ "(), baud rate = 0x%02x\n",
+ param->pv.i);
} else {
/*
* Stations must agree on baud rate, so calculate
@@ -435,6 +514,57 @@ static int irlap_param_min_turn_time(void *instance, param_t *param, int get)
return 0;
}
+/*
+ * Function irlap_max_line_capacity (speed, max_turn_time, min_turn_time)
+ *
+ * Calculate the maximum line capacity
+ *
+ */
+__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time)
+{
+ __u32 line_capacity;
+ int i,j;
+
+ IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, max_turn_time=%d\n",
+ speed, max_turn_time);
+
+ i = value_index(speed, baud_rates);
+ j = value_index(max_turn_time, max_turn_times);
+
+ ASSERT(((i >=0) && (i <=10)), return 0;);
+ ASSERT(((j >=0) && (j <=4)), return 0;);
+
+ line_capacity = max_line_capacities[i][j];
+
+ IRDA_DEBUG(2, __FUNCTION__ "(), line capacity=%d bytes\n",
+ line_capacity);
+
+ return line_capacity;
+}
+
+__u32 irlap_requested_line_capacity(struct qos_info *qos)
+{ __u32 line_capacity;
+
+ line_capacity = qos->window_size.value *
+ (qos->data_size.value + 6 + qos->additional_bofs.value) +
+ irlap_min_turn_time_in_bytes(qos->baud_rate.value,
+ qos->min_turn_time.value);
+
+ IRDA_DEBUG(2, __FUNCTION__ "(), requested line capacity=%d\n",
+ line_capacity);
+
+ return line_capacity;
+}
+
+__u32 irlap_min_turn_time_in_bytes(__u32 speed, __u32 min_turn_time)
+{
+ __u32 bytes;
+
+ bytes = speed * min_turn_time / 10000000;
+
+ return bytes;
+}
+
__u32 byte_value(__u8 byte, __u32 *array)
{
int index;
@@ -503,19 +633,19 @@ void irda_qos_bits_to_value(struct qos_info *qos)
qos->baud_rate.value = baud_rates[index];
index = msb_index(qos->data_size.bits);
- qos->data_size.value = data_size[index];
+ qos->data_size.value = data_sizes[index];
index = msb_index(qos->window_size.bits);
qos->window_size.value = index+1;
index = msb_index(qos->min_turn_time.bits);
- qos->min_turn_time.value = min_turn_time[index];
+ qos->min_turn_time.value = min_turn_times[index];
index = msb_index(qos->max_turn_time.bits);
- qos->max_turn_time.value = max_turn_time[index];
+ qos->max_turn_time.value = max_turn_times[index];
index = msb_index(qos->link_disc_time.bits);
- qos->link_disc_time.value = link_disc_time[index];
+ qos->link_disc_time.value = link_disc_times[index];
index = msb_index(qos->additional_bofs.bits);
qos->additional_bofs.value = add_bofs[index];
@@ -523,7 +653,7 @@ void irda_qos_bits_to_value(struct qos_info *qos)
#ifdef CONFIG_IRDA_COMPRESSION
index = msb_index(qos->compression.bits);
if (index >= 0)
- qos->compression.value = compression[index];
+ qos->compression.value = compressions[index];
else
qos->compression.value = 0;
#endif
diff --git a/net/irda/timer.c b/net/irda/timer.c
index 974863721..7625eecfc 100644
--- a/net/irda/timer.c
+++ b/net/irda/timer.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Aug 16 00:59:29 1997
- * Modified at: Thu Oct 7 12:30:19 1999
+ * Modified at: Wed Dec 8 12:50:34 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
@@ -210,4 +210,8 @@ void irlap_media_busy_expired(void* data)
ASSERT(self != NULL, return;);
irda_device_set_media_busy(self->netdev, FALSE);
+
+ /* Send any pending Ultra frames if any */
+ if (!skb_queue_empty(&self->txq_ultra))
+ irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
}
diff --git a/net/irda/wrapper.c b/net/irda/wrapper.c
index 6f21b15f3..13e4d0465 100644
--- a/net/irda/wrapper.c
+++ b/net/irda/wrapper.c
@@ -3,10 +3,10 @@
* Filename: wrapper.c
* Version: 1.2
* Description: IrDA SIR async wrapper layer
- * Status: Experimental.
+ * Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Sat Oct 30 17:24:25 1999
+ * Modified at: Sun Dec 12 13:46:40 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Modified at: Fri May 28 3:11 CST 1999
* Modified by: Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
@@ -86,11 +86,24 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
* additional XBOFS
*/
if (((struct irda_skb_cb *)(skb->cb))->magic != LAP_MAGIC) {
+ /*
+ * This will happen for all frames sent from user-space.
+ * Nothing to worry about, but we set the default number of
+ * BOF's
+ */
IRDA_DEBUG(1, __FUNCTION__ "(), wrong magic in skb!\n");
xbofs = 10;
} else
xbofs = ((struct irda_skb_cb *)(skb->cb))->xbofs;
+ IRDA_DEBUG(4, __FUNCTION__ "(), xbofs=%d\n", xbofs);
+
+ /* Check that we never use more than 115 + 48 xbofs */
+ if (xbofs > 163) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), too many xbofs (%d)\n", xbofs);
+ xbofs = 163;
+ }
+
memset(tx_buff+n, XBOF, xbofs);
n += xbofs;
@@ -200,7 +213,7 @@ inline void async_unwrap_char(struct net_device *dev,
/*
* Function state_outside_frame (dev, rx_buff, byte)
*
- *
+ * Not receiving any frame (or just bogus data)
*
*/
static void state_outside_frame(struct net_device *dev,
@@ -219,6 +232,7 @@ static void state_outside_frame(struct net_device *dev,
irda_device_set_media_busy(dev, TRUE);
break;
default:
+ irda_device_set_media_busy(dev, TRUE);
break;
}
}
@@ -249,13 +263,12 @@ static void state_begin_frame(struct net_device *dev,
case EOF:
/* Abort frame */
rx_buff->state = OUTSIDE_FRAME;
-
+ IRDA_DEBUG(1, __FUNCTION__ "(), abort frame\n");
stats->rx_errors++;
stats->rx_frame_errors++;
break;
default:
rx_buff->data[rx_buff->len++] = byte;
-
rx_buff->fcs = irda_fcs(rx_buff->fcs, byte);
rx_buff->state = INSIDE_FRAME;
break;
@@ -265,7 +278,7 @@ static void state_begin_frame(struct net_device *dev,
/*
* Function state_link_escape (idev, byte)
*
- *
+ * Found link escape character
*
*/
static void state_link_escape(struct net_device *dev,
@@ -278,7 +291,7 @@ static void state_link_escape(struct net_device *dev,
irda_device_set_media_busy(dev, TRUE);
break;
case CE:
- IRDA_DEBUG(4, "WARNING: State not defined\n");
+ WARNING(__FUNCTION__ "(), state not defined\n");
break;
case EOF: /* Abort frame */
rx_buff->state = OUTSIDE_FRAME;
@@ -294,8 +307,7 @@ static void state_link_escape(struct net_device *dev,
rx_buff->fcs = irda_fcs(rx_buff->fcs, byte);
rx_buff->state = INSIDE_FRAME;
} else {
- IRDA_DEBUG(1, __FUNCTION__
- "(), Rx buffer overflow, aborting\n");
+ IRDA_DEBUG(1, __FUNCTION__ "(), rx buffer overflow\n");
rx_buff->state = OUTSIDE_FRAME;
}
break;
@@ -336,6 +348,7 @@ static void state_inside_frame(struct net_device *dev,
/* Wrong CRC, discard frame! */
irda_device_set_media_busy(dev, TRUE);
+ IRDA_DEBUG(1, __FUNCTION__ "(), crc error\n");
stats->rx_errors++;
stats->rx_crc_errors++;
}