diff options
| -rw-r--r-- | test/l2test.c | 124 | 
1 files changed, 117 insertions, 7 deletions
| diff --git a/test/l2test.c b/test/l2test.c index f3365c01..42d66adf 100644 --- a/test/l2test.c +++ b/test/l2test.c @@ -58,7 +58,8 @@ enum {  	CRECV,  	LSEND,  	SENDDUMP, -	LSENDDUMP +	LSENDDUMP, +	INFOREQ  };  static unsigned char *buf; @@ -676,6 +677,105 @@ static void multi_connect_mode(int argc, char *argv[])  	}  } +static void info_request(char *svr) +{ +	unsigned char buf[48]; +	l2cap_cmd_hdr *cmd = (l2cap_cmd_hdr *) buf; +	l2cap_info_req *req = (l2cap_info_req *) (buf + L2CAP_CMD_HDR_SIZE); +	l2cap_info_rsp *rsp = (l2cap_info_rsp *) (buf + L2CAP_CMD_HDR_SIZE); +	uint16_t mtu; +	uint32_t mask; +	struct sockaddr_l2 addr; +	int sk, err; + +	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); + +	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); + +	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0 ) { +		perror("Can't connect socket"); +		goto failed; +	} + +	memset(buf, 0, sizeof(buf)); +	cmd->code  = L2CAP_INFO_REQ; +	cmd->ident = 0; +	cmd->len   = htobs(2); +	req->type  = htobs(0x0001); + +	if (send(sk, buf, L2CAP_CMD_HDR_SIZE + L2CAP_INFO_REQ_SIZE, 0) < 0) { +		perror("Can't send info request"); +		goto failed; +	} + +	err = recv(sk, buf, L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + 2, 0); +	if (err < 0) { +		perror("Can't receive info response"); +		goto failed; +	} + +	switch (btohs(rsp->result)) { +	case 0x0000: +		mtu = btohs(bt_get_unaligned((uint16_t *) rsp->data)); +		printf("Connectionless MTU size is %d\n", mtu); +		break; +	case 0x0001: +		printf("Connectionless MTU is not supported\n"); +		break; +	} + +	memset(buf, 0, sizeof(buf)); +	cmd->code  = L2CAP_INFO_REQ; +	cmd->ident = 0; +	cmd->len   = htobs(2); +	req->type  = htobs(0x0002); + +	if (send(sk, buf, L2CAP_CMD_HDR_SIZE + L2CAP_INFO_REQ_SIZE, 0) < 0) { +		perror("Can't send info request"); +		goto failed; +	} + +	err = recv(sk, buf, L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + 4, 0); +	if (err < 0) { +		perror("Can't receive info response"); +		goto failed; +	} + +	switch (btohs(rsp->result)) { +	case 0x0000: +		mask = btohl(bt_get_unaligned((uint32_t *) rsp->data)); +		printf("Extended feature mask is 0x%04x\n", mask); +		if (mask & 0x01) +			printf("  Flow control mode\n"); +		if (mask & 0x02) +			printf("  Retransmission mode\n"); +		if (mask & 0x04) +			printf("  Bi-directional QoS\n"); +		break; +	case 0x0001: +		printf("Extended feature mask is not supported\n"); +		break; +	} + +failed: +	close(sk); +} +  static void usage(void)  {  	printf("l2test - L2CAP testing\n" @@ -691,7 +791,8 @@ static void usage(void)  		"\t-n connect and be silent\n"  		"\t-y connect, then send, then dump incoming data\n"  		"\t-c connect, disconnect, connect, ...\n" -		"\t-m multiple connects\n"); +		"\t-m multiple connects\n" +		"\t-z information request\n");  	printf("Options:\n"  		"\t[-b bytes] [-i device] [-P psm]\n" @@ -717,7 +818,7 @@ int main(int argc, char *argv[])  	bacpy(&bdaddr, BDADDR_ANY); -	while ((opt=getopt(argc,argv,"rdscuwmnxyb:i:P:I:O:B:N:L:C:D:RGFAESM")) != EOF) { +	while ((opt=getopt(argc,argv,"rdscuwmnxyzb:i:P:I:O:B:N:L:C:D:RGFAESM")) != EOF) {  		switch(opt) {  		case 'r':  			mode = RECV; @@ -756,10 +857,6 @@ int main(int argc, char *argv[])  			need_addr = 1;  			break; -		case 'b': -			data_size = atoi(optarg); -			break; -  		case 'x':  			mode = LSENDDUMP;  			break; @@ -768,6 +865,15 @@ int main(int argc, char *argv[])  			mode = SENDDUMP;  			break; +		case 'z': +			mode = INFOREQ; +			need_addr = 1; +			break; + +		case 'b': +			data_size = atoi(optarg); +			break; +  		case 'i':  			if (!strncasecmp(optarg, "hci", 3))  				hci_devba(atoi(optarg + 3), &bdaddr); @@ -915,6 +1021,10 @@ int main(int argc, char *argv[])  		case LSENDDUMP:  			do_listen(senddump_mode);  			break; + +		case INFOREQ: +			info_request(argv[optind]); +			exit(0);  	}  	syslog(LOG_INFO, "Exit"); | 
