Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluet...
authorDavid S. Miller <davem@davemloft.net>
Sat, 19 Jul 2008 07:30:39 +0000 (00:30 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sat, 19 Jul 2008 07:30:39 +0000 (00:30 -0700)
1  2 
fs/compat_ioctl.c
net/bluetooth/bnep/core.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c

diff --combined fs/compat_ioctl.c
@@@ -58,6 -58,7 +58,6 @@@
  #include <linux/syscalls.h>
  #include <linux/i2c.h>
  #include <linux/i2c-dev.h>
 -#include <linux/wireless.h>
  #include <linux/atalk.h>
  #include <linux/loop.h>
  
  #include <linux/capi.h>
  #include <linux/gigaset_dev.h>
  
 +#ifdef CONFIG_BLOCK
  #include <scsi/scsi.h>
  #include <scsi/scsi_ioctl.h>
  #include <scsi/sg.h>
 +#endif
  
  #include <asm/uaccess.h>
  #include <linux/ethtool.h>
@@@ -1758,6 -1757,64 +1758,6 @@@ static int do_i2c_smbus_ioctl(unsigned 
        return sys_ioctl(fd, cmd, (unsigned long)tdata);
  }
  
 -struct compat_iw_point {
 -      compat_caddr_t pointer;
 -      __u16 length;
 -      __u16 flags;
 -};
 -
 -static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 -{
 -      struct iwreq __user *iwr;
 -      struct iwreq __user *iwr_u;
 -      struct iw_point __user *iwp;
 -      struct compat_iw_point __user *iwp_u;
 -      compat_caddr_t pointer_u;
 -      void __user *pointer;
 -      __u16 length, flags;
 -      int ret;
 -
 -      iwr_u = compat_ptr(arg);
 -      iwp_u = (struct compat_iw_point __user *) &iwr_u->u.data;
 -      iwr = compat_alloc_user_space(sizeof(*iwr));
 -      if (iwr == NULL)
 -              return -ENOMEM;
 -
 -      iwp = &iwr->u.data;
 -
 -      if (!access_ok(VERIFY_WRITE, iwr, sizeof(*iwr)))
 -              return -EFAULT;
 -
 -      if (__copy_in_user(&iwr->ifr_ifrn.ifrn_name[0],
 -                         &iwr_u->ifr_ifrn.ifrn_name[0],
 -                         sizeof(iwr->ifr_ifrn.ifrn_name)))
 -              return -EFAULT;
 -
 -      if (__get_user(pointer_u, &iwp_u->pointer) ||
 -          __get_user(length, &iwp_u->length) ||
 -          __get_user(flags, &iwp_u->flags))
 -              return -EFAULT;
 -
 -      if (__put_user(compat_ptr(pointer_u), &iwp->pointer) ||
 -          __put_user(length, &iwp->length) ||
 -          __put_user(flags, &iwp->flags))
 -              return -EFAULT;
 -
 -      ret = sys_ioctl(fd, cmd, (unsigned long) iwr);
 -
 -      if (__get_user(pointer, &iwp->pointer) ||
 -          __get_user(length, &iwp->length) ||
 -          __get_user(flags, &iwp->flags))
 -              return -EFAULT;
 -
 -      if (__put_user(ptr_to_compat(pointer), &iwp_u->pointer) ||
 -          __put_user(length, &iwp_u->length) ||
 -          __put_user(flags, &iwp_u->flags))
 -              return -EFAULT;
 -
 -      return ret;
 -}
 -
  /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
   * for some operations; this forces use of the newer bridge-utils that
   * use compatiable ioctls
@@@ -1967,7 -2024,6 +1967,7 @@@ COMPATIBLE_IOCTL(GIO_UNISCRNMAP
  COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
  COMPATIBLE_IOCTL(PIO_FONTRESET)
  COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
 +#ifdef CONFIG_BLOCK
  /* Big S */
  COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
  COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
@@@ -1977,7 -2033,6 +1977,7 @@@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUM
  COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
  COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
  COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
 +#endif
  /* Big T */
  COMPATIBLE_IOCTL(TUNSETNOCSUM)
  COMPATIBLE_IOCTL(TUNSETDEBUG)
@@@ -2048,7 -2103,6 +2048,7 @@@ COMPATIBLE_IOCTL(SIOCGIFVLAN
  COMPATIBLE_IOCTL(SIOCSIFVLAN)
  COMPATIBLE_IOCTL(SIOCBRADDBR)
  COMPATIBLE_IOCTL(SIOCBRDELBR)
 +#ifdef CONFIG_BLOCK
  /* SG stuff */
  COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
  COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
@@@ -2073,7 -2127,6 +2073,7 @@@ COMPATIBLE_IOCTL(SG_SCSI_RESET
  COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
  COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
  COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
 +#endif
  /* PPP stuff */
  COMPATIBLE_IOCTL(PPPIOCGFLAGS)
  COMPATIBLE_IOCTL(PPPIOCSFLAGS)
@@@ -2346,6 -2399,7 +2346,7 @@@ COMPATIBLE_IOCTL(HCIGETDEVLIST
  COMPATIBLE_IOCTL(HCIGETDEVINFO)
  COMPATIBLE_IOCTL(HCIGETCONNLIST)
  COMPATIBLE_IOCTL(HCIGETCONNINFO)
+ COMPATIBLE_IOCTL(HCIGETAUTHINFO)
  COMPATIBLE_IOCTL(HCISETRAW)
  COMPATIBLE_IOCTL(HCISETSCAN)
  COMPATIBLE_IOCTL(HCISETAUTH)
@@@ -2442,6 -2496,36 +2443,6 @@@ COMPATIBLE_IOCTL(I2C_TENBIT
  COMPATIBLE_IOCTL(I2C_PEC)
  COMPATIBLE_IOCTL(I2C_RETRIES)
  COMPATIBLE_IOCTL(I2C_TIMEOUT)
 -/* wireless */
 -COMPATIBLE_IOCTL(SIOCSIWCOMMIT)
 -COMPATIBLE_IOCTL(SIOCGIWNAME)
 -COMPATIBLE_IOCTL(SIOCSIWNWID)
 -COMPATIBLE_IOCTL(SIOCGIWNWID)
 -COMPATIBLE_IOCTL(SIOCSIWFREQ)
 -COMPATIBLE_IOCTL(SIOCGIWFREQ)
 -COMPATIBLE_IOCTL(SIOCSIWMODE)
 -COMPATIBLE_IOCTL(SIOCGIWMODE)
 -COMPATIBLE_IOCTL(SIOCSIWSENS)
 -COMPATIBLE_IOCTL(SIOCGIWSENS)
 -COMPATIBLE_IOCTL(SIOCSIWRANGE)
 -COMPATIBLE_IOCTL(SIOCSIWPRIV)
 -COMPATIBLE_IOCTL(SIOCSIWSTATS)
 -COMPATIBLE_IOCTL(SIOCSIWAP)
 -COMPATIBLE_IOCTL(SIOCGIWAP)
 -COMPATIBLE_IOCTL(SIOCSIWRATE)
 -COMPATIBLE_IOCTL(SIOCGIWRATE)
 -COMPATIBLE_IOCTL(SIOCSIWRTS)
 -COMPATIBLE_IOCTL(SIOCGIWRTS)
 -COMPATIBLE_IOCTL(SIOCSIWFRAG)
 -COMPATIBLE_IOCTL(SIOCGIWFRAG)
 -COMPATIBLE_IOCTL(SIOCSIWTXPOW)
 -COMPATIBLE_IOCTL(SIOCGIWTXPOW)
 -COMPATIBLE_IOCTL(SIOCSIWRETRY)
 -COMPATIBLE_IOCTL(SIOCGIWRETRY)
 -COMPATIBLE_IOCTL(SIOCSIWPOWER)
 -COMPATIBLE_IOCTL(SIOCGIWPOWER)
 -COMPATIBLE_IOCTL(SIOCSIWAUTH)
 -COMPATIBLE_IOCTL(SIOCGIWAUTH)
  /* hiddev */
  COMPATIBLE_IOCTL(HIDIOCGVERSION)
  COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
@@@ -2672,7 -2756,29 +2673,7 @@@ COMPATIBLE_IOCTL(USBDEVFS_IOCTL32
  HANDLE_IOCTL(I2C_FUNCS, w_long)
  HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
  HANDLE_IOCTL(I2C_SMBUS, do_i2c_smbus_ioctl)
 -/* wireless */
 -HANDLE_IOCTL(SIOCGIWRANGE, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWPRIV, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWSTATS, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWSPY, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWSPY, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWTHRSPY, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWTHRSPY, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWMLME, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWAPLIST, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWSCAN, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWSCAN, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWESSID, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWESSID, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWNICKN, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWNICKN, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWENCODE, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWENCODE, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWGENIE, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWGENIE, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWENCODEEXT, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCGIWENCODEEXT, do_wireless_ioctl)
 -HANDLE_IOCTL(SIOCSIWPMKSA, do_wireless_ioctl)
 +/* bridge */
  HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl)
  HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
  /* Not implemented in the native kernel */
     SOFTWARE IS DISCLAIMED.
  */
  
 -/*
 - * $Id: core.c,v 1.20 2002/08/04 21:23:58 maxk Exp $
 - */
 -
  #include <linux/module.h>
  
  #include <linux/kernel.h>
@@@ -503,6 -507,11 +503,11 @@@ static int bnep_session(void *arg
        /* Delete network device */
        unregister_netdev(dev);
  
+       /* Wakeup user-space polling for socket errors */
+       s->sock->sk->sk_err = EUNATCH;
+       wake_up_interruptible(s->sock->sk->sk_sleep);
        /* Release the socket */
        fput(s->sock->file);
  
@@@ -23,6 -23,8 +23,6 @@@
  
  /*
   * Bluetooth RFCOMM core.
 - *
 - * $Id: core.c,v 1.42 2002/10/01 23:26:25 maxk Exp $
   */
  
  #include <linux/module.h>
@@@ -51,7 -53,7 +51,7 @@@
  #define BT_DBG(D...)
  #endif
  
- #define VERSION "1.8"
+ #define VERSION "1.10"
  
  static int disable_cfc = 0;
  static int channel_mtu = -1;
@@@ -228,6 -230,21 +228,21 @@@ static int rfcomm_l2sock_create(struct 
        return err;
  }
  
+ static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
+ {
+       struct sock *sk = d->session->sock->sk;
+       if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
+               if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
+                       return 1;
+       } else if (d->link_mode & RFCOMM_LM_AUTH) {
+               if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
+                       return 1;
+       }
+       return 0;
+ }
  /* ---- RFCOMM DLCs ---- */
  static void rfcomm_dlc_timeout(unsigned long arg)
  {
@@@ -369,15 -386,23 +384,23 @@@ static int __rfcomm_dlc_open(struct rfc
        d->addr     = __addr(s->initiator, dlci);
        d->priority = 7;
  
-       d->state    = BT_CONFIG;
+       d->state = BT_CONFIG;
        rfcomm_dlc_link(s, d);
  
+       d->out = 1;
        d->mtu = s->mtu;
        d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
  
-       if (s->state == BT_CONNECTED)
-               rfcomm_send_pn(s, 1, d);
+       if (s->state == BT_CONNECTED) {
+               if (rfcomm_check_link_mode(d))
+                       set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+               else
+                       rfcomm_send_pn(s, 1, d);
+       }
        rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
        return 0;
  }
  
@@@ -1144,21 -1169,6 +1167,6 @@@ static int rfcomm_recv_disc(struct rfco
        return 0;
  }
  
- static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
- {
-       struct sock *sk = d->session->sock->sk;
-       if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
-               if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
-                       return 1;
-       } else if (d->link_mode & RFCOMM_LM_AUTH) {
-               if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
-                       return 1;
-       }
-       return 0;
- }
  static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
  {
        struct sock *sk = d->session->sock->sk;
@@@ -1203,10 -1213,8 +1211,8 @@@ static int rfcomm_recv_sabm(struct rfco
                        if (rfcomm_check_link_mode(d)) {
                                set_bit(RFCOMM_AUTH_PENDING, &d->flags);
                                rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-                               return 0;
-                       }
-                       rfcomm_dlc_accept(d);
+                       } else
+                               rfcomm_dlc_accept(d);
                }
                return 0;
        }
                if (rfcomm_check_link_mode(d)) {
                        set_bit(RFCOMM_AUTH_PENDING, &d->flags);
                        rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-                       return 0;
-               }
-               rfcomm_dlc_accept(d);
+               } else
+                       rfcomm_dlc_accept(d);
        } else {
                rfcomm_send_dm(s, dlci);
        }
@@@ -1457,8 -1463,12 +1461,12 @@@ static int rfcomm_recv_msc(struct rfcom
                        clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
  
                rfcomm_dlc_lock(d);
+               d->remote_v24_sig = msc->v24_sig;
                if (d->modem_status)
                        d->modem_status(d, msc->v24_sig);
                rfcomm_dlc_unlock(d);
  
                rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
@@@ -1634,7 -1644,11 +1642,11 @@@ static void rfcomm_process_connect(stru
                d = list_entry(p, struct rfcomm_dlc, list);
                if (d->state == BT_CONFIG) {
                        d->mtu = s->mtu;
-                       rfcomm_send_pn(s, 1, d);
+                       if (rfcomm_check_link_mode(d)) {
+                               set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+                               rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+                       } else
+                               rfcomm_send_pn(s, 1, d);
                }
        }
  }
@@@ -1707,7 -1721,11 +1719,11 @@@ static inline void rfcomm_process_dlcs(
  
                if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) {
                        rfcomm_dlc_clear_timer(d);
-                       rfcomm_dlc_accept(d);
+                       if (d->out) {
+                               rfcomm_send_pn(s, 1, d);
+                               rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
+                       } else
+                               rfcomm_dlc_accept(d);
                        if (d->link_mode & RFCOMM_LM_SECURE) {
                                struct sock *sk = s->sock->sk;
                                hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);
                        continue;
                } else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
                        rfcomm_dlc_clear_timer(d);
-                       rfcomm_send_dm(s, d->dlci);
+                       if (!d->out)
+                               rfcomm_send_dm(s, d->dlci);
+                       else
+                               d->state = BT_CLOSED;
                        __rfcomm_dlc_close(d, ECONNREFUSED);
                        continue;
                }
                        continue;
  
                if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
-                               d->mscex == RFCOMM_MSCEX_OK)
+                                               d->mscex == RFCOMM_MSCEX_OK)
                        rfcomm_process_tx(d);
        }
  }
