aboutsummaryrefslogtreecommitdiff
path: root/net/bluetooth/rfcomm/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-07-20 17:43:29 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-20 17:43:29 -0700
commitdb6d8c7a4027b48d797b369a53f8470aaeed7063 (patch)
treee140c104a89abc2154e1f41a7db8ebecbb6fa0b4 /net/bluetooth/rfcomm/core.c
parent3a533374283aea50eab3976d8a6d30532175f009 (diff)
parentfb65a7c091529bfffb1262515252c0d0f6241c5c (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (1232 commits) iucv: Fix bad merging. net_sched: Add size table for qdiscs net_sched: Add accessor function for packet length for qdiscs net_sched: Add qdisc_enqueue wrapper highmem: Export totalhigh_pages. ipv6 mcast: Omit redundant address family checks in ip6_mc_source(). net: Use standard structures for generic socket address structures. ipv6 netns: Make several "global" sysctl variables namespace aware. netns: Use net_eq() to compare net-namespaces for optimization. ipv6: remove unused macros from net/ipv6.h ipv6: remove unused parameter from ip6_ra_control tcp: fix kernel panic with listening_get_next tcp: Remove redundant checks when setting eff_sacks tcp: options clean up tcp: Fix MD5 signatures for non-linear skbs sctp: Update sctp global memory limit allocations. sctp: remove unnecessary byteshifting, calculate directly in big-endian sctp: Allow only 1 listening socket with SO_REUSEADDR sctp: Do not leak memory on multiple listen() calls sctp: Support ipv6only AF_INET6 sockets. ...
Diffstat (limited to 'net/bluetooth/rfcomm/core.c')
-rw-r--r--net/bluetooth/rfcomm/core.c94
1 files changed, 60 insertions, 34 deletions
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 0c2c93735e9..6cfc7ba611b 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -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>
@@ -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;
@@ -230,6 +228,21 @@ static int rfcomm_l2sock_create(struct socket **sock)
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)
{
@@ -371,15 +384,23 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
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;
}
@@ -1146,21 +1167,6 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
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;
@@ -1205,10 +1211,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
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;
}
@@ -1223,10 +1227,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
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);
}
@@ -1459,8 +1461,12 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
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);
@@ -1636,7 +1642,11 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
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);
}
}
}
@@ -1709,7 +1719,11 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
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);
@@ -1717,7 +1731,10 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
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;
}
@@ -1726,7 +1743,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
continue;
if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
- d->mscex == RFCOMM_MSCEX_OK)
+ d->mscex == RFCOMM_MSCEX_OK)
rfcomm_process_tx(d);
}
}
@@ -1954,7 +1971,8 @@ static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status)
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))
@@ -1988,6 +2006,14 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
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;