This allows to send l2cap configuration request by providing
'-o' option to l2test along with '-f' option to add destination CID.
e.g.,
l2test command format:
l2test -o -X <mode> -f <destination CID> -P <psm> <bd_addr>
---
lib/l2cap.h | 10 ++++
tools/l2test.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 167 insertions(+), 5 deletions(-)
diff --git a/lib/l2cap.h b/lib/l2cap.h
index 5ce94c4..85f3c80 100644
--- a/lib/l2cap.h
+++ b/lib/l2cap.h
@@ -235,6 +235,16 @@ typedef struct {
#define L2CAP_IR_NOTSUPP 0x0001
typedef struct {
+ uint8_t mode;
+ uint8_t txwin_size;
+ uint8_t max_transmit;
+ uint16_t retrans_timeout;
+ uint16_t monitor_timeout;
+ uint16_t max_pdu_size;
+} __attribute__ ((packed)) l2cap_conf_rfc ;
+#define L2CAP_CONF_RFC_SIZE 9
+
+typedef struct {
uint16_t psm;
uint16_t scid;
uint8_t id;
diff --git a/tools/l2test.c b/tools/l2test.c
index abe09c1..59500fb 100644
--- a/tools/l2test.c
+++ b/tools/l2test.c
@@ -69,9 +69,13 @@ enum {
LSENDRECV,
CSENDRECV,
INFOREQ,
+ CONFIGREQ,
PAIRING,
};
+#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
+#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
+
static unsigned char *buf;
/* Default mtu */
@@ -91,10 +95,11 @@ static int max_transmit = 3;
static long data_size = -1;
static long buffer_size = 2048;
-/* Default addr and psm and cid */
+/* Default addr, psm, cid and dcid */
static bdaddr_t bdaddr;
static unsigned short psm = 0;
static unsigned short cid = 0;
+static uint16_t dcid = 0;
/* Default number of frames to send (-1 = infinite) */
static int num_frames = -1;
@@ -1245,6 +1250,138 @@ failed:
close(sk);
}
+static void l2cap_add_conf_opt(void **ptr, uint8_t type,
+ uint8_t len, unsigned long val)
+{
+ l2cap_conf_opt *opt = *ptr;
+
+ printf("type 0x%2.2x len %u val 0x%lx \n", type, len, val);
+
+ opt->type = htobs(type);
+ opt->len = htobs(len);
+
+ switch (opt->len) {
+ case 1:
+ *((uint8_t *) opt->val) = val;
+ break;
+ case 2:
+ bt_put_le16(val, opt->val);
+ break;
+ case 4:
+ bt_put_le32(val, opt->val);
+ break;
+ default:
+ memcpy(opt->val, (void *) val, len);
+ break;
+ }
+
+ *ptr += L2CAP_CONF_OPT_SIZE + len;
+}
+
+static int l2cap_build_conf_req(void *data)
+{
+ l2cap_conf_req *req = data;
+ l2cap_conf_rfc rfc;
+ void *ptr = req->data;
+
+ req->dcid = htobs(dcid);
+ req->flags = htobs(0x0000);
+
+ switch (rfcmode) {
+ case L2CAP_MODE_BASIC:
+ rfc.mode = htobs(L2CAP_MODE_BASIC);
+ rfc.txwin_size = htobs(0);
+ rfc.max_transmit = htobs(0);
+ rfc.retrans_timeout = htobs(0);
+ rfc.monitor_timeout = htobs(0);
+ rfc.max_pdu_size = htobs(0);
+
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+ (unsigned long) &rfc);
+
+ break;
+
+ case L2CAP_MODE_ERTM:
+ rfc.mode = htobs(L2CAP_MODE_ERTM);
+ rfc.txwin_size = htobs(txwin_size);
+ rfc.max_transmit = htobs(max_transmit);
+ rfc.retrans_timeout = htobs(L2CAP_DEFAULT_RETRANS_TO);
+ rfc.monitor_timeout = htobs(L2CAP_DEFAULT_MONITOR_TO);
+ rfc.max_pdu_size = htobs(imtu);
+
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+ (unsigned long) &rfc);
+ break;
+
+ case L2CAP_MODE_STREAMING:
+ rfc.mode = htobs(L2CAP_MODE_STREAMING);
+ rfc.txwin_size = htobs(txwin_size);
+ rfc.max_transmit = htobs(max_transmit);
+ rfc.retrans_timeout = htobs(L2CAP_DEFAULT_RETRANS_TO);
+ rfc.monitor_timeout = htobs(L2CAP_DEFAULT_MONITOR_TO);
+ rfc.max_pdu_size = htobs(imtu);
+
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+ (unsigned long) &rfc);
+
+ break;
+ default:
+ return L2CAP_CONF_REQ_SIZE;
+ }
+
+ return (ptr - data);
+}
+
+static void config_request(char *svr)
+{
+ unsigned char buf[48];
+ l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
+ uint8_t *req_buf = (uint8_t *) (buf + L2CAP_CMD_HDR_SIZE);
+ struct sockaddr_l2 addr;
+ int sk;
+ int data_len = 0;
+
+ sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
+ if (sk < 0) {
+ perror("Can't create socket");
+ return;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, &bdaddr);
+ addr.l2_bdaddr_type = bdaddr_type;
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Can't bind socket");
+ goto failed;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ str2ba(svr, &addr.l2_bdaddr);
+ addr.l2_bdaddr_type = bdaddr_type;
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Can't connect socket");
+ goto failed;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ cmd->code = L2CAP_CONF_REQ;
+ cmd->ident = 141;
+ data_len = l2cap_build_conf_req(req_buf);
+ cmd->len = htobs(data_len);
+
+ if (send(sk, buf, L2CAP_CMD_HDR_SIZE + data_len, 0) < 0) {
+ perror("Can't send info request");
+ goto failed;
+ }
+
+failed:
+ close(sk);
+}
+
static void do_pairing(char *svr)
{
struct sockaddr_l2 addr;
@@ -1311,7 +1448,8 @@ static void usage(void)
"\t-c connect, disconnect, connect, ...\n"
"\t-m multiple connects\n"
"\t-p trigger dedicated bonding\n"
- "\t-z information request\n");
+ "\t-z information request\n"
+ "\t-o configuration request\n");
printf("Options:\n"
"\t[-b bytes] [-i device] [-P psm] [-J cid]\n"
@@ -1340,7 +1478,7 @@ static void usage(void)
"\t[-M] become master\n"
"\t[-T] enable timestamps\n"
"\t[-V type] address type (help for list, default = bredr)\n"
- "\t[-e seq] initial sequence value (default = 0)\n");
+ "\t[-e DCID] Destination CID\n");
}
int main(int argc, char *argv[])
@@ -1350,8 +1488,8 @@ int main(int argc, char *argv[])
bacpy(&bdaddr, BDADDR_ANY);
- while ((opt = getopt(argc, argv, "a:b:cde:g:i:mnpqrstuwxyz"
- "AB:C:D:EF:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) != EOF) {
+ while ((opt = getopt(argc, argv, "a:b:cde:g:i:mnopqrstuwxyz"
+ "AB:C:D:EFf:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) != EOF) {
switch (opt) {
case 'r':
mode = RECV;
@@ -1412,6 +1550,11 @@ int main(int argc, char *argv[])
need_addr = 1;
break;
+ case 'o':
+ mode = CONFIGREQ;
+ need_addr = 1;
+ break;
+
case 'p':
mode = PAIRING;
need_addr = 1;
@@ -1565,6 +1708,11 @@ int main(int argc, char *argv[])
disc_delay = atoi(optarg) * 1000;
break;
+ case 'f':
+ dcid = strtoul(optarg, NULL, 16);
+ printf("dcid 0x%2x", dcid);
+ break;
+
default:
usage();
exit(1);
@@ -1666,6 +1814,10 @@ int main(int argc, char *argv[])
info_request(argv[optind]);
exit(0);
+ case CONFIGREQ:
+ config_request(argv[optind]);
+ exit(0);
+
case PAIRING:
do_pairing(argv[optind]);
exit(0);
--
1.9.1
Hi Luiz,
> -----Original Message-----
> From: [email protected] [mailto:linux-bluetooth-
> [email protected]] On Behalf Of Luiz Augusto von Dentz
> Sent: Friday, June 12, 2015 5:49 PM
> To: Bharat Bhusan Panda
> Cc: [email protected]; [email protected]
> Subject: Re: [PATCH ] tools/l2test: Add support for l2cap config request
>
> Hi Bharat,
>
> On Fri, Jun 12, 2015 at 2:44 PM, Bharat Bhusan Panda
> <[email protected]> wrote:
> > Hi Luiz,
> >
> >> -----Original Message-----
> >> From: [email protected] [mailto:linux-bluetooth-
> >> [email protected]] On Behalf Of Luiz Augusto von Dentz
> >> Sent: Friday, June 12, 2015 4:16 PM
> >> To: Bharat Panda
> >> Cc: [email protected]; [email protected]
> >> Subject: Re: [PATCH ] tools/l2test: Add support for l2cap config
> >> request
> >>
> >> Hi Bharat,
> >>
> >> On Thu, Jun 11, 2015 at 2:19 PM, Bharat Panda
> >> <[email protected]> wrote:
> >> > This allows to send l2cap configuration request by providing '-o'
> >> > option to l2test along with '-f' option to add destination CID.
> >> >
> >> > e.g.,
> >> >
> >> > l2test command format:
> >> > l2test -o -X <mode> -f <destination CID> -P <psm> <bd_addr>
> >>
> >> But the kernel should handle this for us, why do you need to do it
> manually?
> > I am not sure, whether kernel is handling it, as in my setup it fails for below
> PTS test cases, with error "MTC: The IUT does not sent subsequent
> ConfigReq or DisconnectReq after Rtx Timeout. Wait for timeout...."
> >
> > L2CAP Basic Mode
> > TP/COS/CED/BV-08-C
> > TP/COS/CFD/BV-02-C
> >
> > L2CAP ERTM mode
> > TP/CMC/BV-01-C
> > TP/CMC/BV-02-C
> > TP/CMC/BV-03-C
> > TP/CMC/BV-07-C
> > TP/CMC/BV-14-C
> >
> > Anything needs to be configured in kernel, to handle it?
>
> Have you checked the android documentation?
> https://git.kernel.org/cgit/bluetooth/bluez.git/tree/android/pts-l2cap.txt
Thanks, I have gone through the pts report of l2cap, and it passes for all the test cases I mentioned above, but by skipping intermediate steps for configuration negotiation.
Please correct me if I am wrong at any point. As in the PTS log I mentioned, PTS expects subsequent ConfigReq for negotiation (optional)or a DisconnectReq. As IUT dint send subsequent ConfigReq in desired time, after timeout it waits for more 65 secs to receive the ConfigReq. Still after, when it doesn't get a config request from IUT, it PASSes the TC assuming no further configuration negotiation.
So this patch will allow to test if you have further negotiation on configuration. As per the PTS test case description it says so but it is an optional feature. If it is so necessary test case, then we can add this to tree.
Test case : TC_COS_CED_BV_08_C started
- MTC: PTS successfully established an ACL connection.
- The IUT sent an extended feature L2CAP Information Request.
- The IUT sent an L2CAP Information Request.
- MTC: The IUT correctly responded with correctly formatted L2CAP CONNECT RSP.
- MTC: The IUT successfully sent a L2CAP_ConfigReq.
- Tester holding config response for 65 seconds. IUT can optionally send subsequent configReq or disconnectReq during 65 seconds...
- MTC: The IUT does not sent subsequent ConfigReq or DisconnectReq after Rtx Timeout. Wait for timeout...
- MTC: Send config request after 65 seconds.
- MTC: Do not receive ConfigRsp after 5 seconds.
- CM_EXIT
- CM_EXIT
- CM_EXIT
- MTC: Test case ended
-Final Verdict: PASS
TC_COS_CED_BV_08_C finished
>
>
> --
> Luiz Augusto von Dentz
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected] More majordomo
> info at http://vger.kernel.org/majordomo-info.html
Best Regards,
Bharat
Hi Bharat,
On Fri, Jun 12, 2015 at 2:44 PM, Bharat Bhusan Panda
<[email protected]> wrote:
> Hi Luiz,
>
>> -----Original Message-----
>> From: [email protected] [mailto:linux-bluetooth-
>> [email protected]] On Behalf Of Luiz Augusto von Dentz
>> Sent: Friday, June 12, 2015 4:16 PM
>> To: Bharat Panda
>> Cc: [email protected]; [email protected]
>> Subject: Re: [PATCH ] tools/l2test: Add support for l2cap config request
>>
>> Hi Bharat,
>>
>> On Thu, Jun 11, 2015 at 2:19 PM, Bharat Panda
>> <[email protected]> wrote:
>> > This allows to send l2cap configuration request by providing '-o'
>> > option to l2test along with '-f' option to add destination CID.
>> >
>> > e.g.,
>> >
>> > l2test command format:
>> > l2test -o -X <mode> -f <destination CID> -P <psm> <bd_addr>
>>
>> But the kernel should handle this for us, why do you need to do it manually?
> I am not sure, whether kernel is handling it, as in my setup it fails for below PTS test cases, with error "MTC: The IUT does not sent subsequent ConfigReq or DisconnectReq after Rtx Timeout. Wait for timeout...."
>
> L2CAP Basic Mode
> TP/COS/CED/BV-08-C
> TP/COS/CFD/BV-02-C
>
> L2CAP ERTM mode
> TP/CMC/BV-01-C
> TP/CMC/BV-02-C
> TP/CMC/BV-03-C
> TP/CMC/BV-07-C
> TP/CMC/BV-14-C
>
> Anything needs to be configured in kernel, to handle it?
Have you checked the android documentation?
https://git.kernel.org/cgit/bluetooth/bluez.git/tree/android/pts-l2cap.txt
>>
>> > ---
>> > lib/l2cap.h | 10 ++++
>> > tools/l2test.c | 162
>> > +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>> > 2 files changed, 167 insertions(+), 5 deletions(-)
>> >
>> > diff --git a/lib/l2cap.h b/lib/l2cap.h index 5ce94c4..85f3c80 100644
>> > --- a/lib/l2cap.h
>> > +++ b/lib/l2cap.h
>> > @@ -235,6 +235,16 @@ typedef struct {
>> > #define L2CAP_IR_NOTSUPP 0x0001
>> >
>> > typedef struct {
>> > + uint8_t mode;
>> > + uint8_t txwin_size;
>> > + uint8_t max_transmit;
>> > + uint16_t retrans_timeout;
>> > + uint16_t monitor_timeout;
>> > + uint16_t max_pdu_size;
>> > +} __attribute__ ((packed)) l2cap_conf_rfc ; #define
>> > +L2CAP_CONF_RFC_SIZE 9
>> > +
>> > +typedef struct {
>> > uint16_t psm;
>> > uint16_t scid;
>> > uint8_t id;
>> > diff --git a/tools/l2test.c b/tools/l2test.c index abe09c1..59500fb
>> > 100644
>> > --- a/tools/l2test.c
>> > +++ b/tools/l2test.c
>> > @@ -69,9 +69,13 @@ enum {
>> > LSENDRECV,
>> > CSENDRECV,
>> > INFOREQ,
>> > + CONFIGREQ,
>> > PAIRING,
>> > };
>> >
>> > +#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
>> > +#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
>> > +
>> > static unsigned char *buf;
>> >
>> > /* Default mtu */
>> > @@ -91,10 +95,11 @@ static int max_transmit = 3; static long
>> > data_size = -1; static long buffer_size = 2048;
>> >
>> > -/* Default addr and psm and cid */
>> > +/* Default addr, psm, cid and dcid */
>> > static bdaddr_t bdaddr;
>> > static unsigned short psm = 0;
>> > static unsigned short cid = 0;
>> > +static uint16_t dcid = 0;
>> >
>> > /* Default number of frames to send (-1 = infinite) */ static int
>> > num_frames = -1; @@ -1245,6 +1250,138 @@ failed:
>> > close(sk);
>> > }
>> >
>> > +static void l2cap_add_conf_opt(void **ptr, uint8_t type,
>> > + uint8_t len, unsigned long
>> > +val) {
>> > + l2cap_conf_opt *opt = *ptr;
>> > +
>> > + printf("type 0x%2.2x len %u val 0x%lx \n", type, len, val);
>> > +
>> > + opt->type = htobs(type);
>> > + opt->len = htobs(len);
>> > +
>> > + switch (opt->len) {
>> > + case 1:
>> > + *((uint8_t *) opt->val) = val;
>> > + break;
>> > + case 2:
>> > + bt_put_le16(val, opt->val);
>> > + break;
>> > + case 4:
>> > + bt_put_le32(val, opt->val);
>> > + break;
>> > + default:
>> > + memcpy(opt->val, (void *) val, len);
>> > + break;
>> > + }
>> > +
>> > + *ptr += L2CAP_CONF_OPT_SIZE + len; }
>> > +
>> > +static int l2cap_build_conf_req(void *data) {
>> > + l2cap_conf_req *req = data;
>> > + l2cap_conf_rfc rfc;
>> > + void *ptr = req->data;
>> > +
>> > + req->dcid = htobs(dcid);
>> > + req->flags = htobs(0x0000);
>> > +
>> > + switch (rfcmode) {
>> > + case L2CAP_MODE_BASIC:
>> > + rfc.mode = htobs(L2CAP_MODE_BASIC);
>> > + rfc.txwin_size = htobs(0);
>> > + rfc.max_transmit = htobs(0);
>> > + rfc.retrans_timeout = htobs(0);
>> > + rfc.monitor_timeout = htobs(0);
>> > + rfc.max_pdu_size = htobs(0);
>> > +
>> > + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
>> > + (unsigned
>> > + long) &rfc);
>> > +
>> > + break;
>> > +
>> > + case L2CAP_MODE_ERTM:
>> > + rfc.mode = htobs(L2CAP_MODE_ERTM);
>> > + rfc.txwin_size = htobs(txwin_size);
>> > + rfc.max_transmit = htobs(max_transmit);
>> > + rfc.retrans_timeout = htobs(L2CAP_DEFAULT_RETRANS_TO);
>> > + rfc.monitor_timeout = htobs(L2CAP_DEFAULT_MONITOR_TO);
>> > + rfc.max_pdu_size = htobs(imtu);
>> > +
>> > + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
>> > + (unsigned long) &rfc);
>> > + break;
>> > +
>> > + case L2CAP_MODE_STREAMING:
>> > + rfc.mode = htobs(L2CAP_MODE_STREAMING);
>> > + rfc.txwin_size = htobs(txwin_size);
>> > + rfc.max_transmit = htobs(max_transmit);
>> > + rfc.retrans_timeout = htobs(L2CAP_DEFAULT_RETRANS_TO);
>> > + rfc.monitor_timeout = htobs(L2CAP_DEFAULT_MONITOR_TO);
>> > + rfc.max_pdu_size = htobs(imtu);
>> > +
>> > + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
>> > + (unsigned
>> > + long) &rfc);
>> > +
>> > + break;
>> > + default:
>> > + return L2CAP_CONF_REQ_SIZE;
>> > + }
>> > +
>> > + return (ptr - data);
>> > +}
>> > +
>> > +static void config_request(char *svr) {
>> > + unsigned char buf[48];
>> > + l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
>> > + uint8_t *req_buf = (uint8_t *) (buf + L2CAP_CMD_HDR_SIZE);
>> > + struct sockaddr_l2 addr;
>> > + int sk;
>> > + int data_len = 0;
>> > +
>> > + sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
>> > + if (sk < 0) {
>> > + perror("Can't create socket");
>> > + return;
>> > + }
>> > +
>> > + memset(&addr, 0, sizeof(addr));
>> > + addr.l2_family = AF_BLUETOOTH;
>> > + bacpy(&addr.l2_bdaddr, &bdaddr);
>> > + addr.l2_bdaddr_type = bdaddr_type;
>> > +
>> > + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
>> > + perror("Can't bind socket");
>> > + goto failed;
>> > + }
>> > +
>> > + memset(&addr, 0, sizeof(addr));
>> > + addr.l2_family = AF_BLUETOOTH;
>> > + str2ba(svr, &addr.l2_bdaddr);
>> > + addr.l2_bdaddr_type = bdaddr_type;
>> > +
>> > + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
>> > + perror("Can't connect socket");
>> > + goto failed;
>> > + }
>> > +
>> > + memset(buf, 0, sizeof(buf));
>> > + cmd->code = L2CAP_CONF_REQ;
>> > + cmd->ident = 141;
>> > + data_len = l2cap_build_conf_req(req_buf);
>> > + cmd->len = htobs(data_len);
>> > +
>> > + if (send(sk, buf, L2CAP_CMD_HDR_SIZE + data_len, 0) < 0) {
>> > + perror("Can't send info request");
>> > + goto failed;
>> > + }
>> > +
>> > +failed:
>> > + close(sk);
>> > +}
>> > +
>> > static void do_pairing(char *svr)
>> > {
>> > struct sockaddr_l2 addr;
>> > @@ -1311,7 +1448,8 @@ static void usage(void)
>> > "\t-c connect, disconnect, connect, ...\n"
>> > "\t-m multiple connects\n"
>> > "\t-p trigger dedicated bonding\n"
>> > - "\t-z information request\n");
>> > + "\t-z information request\n"
>> > + "\t-o configuration request\n");
>> >
>> > printf("Options:\n"
>> > "\t[-b bytes] [-i device] [-P psm] [-J cid]\n"
>> > @@ -1340,7 +1478,7 @@ static void usage(void)
>> > "\t[-M] become master\n"
>> > "\t[-T] enable timestamps\n"
>> > "\t[-V type] address type (help for list, default = bredr)\n"
>> > - "\t[-e seq] initial sequence value (default = 0)\n");
>> > + "\t[-e DCID] Destination CID\n");
>> > }
>> >
>> > int main(int argc, char *argv[])
>> > @@ -1350,8 +1488,8 @@ int main(int argc, char *argv[])
>> >
>> > bacpy(&bdaddr, BDADDR_ANY);
>> >
>> > - while ((opt = getopt(argc, argv, "a:b:cde:g:i:mnpqrstuwxyz"
>> > - "AB:C:D:EF:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) != EOF) {
>> > + while ((opt = getopt(argc, argv, "a:b:cde:g:i:mnopqrstuwxyz"
>> > + "AB:C:D:EFf:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) !=
>> > + EOF) {
>> > switch (opt) {
>> > case 'r':
>> > mode = RECV;
>> > @@ -1412,6 +1550,11 @@ int main(int argc, char *argv[])
>> > need_addr = 1;
>> > break;
>> >
>> > + case 'o':
>> > + mode = CONFIGREQ;
>> > + need_addr = 1;
>> > + break;
>> > +
>> > case 'p':
>> > mode = PAIRING;
>> > need_addr = 1; @@ -1565,6 +1708,11 @@ int
>> > main(int argc, char *argv[])
>> > disc_delay = atoi(optarg) * 1000;
>> > break;
>> >
>> > + case 'f':
>> > + dcid = strtoul(optarg, NULL, 16);
>> > + printf("dcid 0x%2x", dcid);
>> > + break;
>> > +
>> > default:
>> > usage();
>> > exit(1);
>> > @@ -1666,6 +1814,10 @@ int main(int argc, char *argv[])
>> > info_request(argv[optind]);
>> > exit(0);
>> >
>> > + case CONFIGREQ:
>> > + config_request(argv[optind]);
>> > + exit(0);
>> > +
>> > case PAIRING:
>> > do_pairing(argv[optind]);
>> > exit(0);
>> > --
>> > 1.9.1
>> >
>> > --
>> > To unsubscribe from this list: send the line "unsubscribe
>> > linux-bluetooth" in the body of a message to [email protected]
>> > More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>>
>>
>> --
>> Luiz Augusto von Dentz
> --
> BR,
> Bharat
>
>
>
>
--
Luiz Augusto von Dentz
Hi Luiz,
> -----Original Message-----
> From: [email protected] [mailto:linux-bluetooth-
> [email protected]] On Behalf Of Luiz Augusto von Dentz
> Sent: Friday, June 12, 2015 4:16 PM
> To: Bharat Panda
> Cc: [email protected]; [email protected]
> Subject: Re: [PATCH ] tools/l2test: Add support for l2cap config request
>
> Hi Bharat,
>
> On Thu, Jun 11, 2015 at 2:19 PM, Bharat Panda
> <[email protected]> wrote:
> > This allows to send l2cap configuration request by providing '-o'
> > option to l2test along with '-f' option to add destination CID.
> >
> > e.g.,
> >
> > l2test command format:
> > l2test -o -X <mode> -f <destination CID> -P <psm> <bd_addr>
>
> But the kernel should handle this for us, why do you need to do it manually?
I am not sure, whether kernel is handling it, as in my setup it fails for below PTS test cases, with error "MTC: The IUT does not sent subsequent ConfigReq or DisconnectReq after Rtx Timeout. Wait for timeout...."
L2CAP Basic Mode
TP/COS/CED/BV-08-C
TP/COS/CFD/BV-02-C
L2CAP ERTM mode
TP/CMC/BV-01-C
TP/CMC/BV-02-C
TP/CMC/BV-03-C
TP/CMC/BV-07-C
TP/CMC/BV-14-C
Anything needs to be configured in kernel, to handle it?
>
> > ---
> > lib/l2cap.h | 10 ++++
> > tools/l2test.c | 162
> > +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> > 2 files changed, 167 insertions(+), 5 deletions(-)
> >
> > diff --git a/lib/l2cap.h b/lib/l2cap.h index 5ce94c4..85f3c80 100644
> > --- a/lib/l2cap.h
> > +++ b/lib/l2cap.h
> > @@ -235,6 +235,16 @@ typedef struct {
> > #define L2CAP_IR_NOTSUPP 0x0001
> >
> > typedef struct {
> > + uint8_t mode;
> > + uint8_t txwin_size;
> > + uint8_t max_transmit;
> > + uint16_t retrans_timeout;
> > + uint16_t monitor_timeout;
> > + uint16_t max_pdu_size;
> > +} __attribute__ ((packed)) l2cap_conf_rfc ; #define
> > +L2CAP_CONF_RFC_SIZE 9
> > +
> > +typedef struct {
> > uint16_t psm;
> > uint16_t scid;
> > uint8_t id;
> > diff --git a/tools/l2test.c b/tools/l2test.c index abe09c1..59500fb
> > 100644
> > --- a/tools/l2test.c
> > +++ b/tools/l2test.c
> > @@ -69,9 +69,13 @@ enum {
> > LSENDRECV,
> > CSENDRECV,
> > INFOREQ,
> > + CONFIGREQ,
> > PAIRING,
> > };
> >
> > +#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
> > +#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
> > +
> > static unsigned char *buf;
> >
> > /* Default mtu */
> > @@ -91,10 +95,11 @@ static int max_transmit = 3; static long
> > data_size = -1; static long buffer_size = 2048;
> >
> > -/* Default addr and psm and cid */
> > +/* Default addr, psm, cid and dcid */
> > static bdaddr_t bdaddr;
> > static unsigned short psm = 0;
> > static unsigned short cid = 0;
> > +static uint16_t dcid = 0;
> >
> > /* Default number of frames to send (-1 = infinite) */ static int
> > num_frames = -1; @@ -1245,6 +1250,138 @@ failed:
> > close(sk);
> > }
> >
> > +static void l2cap_add_conf_opt(void **ptr, uint8_t type,
> > + uint8_t len, unsigned long
> > +val) {
> > + l2cap_conf_opt *opt = *ptr;
> > +
> > + printf("type 0x%2.2x len %u val 0x%lx \n", type, len, val);
> > +
> > + opt->type = htobs(type);
> > + opt->len = htobs(len);
> > +
> > + switch (opt->len) {
> > + case 1:
> > + *((uint8_t *) opt->val) = val;
> > + break;
> > + case 2:
> > + bt_put_le16(val, opt->val);
> > + break;
> > + case 4:
> > + bt_put_le32(val, opt->val);
> > + break;
> > + default:
> > + memcpy(opt->val, (void *) val, len);
> > + break;
> > + }
> > +
> > + *ptr += L2CAP_CONF_OPT_SIZE + len; }
> > +
> > +static int l2cap_build_conf_req(void *data) {
> > + l2cap_conf_req *req = data;
> > + l2cap_conf_rfc rfc;
> > + void *ptr = req->data;
> > +
> > + req->dcid = htobs(dcid);
> > + req->flags = htobs(0x0000);
> > +
> > + switch (rfcmode) {
> > + case L2CAP_MODE_BASIC:
> > + rfc.mode = htobs(L2CAP_MODE_BASIC);
> > + rfc.txwin_size = htobs(0);
> > + rfc.max_transmit = htobs(0);
> > + rfc.retrans_timeout = htobs(0);
> > + rfc.monitor_timeout = htobs(0);
> > + rfc.max_pdu_size = htobs(0);
> > +
> > + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> > + (unsigned
> > + long) &rfc);
> > +
> > + break;
> > +
> > + case L2CAP_MODE_ERTM:
> > + rfc.mode = htobs(L2CAP_MODE_ERTM);
> > + rfc.txwin_size = htobs(txwin_size);
> > + rfc.max_transmit = htobs(max_transmit);
> > + rfc.retrans_timeout = htobs(L2CAP_DEFAULT_RETRANS_TO);
> > + rfc.monitor_timeout = htobs(L2CAP_DEFAULT_MONITOR_TO);
> > + rfc.max_pdu_size = htobs(imtu);
> > +
> > + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> > + (unsigned long) &rfc);
> > + break;
> > +
> > + case L2CAP_MODE_STREAMING:
> > + rfc.mode = htobs(L2CAP_MODE_STREAMING);
> > + rfc.txwin_size = htobs(txwin_size);
> > + rfc.max_transmit = htobs(max_transmit);
> > + rfc.retrans_timeout = htobs(L2CAP_DEFAULT_RETRANS_TO);
> > + rfc.monitor_timeout = htobs(L2CAP_DEFAULT_MONITOR_TO);
> > + rfc.max_pdu_size = htobs(imtu);
> > +
> > + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> > + (unsigned
> > + long) &rfc);
> > +
> > + break;
> > + default:
> > + return L2CAP_CONF_REQ_SIZE;
> > + }
> > +
> > + return (ptr - data);
> > +}
> > +
> > +static void config_request(char *svr) {
> > + unsigned char buf[48];
> > + l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
> > + uint8_t *req_buf = (uint8_t *) (buf + L2CAP_CMD_HDR_SIZE);
> > + struct sockaddr_l2 addr;
> > + int sk;
> > + int data_len = 0;
> > +
> > + sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
> > + if (sk < 0) {
> > + perror("Can't create socket");
> > + return;
> > + }
> > +
> > + memset(&addr, 0, sizeof(addr));
> > + addr.l2_family = AF_BLUETOOTH;
> > + bacpy(&addr.l2_bdaddr, &bdaddr);
> > + addr.l2_bdaddr_type = bdaddr_type;
> > +
> > + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> > + perror("Can't bind socket");
> > + goto failed;
> > + }
> > +
> > + memset(&addr, 0, sizeof(addr));
> > + addr.l2_family = AF_BLUETOOTH;
> > + str2ba(svr, &addr.l2_bdaddr);
> > + addr.l2_bdaddr_type = bdaddr_type;
> > +
> > + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> > + perror("Can't connect socket");
> > + goto failed;
> > + }
> > +
> > + memset(buf, 0, sizeof(buf));
> > + cmd->code = L2CAP_CONF_REQ;
> > + cmd->ident = 141;
> > + data_len = l2cap_build_conf_req(req_buf);
> > + cmd->len = htobs(data_len);
> > +
> > + if (send(sk, buf, L2CAP_CMD_HDR_SIZE + data_len, 0) < 0) {
> > + perror("Can't send info request");
> > + goto failed;
> > + }
> > +
> > +failed:
> > + close(sk);
> > +}
> > +
> > static void do_pairing(char *svr)
> > {
> > struct sockaddr_l2 addr;
> > @@ -1311,7 +1448,8 @@ static void usage(void)
> > "\t-c connect, disconnect, connect, ...\n"
> > "\t-m multiple connects\n"
> > "\t-p trigger dedicated bonding\n"
> > - "\t-z information request\n");
> > + "\t-z information request\n"
> > + "\t-o configuration request\n");
> >
> > printf("Options:\n"
> > "\t[-b bytes] [-i device] [-P psm] [-J cid]\n"
> > @@ -1340,7 +1478,7 @@ static void usage(void)
> > "\t[-M] become master\n"
> > "\t[-T] enable timestamps\n"
> > "\t[-V type] address type (help for list, default = bredr)\n"
> > - "\t[-e seq] initial sequence value (default = 0)\n");
> > + "\t[-e DCID] Destination CID\n");
> > }
> >
> > int main(int argc, char *argv[])
> > @@ -1350,8 +1488,8 @@ int main(int argc, char *argv[])
> >
> > bacpy(&bdaddr, BDADDR_ANY);
> >
> > - while ((opt = getopt(argc, argv, "a:b:cde:g:i:mnpqrstuwxyz"
> > - "AB:C:D:EF:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) != EOF) {
> > + while ((opt = getopt(argc, argv, "a:b:cde:g:i:mnopqrstuwxyz"
> > + "AB:C:D:EFf:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) !=
> > + EOF) {
> > switch (opt) {
> > case 'r':
> > mode = RECV;
> > @@ -1412,6 +1550,11 @@ int main(int argc, char *argv[])
> > need_addr = 1;
> > break;
> >
> > + case 'o':
> > + mode = CONFIGREQ;
> > + need_addr = 1;
> > + break;
> > +
> > case 'p':
> > mode = PAIRING;
> > need_addr = 1; @@ -1565,6 +1708,11 @@ int
> > main(int argc, char *argv[])
> > disc_delay = atoi(optarg) * 1000;
> > break;
> >
> > + case 'f':
> > + dcid = strtoul(optarg, NULL, 16);
> > + printf("dcid 0x%2x", dcid);
> > + break;
> > +
> > default:
> > usage();
> > exit(1);
> > @@ -1666,6 +1814,10 @@ int main(int argc, char *argv[])
> > info_request(argv[optind]);
> > exit(0);
> >
> > + case CONFIGREQ:
> > + config_request(argv[optind]);
> > + exit(0);
> > +
> > case PAIRING:
> > do_pairing(argv[optind]);
> > exit(0);
> > --
> > 1.9.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe
> > linux-bluetooth" in the body of a message to [email protected]
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
>
> --
> Luiz Augusto von Dentz
--
BR,
Bharat
Hi Bharat,
On Thu, Jun 11, 2015 at 2:19 PM, Bharat Panda <[email protected]> wrote:
> This allows to send l2cap configuration request by providing
> '-o' option to l2test along with '-f' option to add destination CID.
>
> e.g.,
>
> l2test command format:
> l2test -o -X <mode> -f <destination CID> -P <psm> <bd_addr>
But the kernel should handle this for us, why do you need to do it manually?
> ---
> lib/l2cap.h | 10 ++++
> tools/l2test.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 167 insertions(+), 5 deletions(-)
>
> diff --git a/lib/l2cap.h b/lib/l2cap.h
> index 5ce94c4..85f3c80 100644
> --- a/lib/l2cap.h
> +++ b/lib/l2cap.h
> @@ -235,6 +235,16 @@ typedef struct {
> #define L2CAP_IR_NOTSUPP 0x0001
>
> typedef struct {
> + uint8_t mode;
> + uint8_t txwin_size;
> + uint8_t max_transmit;
> + uint16_t retrans_timeout;
> + uint16_t monitor_timeout;
> + uint16_t max_pdu_size;
> +} __attribute__ ((packed)) l2cap_conf_rfc ;
> +#define L2CAP_CONF_RFC_SIZE 9
> +
> +typedef struct {
> uint16_t psm;
> uint16_t scid;
> uint8_t id;
> diff --git a/tools/l2test.c b/tools/l2test.c
> index abe09c1..59500fb 100644
> --- a/tools/l2test.c
> +++ b/tools/l2test.c
> @@ -69,9 +69,13 @@ enum {
> LSENDRECV,
> CSENDRECV,
> INFOREQ,
> + CONFIGREQ,
> PAIRING,
> };
>
> +#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
> +#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
> +
> static unsigned char *buf;
>
> /* Default mtu */
> @@ -91,10 +95,11 @@ static int max_transmit = 3;
> static long data_size = -1;
> static long buffer_size = 2048;
>
> -/* Default addr and psm and cid */
> +/* Default addr, psm, cid and dcid */
> static bdaddr_t bdaddr;
> static unsigned short psm = 0;
> static unsigned short cid = 0;
> +static uint16_t dcid = 0;
>
> /* Default number of frames to send (-1 = infinite) */
> static int num_frames = -1;
> @@ -1245,6 +1250,138 @@ failed:
> close(sk);
> }
>
> +static void l2cap_add_conf_opt(void **ptr, uint8_t type,
> + uint8_t len, unsigned long val)
> +{
> + l2cap_conf_opt *opt = *ptr;
> +
> + printf("type 0x%2.2x len %u val 0x%lx \n", type, len, val);
> +
> + opt->type = htobs(type);
> + opt->len = htobs(len);
> +
> + switch (opt->len) {
> + case 1:
> + *((uint8_t *) opt->val) = val;
> + break;
> + case 2:
> + bt_put_le16(val, opt->val);
> + break;
> + case 4:
> + bt_put_le32(val, opt->val);
> + break;
> + default:
> + memcpy(opt->val, (void *) val, len);
> + break;
> + }
> +
> + *ptr += L2CAP_CONF_OPT_SIZE + len;
> +}
> +
> +static int l2cap_build_conf_req(void *data)
> +{
> + l2cap_conf_req *req = data;
> + l2cap_conf_rfc rfc;
> + void *ptr = req->data;
> +
> + req->dcid = htobs(dcid);
> + req->flags = htobs(0x0000);
> +
> + switch (rfcmode) {
> + case L2CAP_MODE_BASIC:
> + rfc.mode = htobs(L2CAP_MODE_BASIC);
> + rfc.txwin_size = htobs(0);
> + rfc.max_transmit = htobs(0);
> + rfc.retrans_timeout = htobs(0);
> + rfc.monitor_timeout = htobs(0);
> + rfc.max_pdu_size = htobs(0);
> +
> + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> + (unsigned long) &rfc);
> +
> + break;
> +
> + case L2CAP_MODE_ERTM:
> + rfc.mode = htobs(L2CAP_MODE_ERTM);
> + rfc.txwin_size = htobs(txwin_size);
> + rfc.max_transmit = htobs(max_transmit);
> + rfc.retrans_timeout = htobs(L2CAP_DEFAULT_RETRANS_TO);
> + rfc.monitor_timeout = htobs(L2CAP_DEFAULT_MONITOR_TO);
> + rfc.max_pdu_size = htobs(imtu);
> +
> + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> + (unsigned long) &rfc);
> + break;
> +
> + case L2CAP_MODE_STREAMING:
> + rfc.mode = htobs(L2CAP_MODE_STREAMING);
> + rfc.txwin_size = htobs(txwin_size);
> + rfc.max_transmit = htobs(max_transmit);
> + rfc.retrans_timeout = htobs(L2CAP_DEFAULT_RETRANS_TO);
> + rfc.monitor_timeout = htobs(L2CAP_DEFAULT_MONITOR_TO);
> + rfc.max_pdu_size = htobs(imtu);
> +
> + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> + (unsigned long) &rfc);
> +
> + break;
> + default:
> + return L2CAP_CONF_REQ_SIZE;
> + }
> +
> + return (ptr - data);
> +}
> +
> +static void config_request(char *svr)
> +{
> + unsigned char buf[48];
> + l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf;
> + uint8_t *req_buf = (uint8_t *) (buf + L2CAP_CMD_HDR_SIZE);
> + struct sockaddr_l2 addr;
> + int sk;
> + int data_len = 0;
> +
> + sk = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
> + if (sk < 0) {
> + perror("Can't create socket");
> + return;
> + }
> +
> + memset(&addr, 0, sizeof(addr));
> + addr.l2_family = AF_BLUETOOTH;
> + bacpy(&addr.l2_bdaddr, &bdaddr);
> + addr.l2_bdaddr_type = bdaddr_type;
> +
> + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> + perror("Can't bind socket");
> + goto failed;
> + }
> +
> + memset(&addr, 0, sizeof(addr));
> + addr.l2_family = AF_BLUETOOTH;
> + str2ba(svr, &addr.l2_bdaddr);
> + addr.l2_bdaddr_type = bdaddr_type;
> +
> + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> + perror("Can't connect socket");
> + goto failed;
> + }
> +
> + memset(buf, 0, sizeof(buf));
> + cmd->code = L2CAP_CONF_REQ;
> + cmd->ident = 141;
> + data_len = l2cap_build_conf_req(req_buf);
> + cmd->len = htobs(data_len);
> +
> + if (send(sk, buf, L2CAP_CMD_HDR_SIZE + data_len, 0) < 0) {
> + perror("Can't send info request");
> + goto failed;
> + }
> +
> +failed:
> + close(sk);
> +}
> +
> static void do_pairing(char *svr)
> {
> struct sockaddr_l2 addr;
> @@ -1311,7 +1448,8 @@ static void usage(void)
> "\t-c connect, disconnect, connect, ...\n"
> "\t-m multiple connects\n"
> "\t-p trigger dedicated bonding\n"
> - "\t-z information request\n");
> + "\t-z information request\n"
> + "\t-o configuration request\n");
>
> printf("Options:\n"
> "\t[-b bytes] [-i device] [-P psm] [-J cid]\n"
> @@ -1340,7 +1478,7 @@ static void usage(void)
> "\t[-M] become master\n"
> "\t[-T] enable timestamps\n"
> "\t[-V type] address type (help for list, default = bredr)\n"
> - "\t[-e seq] initial sequence value (default = 0)\n");
> + "\t[-e DCID] Destination CID\n");
> }
>
> int main(int argc, char *argv[])
> @@ -1350,8 +1488,8 @@ int main(int argc, char *argv[])
>
> bacpy(&bdaddr, BDADDR_ANY);
>
> - while ((opt = getopt(argc, argv, "a:b:cde:g:i:mnpqrstuwxyz"
> - "AB:C:D:EF:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) != EOF) {
> + while ((opt = getopt(argc, argv, "a:b:cde:g:i:mnopqrstuwxyz"
> + "AB:C:D:EFf:GH:I:J:K:L:MN:O:P:Q:RSTUV:W:X:Y:Z:")) != EOF) {
> switch (opt) {
> case 'r':
> mode = RECV;
> @@ -1412,6 +1550,11 @@ int main(int argc, char *argv[])
> need_addr = 1;
> break;
>
> + case 'o':
> + mode = CONFIGREQ;
> + need_addr = 1;
> + break;
> +
> case 'p':
> mode = PAIRING;
> need_addr = 1;
> @@ -1565,6 +1708,11 @@ int main(int argc, char *argv[])
> disc_delay = atoi(optarg) * 1000;
> break;
>
> + case 'f':
> + dcid = strtoul(optarg, NULL, 16);
> + printf("dcid 0x%2x", dcid);
> + break;
> +
> default:
> usage();
> exit(1);
> @@ -1666,6 +1814,10 @@ int main(int argc, char *argv[])
> info_request(argv[optind]);
> exit(0);
>
> + case CONFIGREQ:
> + config_request(argv[optind]);
> + exit(0);
> +
> case PAIRING:
> do_pairing(argv[optind]);
> exit(0);
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Luiz Augusto von Dentz