2009-04-30 01:44:44

by Nathan Holstein

[permalink] [raw]
Subject: [PATCH] Add #defines and data structures for enhanced L2CAP

From: Nathan Holstein <[email protected]>

This patch #defines many constants used for implementation of Enhanced
Retranmission and Streaming modes within L2CAP.

This also adds the necessary members to the socket data structures to support
the additional modes.
---
include/net/bluetooth/bluetooth.h | 3 +-
include/net/bluetooth/l2cap.h | 118 ++++++++++++++++++++++++++++++++++---
net/bluetooth/l2cap.c | 17 ++++-
3 files changed, 124 insertions(+), 14 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 3ad5390..f532e2d 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -144,8 +144,9 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
struct bt_skb_cb {
__u8 pkt_type;
__u8 incoming;
+ __u8 tx_seq;
};
-#define bt_cb(skb) ((struct bt_skb_cb *)(skb->cb))
+#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))

static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
{
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 300b63f..3770fb6 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -1,4 +1,4 @@
-/*
+/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated

@@ -12,13 +12,13 @@
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/

@@ -26,12 +26,29 @@
#define __L2CAP_H

/* L2CAP defaults */
-#define L2CAP_DEFAULT_MTU 672
-#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
+#define L2CAP_DEFAULT_MTU 672
+#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
+#define L2CAP_DEFAULT_RX_WINDOW 1
+#define L2CAP_DEFAULT_MAX_RECEIVE 1
+#define L2CAP_DEFAULT_RETRANS_TIMEOUT 300 /* 300 milliseconds */
+#define L2CAP_DEFAULT_MONITOR_TIMEOUT 1000 /* 1 second */
+#define L2CAP_DEFAULT_MAX_RX_APDU 0xFFF7

#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */

+#define L2CAP_FCS_GENERATOR ((u16)0xA001)
+
+/* L2CAP feature bits */
+#define L2CAP_FEATURE_FLOW 0x00000001
+#define L2CAP_FEATURE_RETRANS 0x00000002
+#define L2CAP_FEATURE_QOS 0x00000004
+#define L2CAP_FEATURE_E_RETRANS 0x00000008
+#define L2CAP_FEATURE_STREAM 0x00000010
+#define L2CAP_FEATURE_FCS 0x00000020
+#define L2CAP_FEATURE_FIX_CHAN 0x00000080
+#define L2CAP_FEATURE_RESERVED 0x80000000
+
/* L2CAP socket address */
struct sockaddr_l2 {
sa_family_t l2_family;
@@ -76,6 +93,66 @@ struct l2cap_conninfo {
#define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFO_RSP 0x0b

+/* L2CAP Control Field bit masks */
+#define L2CAP_CONTROL_SAR_MASK 0xC000
+#define L2CAP_CONTROL_REQSEQ_MASK 0x3F00
+#define L2CAP_CONTROL_TXSEQ_MASK 0x007E
+#define L2CAP_CONTROL_RETRANS_MASK 0x0080
+#define L2CAP_CONTROL_FINAL_MASK 0x0080
+#define L2CAP_CONTROL_POLL_MASK 0x0010
+#define L2CAP_CONTROL_SUPERVISE_MASK 0x000C
+#define L2CAP_CONTROL_TYPE_MASK 0x0001 /* I- or S-Frame */
+
+#define L2CAP_CONTROL_TXSEQ_SHIFT 1
+#define L2CAP_CONTROL_REQSEQ_SHIFT 8
+
+#define L2CAP_SEQ_NUM_INC(seq) ((seq) = (seq + 1) % 64)
+
+static inline u8 l2cap_control_txseq(u16 control)
+{
+ return (control & L2CAP_CONTROL_TXSEQ_MASK) >>
+ L2CAP_CONTROL_TXSEQ_SHIFT;
+}
+
+static inline u8 l2cap_control_reqseq(u16 control)
+{
+ return (control & L2CAP_CONTROL_REQSEQ_MASK) >>
+ L2CAP_CONTROL_REQSEQ_SHIFT;
+}
+
+static inline u16 l2cap_txseq_to_reqseq(u16 control)
+{
+ return (control & L2CAP_CONTROL_TXSEQ_MASK) <<
+ (L2CAP_CONTROL_REQSEQ_SHIFT - L2CAP_CONTROL_TXSEQ_SHIFT);
+}
+
+static inline int l2cap_is_I_frame(u16 control)
+{
+ return !(control & L2CAP_CONTROL_TYPE_MASK);
+}
+
+static inline int l2cap_is_S_frame(u16 control)
+{
+ return (control & L2CAP_CONTROL_TYPE_MASK);
+}
+
+/* L2CAP Segmentation and Reassembly */
+#define L2CAP_SAR_UNSEGMENTED 0x0000
+#define L2CAP_SAR_SDU_START 0x4000
+#define L2CAP_SAR_SDU_END 0x8000
+#define L2CAP_SAR_SDU_CONTINUE 0xC000
+
+/* L2CAP Supervisory Function */
+#define L2CAP_SUPER_RCV_READY 0x0000
+#define L2CAP_SUPER_REJECT 0x0004
+#define L2CAP_SUPER_RCV_NOT_READY 0x0008
+#define L2CAP_SUPER_SELECT_REJECT 0x000C
+
+/* L2CAP Optional FCS */
+#define L2CAP_FCS_DISABLE 0x00
+#define L2CAP_FCS_ENABLE 0x01
+#define L2CAP_FCS_DEFAULT L2CAP_FCS_ENABLE
+
/* L2CAP structures */
struct l2cap_hdr {
__le16 len;
@@ -149,12 +226,14 @@ struct l2cap_conf_opt {
} __attribute__ ((packed));
#define L2CAP_CONF_OPT_SIZE 2

-#define L2CAP_CONF_HINT 0x80
+#define L2CAP_CONF_HINT ((u8)0x80)
+#define L2CAP_CONF_MIN_MTU 48

#define L2CAP_CONF_MTU 0x01
#define L2CAP_CONF_FLUSH_TO 0x02
#define L2CAP_CONF_QOS 0x03
#define L2CAP_CONF_RFC 0x04
+#define L2CAP_CONF_FCS 0x05

#define L2CAP_CONF_MAX_SIZE 22

@@ -170,6 +249,8 @@ struct l2cap_conf_rfc {
#define L2CAP_MODE_BASIC 0x00
#define L2CAP_MODE_RETRANS 0x01
#define L2CAP_MODE_FLOWCTL 0x02
+#define L2CAP_MODE_ENH_RETRANS 0x03
+#define L2CAP_MODE_STREAMING 0x04

struct l2cap_disconn_req {
__le16 dcid;
@@ -259,10 +340,29 @@ struct l2cap_pinfo {
__u8 conf_state;
__u8 conf_retry;

+ __u8 tx_seq;
+ __u8 req_seq;
+
+ __u8 fcs;
+
__u8 ident;

__le16 sport;

+ __u8 mode;
+ __u8 txwin_size;
+ __u8 remote_tx_win;
+ __u8 remote_max_tx;
+ __u16 retrans_timeout;
+ __u16 monitor_timeout;
+ __u16 max_pdu_size;
+
+ __u16 sdu_next;
+ __u16 sdu_len;
+
+ struct timer_list retrans_timer;
+ struct timer_list monitor_timer;
+ struct sk_buff *tx_buf;
struct l2cap_conn *conn;
struct sock *next_c;
struct sock *prev_c;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index f6a82f2..31b1cbc 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -52,7 +52,8 @@

#define VERSION "2.13"

-static u32 l2cap_feat_mask = 0x0080;
+static u32 l2cap_feat_mask =
+ L2CAP_FEATURE_FIX_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, };

static const struct proto_ops l2cap_sock_ops;
@@ -718,12 +719,20 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->sec_level = l2cap_pi(parent)->sec_level;
pi->role_switch = l2cap_pi(parent)->role_switch;
pi->force_reliable = l2cap_pi(parent)->force_reliable;
+ pi->fcs = l2cap_pi(parent)->fcs;
+ pi->mode = l2cap_pi(parent)->mode;
} else {
pi->imtu = L2CAP_DEFAULT_MTU;
pi->omtu = 0;
pi->sec_level = BT_SECURITY_LOW;
pi->role_switch = 0;
pi->force_reliable = 0;
+ pi->fcs = L2CAP_FCS_DEFAULT;
+ if (sk->sk_type == SOCK_STREAM)
+ pi->mode = L2CAP_MODE_ENH_RETRANS;
+ else
+ pi->mode = L2CAP_MODE_BASIC;
+
}

/* Default config options */
@@ -770,7 +779,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol)

sock->state = SS_UNCONNECTED;

- if (sock->type != SOCK_SEQPACKET &&
+ if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;

@@ -1747,7 +1756,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
len -= l2cap_get_conf_opt(&req, &type, &olen, &val);

hint = type & L2CAP_CONF_HINT;
- type &= 0x7f;
+ type &= ~L2CAP_CONF_HINT;

switch (type) {
case L2CAP_CONF_MTU:
@@ -2244,7 +2253,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
if (type == L2CAP_IT_FEAT_MASK) {
conn->feat_mask = get_unaligned_le32(rsp->data);

- if (conn->feat_mask & 0x0080) {
+ if (conn->feat_mask & L2CAP_FEATURE_FIX_CHAN) {
struct l2cap_info_req req;
req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);

--
1.6.0.6



2009-04-30 02:18:51

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH] Add #defines and data structures for enhanced L2CAP

Hi Nathan,

> This patch #defines many constants used for implementation of Enhanced
> Retranmission and Streaming modes within L2CAP.
>
> This also adds the necessary members to the socket data structures to support
> the additional modes.

please don't mix them up. These are different. I want the constants
going in first.

> ---
> include/net/bluetooth/bluetooth.h | 3 +-
> include/net/bluetooth/l2cap.h | 118 ++++++++++++++++++++++++++++++++++---
> net/bluetooth/l2cap.c | 17 ++++-
> 3 files changed, 124 insertions(+), 14 deletions(-)
>
> diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
> index 3ad5390..f532e2d 100644
> --- a/include/net/bluetooth/bluetooth.h
> +++ b/include/net/bluetooth/bluetooth.h
> @@ -144,8 +144,9 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
> struct bt_skb_cb {
> __u8 pkt_type;
> __u8 incoming;
> + __u8 tx_seq;
> };
> -#define bt_cb(skb) ((struct bt_skb_cb *)(skb->cb))
> +#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
>
> static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
> {
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 300b63f..3770fb6 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -1,4 +1,4 @@
> -/*
> +/*
> BlueZ - Bluetooth protocol stack for Linux
> Copyright (C) 2000-2001 Qualcomm Incorporated
>
> @@ -12,13 +12,13 @@
> OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
> IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
> - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
> - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
> + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>
> - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
> - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
> + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
> + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
> SOFTWARE IS DISCLAIMED.
> */

Don't touch this. If copyright header needs changing I will do it and
will do in a separate patch.

> @@ -26,12 +26,29 @@
> #define __L2CAP_H
>
> /* L2CAP defaults */
> -#define L2CAP_DEFAULT_MTU 672
> -#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
> +#define L2CAP_DEFAULT_MTU 672
> +#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
> +#define L2CAP_DEFAULT_RX_WINDOW 1
> +#define L2CAP_DEFAULT_MAX_RECEIVE 1
> +#define L2CAP_DEFAULT_RETRANS_TIMEOUT 300 /* 300 milliseconds */
> +#define L2CAP_DEFAULT_MONITOR_TIMEOUT 1000 /* 1 second */
> +#define L2CAP_DEFAULT_MAX_RX_APDU 0xFFF7

call it RETRANS_TO and MONITOR_TO to make it similar for FLUSH_TO.

> +#define L2CAP_FCS_GENERATOR ((u16)0xA001)
> +

Not needed since we should use the kernel FCS stuff.

> +/* L2CAP feature bits */
> +#define L2CAP_FEATURE_FLOW 0x00000001
> +#define L2CAP_FEATURE_RETRANS 0x00000002
> +#define L2CAP_FEATURE_QOS 0x00000004
> +#define L2CAP_FEATURE_E_RETRANS 0x00000008
> +#define L2CAP_FEATURE_STREAM 0x00000010
> +#define L2CAP_FEATURE_FCS 0x00000020
> +#define L2CAP_FEATURE_FIX_CHAN 0x00000080
> +#define L2CAP_FEATURE_RESERVED 0x80000000

I prefer if we only list the features we are going to support. So I like
to have them named like this:

L2CAP_FEAT_ERTM
L2CAP_FEAT_STREAM
L2CAP_FEAT_FCS
L2CAP_FEAT_FIXED_CHAN

> +
> /* L2CAP socket address */
> struct sockaddr_l2 {
> sa_family_t l2_family;
> @@ -76,6 +93,66 @@ struct l2cap_conninfo {
> #define L2CAP_INFO_REQ 0x0a
> #define L2CAP_INFO_RSP 0x0b
>
> +/* L2CAP Control Field bit masks */
> +#define L2CAP_CONTROL_SAR_MASK 0xC000
> +#define L2CAP_CONTROL_REQSEQ_MASK 0x3F00
> +#define L2CAP_CONTROL_TXSEQ_MASK 0x007E
> +#define L2CAP_CONTROL_RETRANS_MASK 0x0080
> +#define L2CAP_CONTROL_FINAL_MASK 0x0080
> +#define L2CAP_CONTROL_POLL_MASK 0x0010
> +#define L2CAP_CONTROL_SUPERVISE_MASK 0x000C
> +#define L2CAP_CONTROL_TYPE_MASK 0x0001 /* I- or S-Frame */
> +
> +#define L2CAP_CONTROL_TXSEQ_SHIFT 1
> +#define L2CAP_CONTROL_REQSEQ_SHIFT 8
> +
> +#define L2CAP_SEQ_NUM_INC(seq) ((seq) = (seq + 1) % 64)
> +
> +static inline u8 l2cap_control_txseq(u16 control)
> +{
> + return (control & L2CAP_CONTROL_TXSEQ_MASK) >>
> + L2CAP_CONTROL_TXSEQ_SHIFT;
> +}
> +
> +static inline u8 l2cap_control_reqseq(u16 control)
> +{
> + return (control & L2CAP_CONTROL_REQSEQ_MASK) >>
> + L2CAP_CONTROL_REQSEQ_SHIFT;
> +}
> +
> +static inline u16 l2cap_txseq_to_reqseq(u16 control)
> +{
> + return (control & L2CAP_CONTROL_TXSEQ_MASK) <<
> + (L2CAP_CONTROL_REQSEQ_SHIFT - L2CAP_CONTROL_TXSEQ_SHIFT);
> +}
> +
> +static inline int l2cap_is_I_frame(u16 control)
> +{
> + return !(control & L2CAP_CONTROL_TYPE_MASK);
> +}
> +
> +static inline int l2cap_is_S_frame(u16 control)
> +{
> + return (control & L2CAP_CONTROL_TYPE_MASK);
> +}
> +
> +/* L2CAP Segmentation and Reassembly */
> +#define L2CAP_SAR_UNSEGMENTED 0x0000
> +#define L2CAP_SAR_SDU_START 0x4000
> +#define L2CAP_SAR_SDU_END 0x8000
> +#define L2CAP_SAR_SDU_CONTINUE 0xC000
> +
> +/* L2CAP Supervisory Function */
> +#define L2CAP_SUPER_RCV_READY 0x0000
> +#define L2CAP_SUPER_REJECT 0x0004
> +#define L2CAP_SUPER_RCV_NOT_READY 0x0008
> +#define L2CAP_SUPER_SELECT_REJECT 0x000C

I want these in a a separate patch.
+
> +/* L2CAP Optional FCS */
> +#define L2CAP_FCS_DISABLE 0x00
> +#define L2CAP_FCS_ENABLE 0x01
> +#define L2CAP_FCS_DEFAULT L2CAP_FCS_ENABLE

This is actually L2CAP_FCS_NONE, L2CAP_FCS_CRC16. It is defined in a way
that it could be extended with other FCS.

> +
> /* L2CAP structures */
> struct l2cap_hdr {
> __le16 len;
> @@ -149,12 +226,14 @@ struct l2cap_conf_opt {
> } __attribute__ ((packed));
> #define L2CAP_CONF_OPT_SIZE 2
>
> -#define L2CAP_CONF_HINT 0x80
> +#define L2CAP_CONF_HINT ((u8)0x80)
> +#define L2CAP_CONF_MIN_MTU 48

Non of these should be needed right now. Especially the (u8) is unclear
to me.

> #define L2CAP_CONF_MTU 0x01
> #define L2CAP_CONF_FLUSH_TO 0x02
> #define L2CAP_CONF_QOS 0x03
> #define L2CAP_CONF_RFC 0x04
> +#define L2CAP_CONF_FCS 0x05
>
> #define L2CAP_CONF_MAX_SIZE 22
>
> @@ -170,6 +249,8 @@ struct l2cap_conf_rfc {
> #define L2CAP_MODE_BASIC 0x00
> #define L2CAP_MODE_RETRANS 0x01
> #define L2CAP_MODE_FLOWCTL 0x02
> +#define L2CAP_MODE_ENH_RETRANS 0x03
> +#define L2CAP_MODE_STREAMING 0x04

Name this MODE_ERTM and MODE_STREAM to match FEAT_*.

> struct l2cap_disconn_req {
> __le16 dcid;
> @@ -259,10 +340,29 @@ struct l2cap_pinfo {
> __u8 conf_state;
> __u8 conf_retry;
>
> + __u8 tx_seq;
> + __u8 req_seq;
> +
> + __u8 fcs;
> +
> __u8 ident;
>
> __le16 sport;
>
> + __u8 mode;
> + __u8 txwin_size;
> + __u8 remote_tx_win;
> + __u8 remote_max_tx;
> + __u16 retrans_timeout;
> + __u16 monitor_timeout;
> + __u16 max_pdu_size;
> +
> + __u16 sdu_next;
> + __u16 sdu_len;
> +
> + struct timer_list retrans_timer;
> + struct timer_list monitor_timer;
> + struct sk_buff *tx_buf;
> struct l2cap_conn *conn;
> struct sock *next_c;
> struct sock *prev_c;

Separate patch.

> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
> index f6a82f2..31b1cbc 100644
> --- a/net/bluetooth/l2cap.c
> +++ b/net/bluetooth/l2cap.c
> @@ -52,7 +52,8 @@
>
> #define VERSION "2.13"
>
> -static u32 l2cap_feat_mask = 0x0080;
> +static u32 l2cap_feat_mask =
> + L2CAP_FEATURE_FIX_CHAN;

Put in on the same line please.

> static u8 l2cap_fixed_chan[8] = { 0x02, };
>
> static const struct proto_ops l2cap_sock_ops;
> @@ -718,12 +719,20 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
> pi->sec_level = l2cap_pi(parent)->sec_level;
> pi->role_switch = l2cap_pi(parent)->role_switch;
> pi->force_reliable = l2cap_pi(parent)->force_reliable;
> + pi->fcs = l2cap_pi(parent)->fcs;
> + pi->mode = l2cap_pi(parent)->mode;
> } else {
> pi->imtu = L2CAP_DEFAULT_MTU;
> pi->omtu = 0;
> pi->sec_level = BT_SECURITY_LOW;
> pi->role_switch = 0;
> pi->force_reliable = 0;
> + pi->fcs = L2CAP_FCS_DEFAULT;
> + if (sk->sk_type == SOCK_STREAM)
> + pi->mode = L2CAP_MODE_ENH_RETRANS;
> + else
> + pi->mode = L2CAP_MODE_BASIC;
> +
> }

Separate patch.

> /* Default config options */
> @@ -770,7 +779,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol)
>
> sock->state = SS_UNCONNECTED;
>
> - if (sock->type != SOCK_SEQPACKET &&
> + if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
> sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
> return -ESOCKTNOSUPPORT;

we can not do that right now. This will break proper bi-section.

> @@ -1747,7 +1756,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
> len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
>
> hint = type & L2CAP_CONF_HINT;
> - type &= 0x7f;
> + type &= ~L2CAP_CONF_HINT;

Using something like L2CAP_CONF_MASK is way better here.

> switch (type) {
> case L2CAP_CONF_MTU:
> @@ -2244,7 +2253,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
> if (type == L2CAP_IT_FEAT_MASK) {
> conn->feat_mask = get_unaligned_le32(rsp->data);
>
> - if (conn->feat_mask & 0x0080) {
> + if (conn->feat_mask & L2CAP_FEATURE_FIX_CHAN) {
> struct l2cap_info_req req;
> req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
>

Regards

Marcel



2009-04-30 01:44:45

by Nathan Holstein

[permalink] [raw]
Subject: [PATCH] Reassemble segmented L2CAP PDUs upon reception

From: Nathan Holstein <[email protected]>

When configured in Enhanced Retransmission of Streaming modes, data sent over
L2CAP can be broken up into multiple L2CAP SDUs. This patch adds support for
reassembling these packets upon reception.
---
net/bluetooth/l2cap.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 6328fb8..7505137 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2595,6 +2595,43 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct l2cap_hdr *lh, struct
return 0;
}

+static int l2cap_check_sar(struct l2cap_pinfo *pi, u16 control, struct sk_buff *skb)
+{
+ u16 mask = control & L2CAP_CONTROL_SAR_MASK;
+
+ switch (mask)
+ {
+ case L2CAP_SAR_UNSEGMENTED:
+ if (pi->sdu_next != 0)
+ return -1;
+ break;
+
+ case L2CAP_SAR_SDU_START:
+ if (pi->sdu_next != 0 || skb->len < 2)
+ return -1;
+ pi->sdu_next = 1;
+ pi->sdu_len = get_unaligned((__le16 *) skb->data);
+ skb_pull(skb, 2);
+ break;
+
+ case L2CAP_SAR_SDU_CONTINUE:
+ if (pi->sdu_next >= pi->sdu_len)
+ return -1;
+ ++pi->sdu_next;
+ break;
+
+ case L2CAP_SAR_SDU_END:
+ /* TODO:
+ * How do we correctly signal MSG_EOR? */
+ if (pi->sdu_next != pi->sdu_len)
+ return -1;
+ pi->sdu_next = pi->sdu_len = 0;
+ break;
+ }
+
+ return 0;
+}
+
static inline int l2cap_data_channel_i_frame(struct sock *sk, u16 rx_control, struct sk_buff *skb)
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -2614,6 +2651,17 @@ static inline int l2cap_data_channel_i_frame(struct sock *sk, u16 rx_control, st
L2CAP_SEQ_NUM_INC(pi->req_seq);
tx_control = pi->req_seq << L2CAP_CONTROL_REQSEQ_SHIFT;

+ /* TODO:
+ * l2cap_check_sar() call side effects! After calling this function,
+ * we can't reject the SDU without possibly screwing up reassembly.
+ * We need to ensure the sequence number is correct, and that we can
+ * queue the skb before calling l2cap_check_sar(). */
+ if (l2cap_check_sar(pi, rx_control, skb)) {
+ tx_control |= L2CAP_SUPER_REJECT;
+ err = -1;
+ goto respond;
+ }
+
if ((err = sock_queue_rcv_skb(sk, skb))) {
tx_control |= L2CAP_SUPER_RCV_NOT_READY;
goto respond;
@@ -2694,6 +2742,11 @@ static int l2cap_data_channel_streaming(struct sock *sk, struct l2cap_hdr *lh, s
control = get_unaligned((__le16 *) skb->data);
skb_pull(skb, 2);

+ /* Todo:
+ * is this the proper behavior? */
+ if (l2cap_is_I_frame(control) && l2cap_check_sar(pi, control, skb))
+ return -1;
+
if (!sock_queue_rcv_skb(sk, skb))
return -1;

--
1.6.0.6