diff options
Diffstat (limited to 'net/irda')
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(¬ify); + notify.udata_indication = irda_data_indication; + notify.instance = self; + strncpy(notify.name, "Ultra", NOTIFY_MAX_NAME); + + self->lsap = irlmp_open_lsap(LSAP_CONNLESS, ¬ify, 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, ¬ify); + self->lsap = irlmp_open_lsap(LSAP_ANY, ¬ify, 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, ¬ify); 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(¬ify, 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(¬ify); - 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, ¬ify); - 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(¬ify); + 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, ¬ify, 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++; } |