Hi Marcel, I spend most of the day reworking the sniff mode patch. I implemented both L2CAP and RFCOMM, and tested those two. They both seem to work. The layering violation is gone. The setting is propagated from a server socket to its children. I think i've seen the end of your first round of comments ;-) Could you please review this patch and tell me what needs fixing ? Regards, Fabien
>From 1252afa5d458cd4782ee767ff1e487a6ce56c964 Mon Sep 17 00:00:00 2001 From: Fabien Chevalier <fabchevalier@xxxxxxx> Date: Sun, 14 Sep 2008 20:52:08 +0200 Subject: [PATCH] Sniff mode fixes V2. * Introduces L2CAP_FORCE_ACTIVE_MODE and RFCOMM_FORCE_ACTIVE_MODE. * Support for RFCOMM and L2CAP. * Setting is now inherited on child sockets created through accept() --- include/net/bluetooth/hci_core.h | 3 ++- include/net/bluetooth/l2cap.h | 5 +++++ include/net/bluetooth/rfcomm.h | 3 +++ net/bluetooth/hci_conn.c | 6 +++++- net/bluetooth/hci_core.c | 4 +++- net/bluetooth/l2cap.c | 38 ++++++++++++++++++++++++++++++++------ net/bluetooth/rfcomm/core.c | 13 +++++++++---- net/bluetooth/rfcomm/sock.c | 32 ++++++++++++++++++++++++++++++-- 8 files changed, 89 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 46a43b7..95f113e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -170,6 +170,7 @@ struct hci_conn { __u32 link_mode; __u8 auth_type; __u8 power_save; + __u8 force_active_mode; unsigned long pend; unsigned int sent; @@ -631,7 +632,7 @@ int hci_register_notifier(struct notifier_block *nb); int hci_unregister_notifier(struct notifier_block *nb); int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); -int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); +int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, int force_active_mode, __u16 flags); int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 73e115b..d13f586 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -62,6 +62,8 @@ struct l2cap_conninfo { #define L2CAP_LM_RELIABLE 0x0010 #define L2CAP_LM_SECURE 0x0020 +#define L2CAP_FORCE_ACTIVE_MODE 0x04 + /* L2CAP command codes */ #define L2CAP_COMMAND_REJ 0x01 #define L2CAP_CONN_REQ 0x02 @@ -210,6 +212,8 @@ struct l2cap_conn { __u8 info_state; __u8 info_ident; + int force_active_mode; + struct timer_list info_timer; spinlock_t lock; @@ -239,6 +243,7 @@ struct l2cap_pinfo { __u16 flush_to; __u32 link_mode; + int force_active_mode; __u8 conf_req[64]; __u8 conf_len; diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 4dc8d92..61bf1cf 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -185,6 +185,7 @@ struct rfcomm_dlc { u8 out; u32 link_mode; + int force_active_mode; uint mtu; uint cfc; @@ -298,6 +299,8 @@ struct rfcomm_conninfo { #define RFCOMM_LM_RELIABLE 0x0010 #define RFCOMM_LM_SECURE 0x0020 +#define RFCOMM_FORCE_ACTIVE_MODE 0x04 + #define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk) struct rfcomm_pinfo { diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b700242..a7feebd 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -214,6 +214,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->state = BT_OPEN; conn->power_save = 1; + conn->force_active_mode = 0; switch (type) { case ACL_LINK: @@ -479,9 +480,12 @@ void hci_conn_enter_active_mode(struct hci_conn *conn) if (test_bit(HCI_RAW, &hdev->flags)) return; - if (conn->mode != HCI_CM_SNIFF || !conn->power_save) + if (conn->mode != HCI_CM_SNIFF) goto timer; + if (!conn->power_save && !conn->force_active_mode) + goto timer; + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { struct hci_cp_exit_sniff_mode cp; cp.handle = cpu_to_le16(conn->handle); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f5b21cb..ec4b1ff 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1193,7 +1193,7 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags) hdr->dlen = cpu_to_le16(len); } -int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) +int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, int force_active_mode, __u16 flags) { struct hci_dev *hdev = conn->hdev; struct sk_buff *list; @@ -1234,6 +1234,8 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) spin_unlock_bh(&conn->data_q.lock); } + conn->force_active_mode = force_active_mode; + hci_sched_tx(hdev); return 0; } diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 9610a9c..7d422e9 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -304,12 +304,12 @@ static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 { struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); - BT_DBG("code 0x%2.2x", code); + BT_DBG("code 0x%2.2x active_mode %d ", code, conn->force_active_mode); if (!skb) return -ENOMEM; - return hci_send_acl(conn->hcon, skb, 0); + return hci_send_acl(conn->hcon, skb, conn->force_active_mode, 0); } static void l2cap_do_start(struct sock *sk) @@ -661,10 +661,13 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->imtu = l2cap_pi(parent)->imtu; pi->omtu = l2cap_pi(parent)->omtu; pi->link_mode = l2cap_pi(parent)->link_mode; + pi->force_active_mode = + l2cap_pi(parent)->force_active_mode; } else { pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; pi->link_mode = 0; + pi->force_active_mode = 0; } /* Default config options */ @@ -818,6 +821,8 @@ static int l2cap_do_connect(struct sock *sk) /* Update source addr of the socket */ bacpy(src, conn->src); + + conn->force_active_mode = l2cap_pi(sk)->force_active_mode; l2cap_chan_add(conn, sk, NULL); @@ -1021,7 +1026,7 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) int err, hlen, count, sent=0; struct l2cap_hdr *lh; - BT_DBG("sk %p len %d", sk, len); + BT_DBG("sk %p len %d active_mode %d", sk, len, conn->force_active_mode); /* First fragment (with L2CAP header) */ if (sk->sk_type == SOCK_DGRAM) @@ -1072,7 +1077,7 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) frag = &(*frag)->next; } - if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0) + if ((err = hci_send_acl(conn->hcon, skb, l2cap_pi(sk)->force_active_mode, 0)) < 0) goto fail; return sent; @@ -1148,6 +1153,20 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch l2cap_pi(sk)->link_mode = opt; break; + case L2CAP_FORCE_ACTIVE_MODE: + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + + l2cap_pi(sk)->force_active_mode = opt; + + if (sk->sk_state == BT_CONNECTED) { + l2cap_pi(sk)->conn->force_active_mode = opt; + } + + break; + default: err = -ENOPROTOOPT; break; @@ -1204,6 +1223,12 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; + case L2CAP_FORCE_ACTIVE_MODE: + if (put_user(l2cap_pi(sk)->force_active_mode, + (u32 __user *) optval)) + err = -EFAULT; + break; + default: err = -ENOPROTOOPT; break; @@ -2429,10 +2454,11 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf) sk_for_each(sk, node, &l2cap_sk_list.head) { struct l2cap_pinfo *pi = l2cap_pi(sk); - str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", + str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid, - pi->imtu, pi->omtu, pi->link_mode); + pi->imtu, pi->omtu, pi->link_mode, + pi->force_active_mode); } read_unlock_bh(&l2cap_sk_list.lock); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index ba537fa..888b431 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -80,7 +80,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr); static void rfcomm_process_connect(struct rfcomm_session *s); -static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err); +static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int force_active_mode, int *err); static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst); static void rfcomm_session_del(struct rfcomm_session *s); @@ -367,7 +367,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, s = rfcomm_session_get(src, dst); if (!s) { - s = rfcomm_session_create(src, dst, &err); + s = rfcomm_session_create(src, dst, d->force_active_mode, &err); if (!s) return err; } @@ -625,19 +625,24 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err) rfcomm_session_put(s); } -static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err) +static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int force_active_mode, int *err) { struct rfcomm_session *s = NULL; struct sockaddr_l2 addr; struct socket *sock; struct sock *sk; - BT_DBG("%s %s", batostr(src), batostr(dst)); + BT_DBG("%s %s %d", batostr(src), batostr(dst), force_active_mode); *err = rfcomm_l2sock_create(&sock); if (*err < 0) return NULL; + *err = kernel_setsockopt(sock, SOL_BLUETOOTH, L2CAP_FORCE_ACTIVE_MODE, + (void *) &force_active_mode, sizeof(force_active_mode)); + if (*err < 0) + goto failed; + bacpy(&addr.l2_bdaddr, src); addr.l2_family = AF_BLUETOOTH; addr.l2_psm = 0; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 8a972b6..f6a48e5 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -267,8 +267,11 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent) if (parent) { sk->sk_type = parent->sk_type; pi->link_mode = rfcomm_pi(parent)->link_mode; + pi->dlc->force_active_mode = + rfcomm_pi(parent)->dlc->force_active_mode; } else { pi->link_mode = 0; + pi->dlc->force_active_mode = 0; } pi->dlc->link_mode = pi->link_mode; @@ -735,6 +738,15 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c rfcomm_pi(sk)->link_mode = opt; break; + case RFCOMM_FORCE_ACTIVE_MODE: + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } + + rfcomm_pi(sk)->dlc->force_active_mode = opt; + break; + default: err = -ENOPROTOOPT; break; @@ -781,6 +793,12 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c break; + case RFCOMM_FORCE_ACTIVE_MODE: + if (put_user(rfcomm_pi(sk)->dlc->force_active_mode, + (u32 __user *) optval)) + err = -EFAULT; + break; + default: err = -ENOPROTOOPT; break; @@ -859,6 +877,8 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * struct sock *sk, *parent; bdaddr_t src, dst; int result = 0; + int err; + int force_active_mode; BT_DBG("session %p channel %d", s, channel); @@ -869,6 +889,13 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * if (!parent) return 0; + /* Propagate setting to children */ + force_active_mode = rfcomm_pi(parent)->dlc->force_active_mode; + err = kernel_setsockopt(s->sock, SOL_BLUETOOTH, L2CAP_FORCE_ACTIVE_MODE, + (void *) &force_active_mode, sizeof(force_active_mode)); + if (err < 0) + goto done; + /* Check for backlog size */ if (sk_acceptq_is_full(parent)) { BT_DBG("backlog full %d", parent->sk_ack_backlog); @@ -905,9 +932,10 @@ static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf) read_lock_bh(&rfcomm_sk_list.lock); sk_for_each(sk, node, &rfcomm_sk_list.head) { - str += sprintf(str, "%s %s %d %d\n", + str += sprintf(str, "%s %s %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, rfcomm_pi(sk)->channel); + sk->sk_state, rfcomm_pi(sk)->channel, + rfcomm_pi(sk)->dlc->force_active_mode); } read_unlock_bh(&rfcomm_sk_list.lock); -- 1.5.6.5