@@@ -1952,7 -1973,8 +1971,8 @@@ static void rfcomm_auth_cfm(struct hci_
        list_for_each_safe(p, n, &s->dlcs) {
                d = list_entry(p, struct rfcomm_dlc, list);
  
-               if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE))
+               if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
+                               !(conn->link_mode & HCI_LM_ENCRYPT) && !status)
                        continue;
  
                if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
@@@ -1986,6 -2008,14 +2006,14 @@@ static void rfcomm_encrypt_cfm(struct h
        list_for_each_safe(p, n, &s->dlcs) {
                d = list_entry(p, struct rfcomm_dlc, list);
  
+               if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
+                                       (d->state == BT_CONNECTED ||
+                                               d->state == BT_CONFIG) &&
+                                               !status && encrypt == 0x00) {
+                       __rfcomm_dlc_close(d, ECONNREFUSED);
+                       continue;
+               }
                if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
                        continue;
  
@@@ -23,6 -23,8 +23,6 @@@
  
  /*
   * RFCOMM sockets.
 - *
 - * $Id: sock.c,v 1.24 2002/10/03 01:00:34 maxk Exp $
   */
  
  #include <linux/module.h>
@@@ -307,13 -309,13 +307,13 @@@ static struct sock *rfcomm_sock_alloc(s
        sk->sk_destruct = rfcomm_sock_destruct;
        sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT;
  
-       sk->sk_sndbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
-       sk->sk_rcvbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+       sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+       sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
  
        sock_reset_flag(sk, SOCK_ZAPPED);
  
        sk->sk_protocol = proto;
-       sk->sk_state    = BT_OPEN;
+       sk->sk_state    = BT_OPEN;
  
        bt_sock_link(&rfcomm_sk_list, sk);
  
@@@ -411,6 -413,8 +411,8 @@@ static int rfcomm_sock_connect(struct s
        bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
        rfcomm_pi(sk)->channel = sa->rc_channel;
  
+       d->link_mode = rfcomm_pi(sk)->link_mode;
        err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
        if (!err)
                err = bt_sock_wait_state(sk, BT_CONNECTED,
@@@ -686,6 -690,8 +688,8 @@@ static int rfcomm_sock_recvmsg(struct k
                copied += chunk;
                size   -= chunk;
  
+               sock_recv_timestamp(msg, sk, skb);
                if (!(flags & MSG_PEEK)) {
                        atomic_sub(chunk, &sk->sk_rmem_alloc);
  
@@@ -791,15 -797,20 +795,20 @@@ static int rfcomm_sock_ioctl(struct soc
        struct sock *sk = sock->sk;
        int err;
  
-       lock_sock(sk);
+       BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);
+       err = bt_sock_ioctl(sock, cmd, arg);
  
+       if (err == -ENOIOCTLCMD) {
  #ifdef CONFIG_BT_RFCOMM_TTY
-       err = rfcomm_dev_ioctl(sk, cmd, (void __user *)arg);
+               lock_sock(sk);
+               err = rfcomm_dev_ioctl(sk, cmd, (void __user *) arg);
+               release_sock(sk);
  #else
-       err = -EOPNOTSUPP;
+               err = -EOPNOTSUPP;
  #endif
+       }
  
-       release_sock(sk);
        return err;
  }
  
@@@ -23,6 -23,8 +23,6 @@@
  
  /*
   * RFCOMM TTY.
 - *
 - * $Id: tty.c,v 1.24 2002/10/03 01:54:38 holtmann Exp $
   */
  
  #include <linux/module.h>
@@@ -75,6 -77,8 +75,8 @@@ struct rfcomm_dev 
        struct device           *tty_dev;
  
        atomic_t                wmem_alloc;
+       struct sk_buff_head     pending;
  };
  
  static LIST_HEAD(rfcomm_dev_list);
@@@ -262,13 -266,34 +264,34 @@@ static int rfcomm_dev_add(struct rfcomm
        init_waitqueue_head(&dev->wait);
        tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
  
+       skb_queue_head_init(&dev->pending);
        rfcomm_dlc_lock(dlc);
+       if (req->flags & (1 << RFCOMM_REUSE_DLC)) {
+               struct sock *sk = dlc->owner;
+               struct sk_buff *skb;
+               BUG_ON(!sk);
+               rfcomm_dlc_throttle(dlc);
+               while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
+                       skb_orphan(skb);
+                       skb_queue_tail(&dev->pending, skb);
+                       atomic_sub(skb->len, &sk->sk_rmem_alloc);
+               }
+       }
        dlc->data_ready   = rfcomm_dev_data_ready;
        dlc->state_change = rfcomm_dev_state_change;
        dlc->modem_status = rfcomm_dev_modem_status;
  
        dlc->owner = dev;
        dev->dlc   = dlc;
+       rfcomm_dev_modem_status(dlc, dlc->remote_v24_sig);
        rfcomm_dlc_unlock(dlc);
  
        /* It's safe to call __module_get() here because socket already
@@@ -537,11 -562,16 +560,16 @@@ static void rfcomm_dev_data_ready(struc
        struct rfcomm_dev *dev = dlc->owner;
        struct tty_struct *tty;
  
-       if (!dev || !(tty = dev->tty)) {
+       if (!dev) {
                kfree_skb(skb);
                return;
        }
  
+       if (!(tty = dev->tty) || !skb_queue_empty(&dev->pending)) {
+               skb_queue_tail(&dev->pending, skb);
+               return;
+       }
        BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
  
        tty_insert_flip_string(tty, skb->data, skb->len);
@@@ -625,6 -655,30 +653,30 @@@ static void rfcomm_tty_wakeup(unsigned 
  #endif
  }
  
+ static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
+ {
+       struct tty_struct *tty = dev->tty;
+       struct sk_buff *skb;
+       int inserted = 0;
+       if (!tty)
+               return;
+       BT_DBG("dev %p tty %p", dev, tty);
+       rfcomm_dlc_lock(dev->dlc);
+       while ((skb = skb_dequeue(&dev->pending))) {
+               inserted += tty_insert_flip_string(tty, skb->data, skb->len);
+               kfree_skb(skb);
+       }
+       rfcomm_dlc_unlock(dev->dlc);
+       if (inserted > 0)
+               tty_flip_buffer_push(tty);
+ }
  static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
  {
        DECLARE_WAITQUEUE(wait, current);
        if (err == 0)
                device_move(dev->tty_dev, rfcomm_get_device(dev));
  
+       rfcomm_tty_copy_pending(dev);
+       rfcomm_dlc_unthrottle(dev->dlc);
        return err;
  }
  
@@@ -1121,6 -1179,7 +1177,7 @@@ int rfcomm_init_ttys(void
        rfcomm_tty_driver->flags        = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        rfcomm_tty_driver->init_termios = tty_std_termios;
        rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
        tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
  
        if (tty_register_driver(rfcomm_tty_driver)) {