BLE建立L2CAP Socket连接remote提示connect refused
最近在全志r329 上面编写和某个remote设备建立BLE连接的程序,发现创建socket以后,和remote设备连接时候,提示connect refused。
最后分析原因是:没有设置LE_HOST_SUPPORTED。
在此记录问题原因和解决方法:
int __host_create_gatt_socket( char *slave_macaddr ) //XX:XX:XX:XX:XX:XX { int sk = 0; struct sockaddr_l2 master_addr; struct sockaddr_l2 slave_addr; struct bt_security btsec; //创建gatt层的socket sk = socket( AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP ); // sk = socket( AF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK, BTPROTO_L2CAP ); printf( "sock = %d\n",sk ); if ( sk<0 ) { pt_error( "Can't create seqpacket socket: %s\n", strerror(errno) ); return -1; } //绑定socket memset( &master_addr,0,sizeof(master_addr) ); master_addr.l2_family = AF_BLUETOOTH; master_addr.l2_cid = 0x0004; master_addr.l2_bdaddr_type=0x01; if( bind(sk, (struct sockaddr *)&master_addr, sizeof(master_addr))<0 ) { pt_error( "[con] bind error: %s\n", strerror(errno) ); close( sk ); return -1; } printf( "bind success\n" ); //slave 的mac 地址 memset( &slave_addr, 0, sizeof(slave_addr) ); slave_addr.l2_family = AF_BLUETOOTH; slave_addr.l2_cid = 0x0004; slave_addr.l2_bdaddr_type = 0x01; str2ba( slave_macaddr, (bdaddr_t*)&slave_addr.l2_bdaddr ); if( connect( sk, (struct sockaddr *)&slave_addr, sizeof(slave_addr))<0 ) { pt_error( "[con] connect error: %s-%d", strerror(errno),errno ); close( sk ); return -1; } printf( "connect to slave success\n" ); return sk; }
创建L2CAP socket以后,调用connect()接口,提示connect refused。
添加如下接口:
int hci_read_le_host_supported(int dd,int *le,int *simul, int to);
int hci_write_le_host_supported(int dd, uint8_t leEnable,uint8_t simulEnable , int to)
int hci_read_le_host_supported(int dd,int *le,int *simul, int to) { read_le_host_supported_rp rp; struct hci_request rq; memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_HOST_CTL; rq.ocf = OCF_READ_LE_HOST_SUPPORTED; rq.rparam = &rp; rq.rlen = READ_LE_HOST_SUPPORTED_RP_SIZE; if (hci_send_req(dd, &rq, to) < 0) return -1; if (rp.status) { errno = EIO; return -1; } if(le) *le = rp.le; if(simul) *simul = rp.simul; return 0; } int hci_write_le_host_supported(int dd, uint8_t leEnable,uint8_t simulEnable , int to) { write_le_host_supported_cp cp; struct hci_request rq; memset(&cp, 0, sizeof(cp)); cp.le = leEnable; cp.simul = simulEnable; memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_HOST_CTL; rq.ocf = OCF_WRITE_LE_HOST_SUPPORTED; rq.cparam = &cp; rq.clen = WRITE_LE_HOST_SUPPORTED_CP_SIZE; if (hci_send_req(dd, &rq, to) < 0) return -1; return 0; }
ble_host_scan( int enable ) { int m_advsock ;
int le=0,simul=0; if( enable ) { m_advsock = hci_open_dev(0) ; //hci0 if( m_advsock>0 ) { hci_read_le_host_supported(m_ble_advsock,&le,&simul,5000); printf( "le=%d simul=%d... \n",le, simul ); hci_write_le_host_supported(m_ble_advsock, 1,simul , 5000); hci_read_le_host_supported(m_ble_advsock,&le,&simul,5000); printf( " le=%d simul=%d... \n",le, simul );
//设置LE扫描参数,使能扫描
ble_hci_lescan( m_advsock, enable ); } }
else
{
ble_hci_lescan( m_advsock, enable );
}
}
int ble_hci_lescan( int s, int enable ) { printf( "ble_hci_lescan=%d %d\n", s, enable ); if( s >= 0 ) { int err=-1; m_is_enable = enable; if( m_is_enable==0 ) { uint8_t filter_dup = 0x01; setsockopt( s, SOL_HCI, HCI_FILTER, &m_orig_filter, sizeof(m_orig_filter) ); err = hci_le_set_scan_enable( s, 0x00, filter_dup, 10000 ); if (err < 0) { pt_error("Disable scan failed ->%s", strerror(errno) ); return -1; } printf( "hci le set scan disable\n" ); } else { uint8_t own_type = LE_PUBLIC_ADDRESS; uint8_t scan_type = 0x00; uint8_t filter_policy = 0x00; uint16_t interval = htobs(0x0050); uint16_t window = htobs(0x0020); uint8_t filter_dup = 0x00;//过滤掉相同的 1 // uint16_t interval = htobs(ble_scan_paramter_interval); // uint16_t window = htobs(ble_scan_paramter_windows); printf( "interval = %d, window = %d\n", interval, window ); err = hci_le_set_scan_parameters( s, scan_type, interval, window, own_type, filter_policy, 10000 ); if (err < 0) { pt_error("Set scan parameters failed ->%s", strerror(errno) ); return -1; } printf( "set scan prameter succ:%d %d\n",interval, window ); err = hci_le_set_scan_enable(s, 0x01, filter_dup, 10000); if (err < 0) { pt_error("Enable scan failed ->%s", strerror(errno) ); return -1; } struct hci_filter nf; socklen_t olen; olen = sizeof(m_orig_filter); if (getsockopt(s, SOL_HCI, HCI_FILTER, &m_orig_filter, &olen) < 0) { pt_error("Could not get socket options\n"); return -1; } hci_filter_clear(&nf); hci_filter_set_ptype(HCI_EVENT_PKT, &nf); hci_filter_set_event(EVT_LE_META_EVENT, &nf); //try to get disconnect event!!! hci_filter_set_event(EVT_DISCONN_COMPLETE, &nf); if (setsockopt(s, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) { pt_error("Could not set socket options\n"); setsockopt(s, SOL_HCI, HCI_FILTER, &m_orig_filter, sizeof(m_orig_filter)); return -1; } } return 0; } return -1; }
设置了LE_HOST_SUPPORT后,即可正常连接remote 设备。
注:
1. 在测试中发现,如果启动bluetoothd,不需要设置LE_HOST_SUPPORT,也可以连接成功。怀疑是Bluetoothd启动中,设置了LE_HOST_SUPPORT。
2. LE_HOST_SUPPORT feature 开发板每次启动都需要设置。该feature应该是设置到了内核中。
3. 跟踪到了内核代码中,初步发现在mgmt.c中的set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)接口中有设置LE_HOST_SUPPORT