Author: takawata Date: Tue Apr 7 10:22:56 2015 New Revision: 281198 URL: https://svnweb.freebsd.org/changeset/base/281198
Log: Initial Bluetooth LE support. Note that sockaddr_l2cap structure is changed , check socket address to initialize new structure member and define L2CAP_SOCKET_CHECKED before including ng_btsocket.h Differential Revision: https://reviews.freebsd.org/D2021 Reviewed by:emax Modified: head/sys/netgraph/bluetooth/hci/ng_hci_cmds.c head/sys/netgraph/bluetooth/hci/ng_hci_evnt.c head/sys/netgraph/bluetooth/hci/ng_hci_main.c head/sys/netgraph/bluetooth/hci/ng_hci_misc.c head/sys/netgraph/bluetooth/hci/ng_hci_misc.h head/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c head/sys/netgraph/bluetooth/hci/ng_hci_var.h head/sys/netgraph/bluetooth/include/ng_btsocket.h head/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h head/sys/netgraph/bluetooth/include/ng_hci.h head/sys/netgraph/bluetooth/include/ng_l2cap.h head/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.c head/sys/netgraph/bluetooth/l2cap/ng_l2cap_cmds.h head/sys/netgraph/bluetooth/l2cap/ng_l2cap_evnt.c head/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c head/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.h head/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.c head/sys/netgraph/bluetooth/l2cap/ng_l2cap_misc.h head/sys/netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c head/sys/netgraph/bluetooth/l2cap/ng_l2cap_var.h head/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c head/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c head/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c Modified: head/sys/netgraph/bluetooth/hci/ng_hci_cmds.c ============================================================================== --- head/sys/netgraph/bluetooth/hci/ng_hci_cmds.c Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/hci/ng_hci_cmds.c Tue Apr 7 10:22:56 2015 (r281198) @@ -71,11 +71,15 @@ static int process_status_params (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); static int process_testing_params (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); +static int process_le_params + (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); static int process_link_control_status (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *); static int process_link_policy_status (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *); +static int process_le_status + (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *); /* * Send HCI command to the driver. @@ -222,7 +226,10 @@ ng_hci_process_command_complete(ng_hci_u error = process_testing_params(unit, NG_HCI_OCF(ep->opcode), cp, e); break; - + case NG_HCI_OGF_LE: + error = process_le_params(unit, + NG_HCI_OCF(ep->opcode), cp, e); + break; case NG_HCI_OGF_BT_LOGO: case NG_HCI_OGF_VENDOR: NG_FREE_M(cp); @@ -294,7 +301,9 @@ ng_hci_process_command_status(ng_hci_uni case NG_HCI_OGF_LINK_POLICY: error = process_link_policy_status(unit, ep, cp); break; - + case NG_HCI_OGF_LE: + error = process_le_status(unit, ep, cp); + break; case NG_HCI_OGF_BT_LOGO: case NG_HCI_OGF_VENDOR: NG_FREE_M(cp); @@ -604,6 +613,8 @@ process_hc_baseband_params(ng_hci_unit_p case NG_HCI_OCF_READ_LOCAL_NAME: case NG_HCI_OCF_READ_UNIT_CLASS: case NG_HCI_OCF_WRITE_UNIT_CLASS: + case NG_HCI_OCF_READ_LE_HOST_SUPPORTED: + case NG_HCI_OCF_WRITE_LE_HOST_SUPPORTED: /* These do not need post processing */ break; @@ -796,6 +807,132 @@ process_testing_params(ng_hci_unit_p uni return (error); } /* process_testing_params */ +/* + * Process LE command return parameters + */ + +static int +process_le_params(ng_hci_unit_p unit, u_int16_t ocf, + struct mbuf *mcp, struct mbuf *mrp) +{ + int error = 0; + + switch (ocf){ + case NG_HCI_OCF_LE_SET_EVENT_MASK: + case NG_HCI_OCF_LE_READ_BUFFER_SIZE: + case NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES: + case NG_HCI_OCF_LE_SET_RANDOM_ADDRESS: + case NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS: + case NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER: + case NG_HCI_OCF_LE_SET_ADVERTISING_DATA: + case NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA: + case NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE: + case NG_HCI_OCF_LE_SET_SCAN_PARAMETERS: + case NG_HCI_OCF_LE_SET_SCAN_ENABLE: + case NG_HCI_OCF_LE_CREATE_CONNECTION_CANCEL: + case NG_HCI_OCF_LE_CLEAR_WHITE_LIST: + case NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE: + case NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST: + case NG_HCI_OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST: + case NG_HCI_OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION: + case NG_HCI_OCF_LE_READ_CHANNEL_MAP: + case NG_HCI_OCF_LE_ENCRYPT: + case NG_HCI_OCF_LE_RAND: + case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_REPLY: + case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY: + case NG_HCI_OCF_LE_READ_SUPPORTED_STATUS: + case NG_HCI_OCF_LE_RECEIVER_TEST: + case NG_HCI_OCF_LE_TRANSMITTER_TEST: + case NG_HCI_OCF_LE_TEST_END: + + /* These do not need post processing */ + break; + case NG_HCI_OCF_LE_CREATE_CONNECTION: + case NG_HCI_OCF_LE_CONNECTION_UPDATE: + case NG_HCI_OCF_LE_READ_REMOTE_USED_FEATURES: + case NG_HCI_OCF_LE_START_ENCRYPTION: + + + default: + /* + * None of these command was supposed to generate + * Command_Complete event. Instead Command_Status event + * should have been generated and then appropriate event + * should have been sent to indicate the final result. + */ + + error = EINVAL; + break; + } + + NG_FREE_M(mcp); + NG_FREE_M(mrp); + + return (error); + +} + + + +static int +process_le_status(ng_hci_unit_p unit,ng_hci_command_status_ep *ep, + struct mbuf *mcp) +{ + int error = 0; + + switch (NG_HCI_OCF(ep->opcode)){ + case NG_HCI_OCF_LE_CREATE_CONNECTION: + case NG_HCI_OCF_LE_CONNECTION_UPDATE: + case NG_HCI_OCF_LE_READ_REMOTE_USED_FEATURES: + case NG_HCI_OCF_LE_START_ENCRYPTION: + + /* These do not need post processing */ + break; + + case NG_HCI_OCF_LE_SET_EVENT_MASK: + case NG_HCI_OCF_LE_READ_BUFFER_SIZE: + case NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES: + case NG_HCI_OCF_LE_SET_RANDOM_ADDRESS: + case NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS: + case NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER: + case NG_HCI_OCF_LE_SET_ADVERTISING_DATA: + case NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA: + case NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE: + case NG_HCI_OCF_LE_SET_SCAN_PARAMETERS: + case NG_HCI_OCF_LE_SET_SCAN_ENABLE: + case NG_HCI_OCF_LE_CREATE_CONNECTION_CANCEL: + case NG_HCI_OCF_LE_CLEAR_WHITE_LIST: + case NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE: + case NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST: + case NG_HCI_OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST: + case NG_HCI_OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION: + case NG_HCI_OCF_LE_READ_CHANNEL_MAP: + case NG_HCI_OCF_LE_ENCRYPT: + case NG_HCI_OCF_LE_RAND: + case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_REPLY: + case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY: + case NG_HCI_OCF_LE_READ_SUPPORTED_STATUS: + case NG_HCI_OCF_LE_RECEIVER_TEST: + case NG_HCI_OCF_LE_TRANSMITTER_TEST: + case NG_HCI_OCF_LE_TEST_END: + + + default: + /* + * None of these command was supposed to generate + * Command_Stutus event. Command Complete instead. + */ + + error = EINVAL; + break; + } + + NG_FREE_M(mcp); + + return (error); + +} + /* * Process link control command status */ Modified: head/sys/netgraph/bluetooth/hci/ng_hci_evnt.c ============================================================================== --- head/sys/netgraph/bluetooth/hci/ng_hci_evnt.c Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/hci/ng_hci_evnt.c Tue Apr 7 10:22:56 2015 (r281198) @@ -76,6 +76,7 @@ static int page_scan_mode_change (n static int page_scan_rep_mode_change (ng_hci_unit_p, struct mbuf *); static int sync_con_queue (ng_hci_unit_p, ng_hci_unit_con_p, int); static int send_data_packets (ng_hci_unit_p, int, int); +static int le_event (ng_hci_unit_p, struct mbuf *); /* * Process HCI event packet @@ -121,6 +122,9 @@ ng_hci_process_event(ng_hci_unit_p unit, /* These do not need post processing */ NG_FREE_M(event); break; + case NG_HCI_EVENT_LE: + error = le_event(unit, event); + break; case NG_HCI_EVENT_INQUIRY_RESULT: error = inquiry_result(unit, event); @@ -247,6 +251,7 @@ static int send_data_packets(ng_hci_unit_p unit, int link_type, int limit) { ng_hci_unit_con_p con = NULL, winner = NULL; + int reallink_type; item_p item = NULL; int min_pending, total_sent, sent, error, v; @@ -260,8 +265,11 @@ send_data_packets(ng_hci_unit_p unit, in */ LIST_FOREACH(con, &unit->con_list, next) { - if (con->link_type != link_type) + reallink_type = (con->link_type == NG_HCI_LINK_SCO)? + NG_HCI_LINK_SCO: NG_HCI_LINK_ACL; + if (reallink_type != link_type){ continue; + } if (NG_BT_ITEMQ_LEN(&con->conq) == 0) continue; @@ -327,7 +335,6 @@ send_data_packets(ng_hci_unit_p unit, in /* * Sync connection queue for the winner */ - sync_con_queue(unit, winner, sent); } @@ -346,7 +353,7 @@ sync_con_queue(ng_hci_unit_p unit, ng_hc ng_hci_sync_con_queue_ep *state = NULL; int error; - hook = (con->link_type == NG_HCI_LINK_ACL)? unit->acl : unit->sco; + hook = (con->link_type != NG_HCI_LINK_SCO)? unit->acl : unit->sco; if (hook == NULL || NG_HOOK_NOT_VALID(hook)) return (ENOTCONN); @@ -363,6 +370,223 @@ sync_con_queue(ng_hci_unit_p unit, ng_hc return (error); } /* sync_con_queue */ +/* le meta event */ +/* Inquiry result event */ +static int +le_advertizing_report(ng_hci_unit_p unit, struct mbuf *event) +{ + ng_hci_le_advertising_report_ep *ep = NULL; + ng_hci_neighbor_p n = NULL; + bdaddr_t bdaddr; + int error = 0; + u_int8_t event_type; + u_int8_t addr_type; + + NG_HCI_M_PULLUP(event, sizeof(*ep)); + if (event == NULL) + return (ENOBUFS); + + ep = mtod(event, ng_hci_le_advertising_report_ep *); + m_adj(event, sizeof(*ep)); + + for (; ep->num_reports > 0; ep->num_reports --) { + /* Get remote unit address */ + NG_HCI_M_PULLUP(event, sizeof(u_int8_t)); + event_type = *mtod(event, u_int8_t *); + m_adj(event, sizeof(u_int8_t)); + NG_HCI_M_PULLUP(event, sizeof(u_int8_t)); + addr_type = *mtod(event, u_int8_t *); + m_adj(event, sizeof(u_int8_t)); + + m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr); + m_adj(event, sizeof(bdaddr)); + + /* Lookup entry in the cache */ + n = ng_hci_get_neighbor(unit, &bdaddr, (addr_type) ? NG_HCI_LINK_LE_RANDOM:NG_HCI_LINK_LE_PUBLIC); + if (n == NULL) { + /* Create new entry */ + n = ng_hci_new_neighbor(unit); + if (n == NULL) { + error = ENOMEM; + break; + } + bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr)); + n->addrtype = (addr_type)? NG_HCI_LINK_LE_RANDOM : + NG_HCI_LINK_LE_PUBLIC; + + } else + getmicrotime(&n->updated); + +#if 0 + { + /* + * TODO: Make these information + * Available from userland. + */ + u_int8_t length_data; + + char *rssi; + + NG_HCI_M_PULLUP(event, sizeof(u_int8_t)); + length_data = *mtod(event, u_int8_t *); + m_adj(event, sizeof(u_int8_t)); + /*Advertizement data*/ + NG_HCI_M_PULLUP(event, length_data); + m_adj(event, length_data); + NG_HCI_M_PULLUP(event, sizeof(char )); + /*Get RSSI*/ + rssi = mtod(event, char *); + m_adj(event, sizeof(u_int8_t)); + } +#endif + } + NG_FREE_M(event); + + return (error); +} /* inquiry_result */ + +static int le_connection_complete(ng_hci_unit_p unit, struct mbuf *event) +{ + int error = 0; + + ng_hci_le_connection_complete_ep *ep = NULL; + ng_hci_unit_con_p con = NULL; + int link_type; + uint8_t uclass[3] = {0,0,0};//dummy uclass + + NG_HCI_M_PULLUP(event, sizeof(*ep)); + if (event == NULL) + return (ENOBUFS); + + ep = mtod(event, ng_hci_le_connection_complete_ep *); + link_type = (ep->address_type)? NG_HCI_LINK_LE_RANDOM : + NG_HCI_LINK_LE_PUBLIC; + /* + * Find the first connection descriptor that matches the following: + * + * 1) con->link_type == link_type + * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE + * 3) con->bdaddr == ep->address + */ + LIST_FOREACH(con, &unit->con_list, next) + if (con->link_type == link_type && + con->state == NG_HCI_CON_W4_CONN_COMPLETE && + bcmp(&con->bdaddr, &ep->address, sizeof(bdaddr_t)) == 0) + break; + + /* + * Two possible cases: + * + * 1) We have found connection descriptor. That means upper layer has + * requested this connection via LP_CON_REQ message. In this case + * connection must have timeout set. If ng_hci_con_untimeout() fails + * then timeout message already went into node's queue. In this case + * ignore Connection_Complete event and let timeout deal with it. + * + * 2) We do not have connection descriptor. That means upper layer + * nas not requested this connection , (less likely) we gave up + * on this connection (timeout) or as node act as slave role. + * The most likely scenario is that + * we have received LE_Create_Connection command + * from the RAW hook + */ + + if (con == NULL) { + if (ep->status != 0) + goto out; + + con = ng_hci_new_con(unit, link_type); + if (con == NULL) { + error = ENOMEM; + goto out; + } + + con->state = NG_HCI_CON_W4_LP_CON_RSP; + ng_hci_con_timeout(con); + + bcopy(&ep->address, &con->bdaddr, sizeof(con->bdaddr)); + error = ng_hci_lp_con_ind(con, uclass); + if (error != 0) { + ng_hci_con_untimeout(con); + ng_hci_free_con(con); + } + + } else if ((error = ng_hci_con_untimeout(con)) != 0) + goto out; + + /* + * Update connection descriptor and send notification + * to the upper layers. + */ + + con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->handle)); + con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE; + + ng_hci_lp_con_cfm(con, ep->status); + + /* Adjust connection state */ + if (ep->status != 0) + ng_hci_free_con(con); + else { + con->state = NG_HCI_CON_OPEN; + + /* + * Change link policy for the ACL connections. Enable all + * supported link modes. Enable Role switch as well if + * device supports it. + */ + + } + +out: + NG_FREE_M(event); + + return (error); + +} + +static int le_connection_update(ng_hci_unit_p unit, struct mbuf *event) +{ + int error = 0; + /*TBD*/ + + NG_FREE_M(event); + return error; + +} +static int +le_event(ng_hci_unit_p unit, struct mbuf *event) +{ + int error = 0; + ng_hci_le_ep *lep; + + NG_HCI_M_PULLUP(event, sizeof(*lep)); + if(event ==NULL){ + return ENOBUFS; + } + lep = mtod(event, ng_hci_le_ep *); + m_adj(event, sizeof(*lep)); + switch(lep->subevent_code){ + case NG_HCI_LEEV_CON_COMPL: + le_connection_complete(unit, event); + break; + case NG_HCI_LEEV_ADVREP: + le_advertizing_report(unit, event); + break; + case NG_HCI_LEEV_CON_UPDATE_COMPL: + le_connection_update(unit, event); + break; + case NG_HCI_LEEV_READ_REMOTE_FEATURES_COMPL: + //TBD + /*FALLTHROUGH*/ + case NG_HCI_LEEV_LONG_TERM_KEY_REQUEST: + //TBD + /*FALLTHROUGH*/ + default: + NG_FREE_M(event); + } + return error; +} /* Inquiry result event */ static int @@ -386,7 +610,7 @@ inquiry_result(ng_hci_unit_p unit, struc m_adj(event, sizeof(bdaddr)); /* Lookup entry in the cache */ - n = ng_hci_get_neighbor(unit, &bdaddr); + n = ng_hci_get_neighbor(unit, &bdaddr, NG_HCI_LINK_ACL); if (n == NULL) { /* Create new entry */ n = ng_hci_new_neighbor(unit); @@ -398,6 +622,7 @@ inquiry_result(ng_hci_unit_p unit, struc getmicrotime(&n->updated); bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr)); + n->addrtype = NG_HCI_LINK_ACL; /* XXX call m_pullup here? */ @@ -754,7 +979,7 @@ read_remote_features_compl(ng_hci_unit_p } /* Update cache entry */ - n = ng_hci_get_neighbor(unit, &con->bdaddr); + n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL); if (n == NULL) { n = ng_hci_new_neighbor(unit); if (n == NULL) { @@ -763,6 +988,7 @@ read_remote_features_compl(ng_hci_unit_p } bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); + n->addrtype = NG_HCI_LINK_ACL; } else getmicrotime(&n->updated); @@ -909,7 +1135,7 @@ num_compl_pkts(ng_hci_unit_p unit, struc } /* Update buffer descriptor */ - if (con->link_type == NG_HCI_LINK_ACL) + if (con->link_type != NG_HCI_LINK_SCO) NG_HCI_BUFF_ACL_FREE(unit->buffer, p); else NG_HCI_BUFF_SCO_FREE(unit->buffer, p); @@ -1010,7 +1236,7 @@ read_clock_offset_compl(ng_hci_unit_p un } /* Update cache entry */ - n = ng_hci_get_neighbor(unit, &con->bdaddr); + n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL); if (n == NULL) { n = ng_hci_new_neighbor(unit); if (n == NULL) { @@ -1019,6 +1245,7 @@ read_clock_offset_compl(ng_hci_unit_p un } bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); + n->addrtype = NG_HCI_LINK_ACL; } else getmicrotime(&n->updated); @@ -1089,7 +1316,7 @@ page_scan_mode_change(ng_hci_unit_p unit ep = mtod(event, ng_hci_page_scan_mode_change_ep *); /* Update cache entry */ - n = ng_hci_get_neighbor(unit, &ep->bdaddr); + n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL); if (n == NULL) { n = ng_hci_new_neighbor(unit); if (n == NULL) { @@ -1098,6 +1325,7 @@ page_scan_mode_change(ng_hci_unit_p unit } bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); + n->addrtype = NG_HCI_LINK_ACL; } else getmicrotime(&n->updated); @@ -1123,7 +1351,7 @@ page_scan_rep_mode_change(ng_hci_unit_p ep = mtod(event, ng_hci_page_scan_rep_mode_change_ep *); /* Update cache entry */ - n = ng_hci_get_neighbor(unit, &ep->bdaddr); + n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL); if (n == NULL) { n = ng_hci_new_neighbor(unit); if (n == NULL) { @@ -1132,6 +1360,7 @@ page_scan_rep_mode_change(ng_hci_unit_p } bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); + n->addrtype = NG_HCI_LINK_ACL; } else getmicrotime(&n->updated); Modified: head/sys/netgraph/bluetooth/hci/ng_hci_main.c ============================================================================== --- head/sys/netgraph/bluetooth/hci/ng_hci_main.c Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/hci/ng_hci_main.c Tue Apr 7 10:22:56 2015 (r281198) @@ -775,7 +775,6 @@ ng_hci_acl_rcvdata(hook_p hook, item_p i int size, error = 0; NG_HCI_BUFF_ACL_SIZE(unit->buffer, size); - /* Check packet */ NGI_GET_M(item, m); @@ -788,7 +787,6 @@ ng_hci_acl_rcvdata(hook_p hook, item_p i error = EINVAL; goto drop; } - if (m->m_pkthdr.len < sizeof(ng_hci_acldata_pkt_t) || m->m_pkthdr.len > sizeof(ng_hci_acldata_pkt_t) + size) { NG_HCI_ALERT( @@ -831,7 +829,7 @@ ng_hci_acl_rcvdata(hook_p hook, item_p i goto drop; } - if (con->link_type != NG_HCI_LINK_ACL) { + if (con->link_type == NG_HCI_LINK_SCO) { NG_HCI_ERR( "%s: %s - unexpected HCI ACL data packet. Not ACL link, con_handle=%d, " \ "link_type=%d\n", __func__, NG_NODE_NAME(unit->node), Modified: head/sys/netgraph/bluetooth/hci/ng_hci_misc.c ============================================================================== --- head/sys/netgraph/bluetooth/hci/ng_hci_misc.c Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/hci/ng_hci_misc.c Tue Apr 7 10:22:56 2015 (r281198) @@ -214,7 +214,7 @@ ng_hci_flush_neighbor_cache(ng_hci_unit_ */ ng_hci_neighbor_p -ng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr) +ng_hci_get_neighbor(ng_hci_unit_p unit, bdaddr_p bdaddr,int link_type) { ng_hci_neighbor_p n = NULL; @@ -222,7 +222,8 @@ ng_hci_get_neighbor(ng_hci_unit_p unit, ng_hci_neighbor_p nn = LIST_NEXT(n, next); if (!ng_hci_neighbor_stale(n)) { - if (bcmp(&n->bdaddr, bdaddr, sizeof(*bdaddr)) == 0) + if (n->addrtype == link_type && + bcmp(&n->bdaddr, bdaddr, sizeof(*bdaddr)) == 0) break; } else ng_hci_free_neighbor(n); /* remove old entry */ @@ -284,7 +285,7 @@ ng_hci_new_con(ng_hci_unit_p unit, int l con->link_type = link_type; - if (con->link_type == NG_HCI_LINK_ACL) + if (con->link_type != NG_HCI_LINK_SCO) NG_HCI_BUFF_ACL_TOTAL(unit->buffer, num_pkts); else NG_HCI_BUFF_SCO_TOTAL(unit->buffer, num_pkts); @@ -313,7 +314,7 @@ ng_hci_free_con(ng_hci_unit_con_p con) * flushed these packets and we can free them too */ - if (con->link_type == NG_HCI_LINK_ACL) + if (con->link_type != NG_HCI_LINK_SCO) NG_HCI_BUFF_ACL_FREE(con->unit->buffer, con->pending); else NG_HCI_BUFF_SCO_FREE(con->unit->buffer, con->pending); Modified: head/sys/netgraph/bluetooth/hci/ng_hci_misc.h ============================================================================== --- head/sys/netgraph/bluetooth/hci/ng_hci_misc.h Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/hci/ng_hci_misc.h Tue Apr 7 10:22:56 2015 (r281198) @@ -41,7 +41,7 @@ void ng_hci_unit_clean ng_hci_neighbor_p ng_hci_new_neighbor (ng_hci_unit_p); void ng_hci_free_neighbor (ng_hci_neighbor_p); void ng_hci_flush_neighbor_cache (ng_hci_unit_p); -ng_hci_neighbor_p ng_hci_get_neighbor (ng_hci_unit_p, bdaddr_p); +ng_hci_neighbor_p ng_hci_get_neighbor (ng_hci_unit_p, bdaddr_p, int); int ng_hci_neighbor_stale (ng_hci_neighbor_p); ng_hci_unit_con_p ng_hci_new_con (ng_hci_unit_p, int); Modified: head/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c ============================================================================== --- head/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c Tue Apr 7 10:22:56 2015 (r281198) @@ -56,6 +56,7 @@ static int ng_hci_lp_acl_con_req (ng_hci_unit_p, item_p, hook_p); static int ng_hci_lp_sco_con_req (ng_hci_unit_p, item_p, hook_p); +static int ng_hci_lp_le_con_req (ng_hci_unit_p, item_p, hook_p, int); /* * Process LP_ConnectReq event from the upper layer protocol @@ -64,6 +65,8 @@ static int ng_hci_lp_sco_con_req (ng_hci int ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) { + int link_type; + if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { NG_HCI_WARN( "%s: %s - unit is not ready, state=%#x\n", @@ -84,21 +87,30 @@ ng_hci_lp_con_req(ng_hci_unit_p unit, it return (EMSGSIZE); } - - if (((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type == NG_HCI_LINK_ACL) + link_type = ((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type; + switch(link_type){ + case NG_HCI_LINK_ACL: return (ng_hci_lp_acl_con_req(unit, item, hook)); - - if (hook != unit->sco) { - NG_HCI_WARN( -"%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n", - __func__, NG_NODE_NAME(unit->node), hook); - - NG_FREE_ITEM(item); - - return (EINVAL); + case NG_HCI_LINK_SCO: + if (hook != unit->sco ) { + NG_HCI_WARN( + "%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n", + __func__, NG_NODE_NAME(unit->node), hook); + + NG_FREE_ITEM(item); + + return (EINVAL); + } + + return (ng_hci_lp_sco_con_req(unit, item, hook)); + case NG_HCI_LINK_LE_PUBLIC: + case NG_HCI_LINK_LE_RANDOM: + return (ng_hci_lp_le_con_req(unit, item, hook, link_type)); + default: + panic("%s: link_type invalid.", __func__); } - - return (ng_hci_lp_sco_con_req(unit, item, hook)); + + return (EINVAL); } /* ng_hci_lp_con_req */ /* @@ -264,7 +276,7 @@ ng_hci_lp_acl_con_req(ng_hci_unit_p unit * So check the neighbor cache. */ - n = ng_hci_get_neighbor(unit, &ep->bdaddr); + n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL); if (n == NULL) { req->cp.page_scan_rep_mode = 0; req->cp.page_scan_mode = 0; @@ -469,6 +481,180 @@ out: return (error); } /* ng_hci_lp_sco_con_req */ +static int +ng_hci_lp_le_con_req(ng_hci_unit_p unit, item_p item, hook_p hook, int link_type) +{ + struct acl_con_req { + ng_hci_cmd_pkt_t hdr; + ng_hci_le_create_connection_cp cp; + } __attribute__ ((packed)) *req = NULL; + ng_hci_lp_con_req_ep *ep = NULL; + ng_hci_unit_con_p con = NULL; + struct mbuf *m = NULL; + int error = 0; + + ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); + if((link_type != NG_HCI_LINK_LE_PUBLIC)&& + (link_type != NG_HCI_LINK_LE_RANDOM)){ + printf("%s: Link type %d Cannot be here \n", __func__, + link_type); + } + /* + * Only one ACL connection can exist between each pair of units. + * So try to find ACL connection descriptor (in any state) that + * has requested remote BD_ADDR. + * + * Two cases: + * + * 1) We do not have connection to the remote unit. This is simple. + * Just create new connection descriptor and send HCI command to + * create new connection. + * + * 2) We do have connection descriptor. We need to check connection + * state: + * + * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of + * accepting connection from the remote unit. This is a race + * condition. We will ignore this message. + * + * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already + * requested connection or we just accepted it. In any case + * all we need to do here is set appropriate notification bit + * and wait. + * + * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back + * and let upper layer know that we have connection already. + */ + + con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, link_type); + if (con != NULL) { + switch (con->state) { + case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ + error = EALREADY; + break; + + case NG_HCI_CON_W4_CONN_COMPLETE: + if (hook != unit->sco) + con->flags |= NG_HCI_CON_NOTIFY_ACL; + else + con->flags |= NG_HCI_CON_NOTIFY_SCO; + break; + + case NG_HCI_CON_OPEN: { + struct ng_mesg *msg = NULL; + ng_hci_lp_con_cfm_ep *cfm = NULL; + + if (hook != NULL && NG_HOOK_IS_VALID(hook)) { + NGI_GET_MSG(item, msg); + NG_FREE_MSG(msg); + + NG_MKMESSAGE(msg, NGM_HCI_COOKIE, + NGM_HCI_LP_CON_CFM, sizeof(*cfm), + M_NOWAIT); + if (msg != NULL) { + cfm = (ng_hci_lp_con_cfm_ep *)msg->data; + cfm->status = 0; + cfm->link_type = con->link_type; + cfm->con_handle = con->con_handle; + bcopy(&con->bdaddr, &cfm->bdaddr, + sizeof(cfm->bdaddr)); + + /* + * This will forward item back to + * sender and set item to NULL + */ + + _NGI_MSG(item) = msg; + NG_FWD_ITEM_HOOK(error, item, hook); + } else + error = ENOMEM; + } else + NG_HCI_INFO( +"%s: %s - Source hook is not valid, hook=%p\n", + __func__, NG_NODE_NAME(unit->node), + hook); + } break; + + default: + panic( +"%s: %s - Invalid connection state=%d\n", + __func__, NG_NODE_NAME(unit->node), con->state); + break; + } + + goto out; + } + + /* + * If we got here then we need to create new ACL connection descriptor + * and submit HCI command. First create new connection desriptor, set + * bdaddr and notification flags. + */ + + con = ng_hci_new_con(unit, link_type); + if (con == NULL) { + error = ENOMEM; + goto out; + } + + bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); + + /* + * Create HCI command + */ + + MGETHDR(m, M_NOWAIT, MT_DATA); + if (m == NULL) { + ng_hci_free_con(con); + error = ENOBUFS; + goto out; + } + + m->m_pkthdr.len = m->m_len = sizeof(*req); + req = mtod(m, struct acl_con_req *); + req->hdr.type = NG_HCI_CMD_PKT; + req->hdr.length = sizeof(req->cp); + req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LE, + NG_HCI_OCF_LE_CREATE_CONNECTION)); + + bcopy(&ep->bdaddr, &req->cp.peer_addr, sizeof(req->cp.peer_addr)); + req->cp.own_address_type = 0; + req->cp.peer_addr_type = (link_type == NG_HCI_LINK_LE_RANDOM)? 1:0; + req->cp.scan_interval = htole16(4); + req->cp.scan_window = htole16(4); + req->cp.filter_policy = 0; + req->cp.conn_interval_min = htole16(0xf); + req->cp.conn_interval_max = htole16(0xf); + req->cp.conn_latency = htole16(0); + req->cp.supervision_timeout = htole16(0xc80); + req->cp.min_ce_length = htole16(1); + req->cp.max_ce_length = htole16(1); + /* + * Adust connection state + */ + + if (hook != unit->sco) + con->flags |= NG_HCI_CON_NOTIFY_ACL; + else + con->flags |= NG_HCI_CON_NOTIFY_SCO; + + con->state = NG_HCI_CON_W4_CONN_COMPLETE; + ng_hci_con_timeout(con); + + /* + * Queue and send HCI command + */ + + NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); + if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) + error = ng_hci_send_command(unit); +out: + if (item != NULL) + NG_FREE_ITEM(item); + + return (error); +} /* ng_hci_lp_acl_con_req */ + /* * Process LP_DisconnectReq event from the upper layer protocol */ @@ -578,7 +764,7 @@ ng_hci_lp_con_cfm(ng_hci_unit_con_p con, * only SCO upstream hook will receive notification */ - if (con->link_type == NG_HCI_LINK_ACL && + if (con->link_type != NG_HCI_LINK_SCO && con->flags & NG_HCI_CON_NOTIFY_ACL) { if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, @@ -646,7 +832,7 @@ ng_hci_lp_con_ind(ng_hci_unit_con_p con, * Use link_type to select upstream hook. */ - if (con->link_type == NG_HCI_LINK_ACL) + if (con->link_type != NG_HCI_LINK_SCO) hook = unit->acl; else hook = unit->sco; @@ -887,7 +1073,7 @@ ng_hci_lp_discon_ind(ng_hci_unit_con_p c * only SCO upstream hook will receive notification. */ - if (con->link_type == NG_HCI_LINK_ACL) { + if (con->link_type != NG_HCI_LINK_SCO) { if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_IND, sizeof(*ep), M_NOWAIT); Modified: head/sys/netgraph/bluetooth/hci/ng_hci_var.h ============================================================================== --- head/sys/netgraph/bluetooth/hci/ng_hci_var.h Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/hci/ng_hci_var.h Tue Apr 7 10:22:56 2015 (r281198) @@ -205,6 +205,7 @@ typedef struct ng_hci_neighbor { bdaddr_t bdaddr; /* address */ u_int8_t features[NG_HCI_FEATURES_SIZE]; /* LMP features */ + u_int8_t addrtype; /*Address Type*/ u_int8_t page_scan_rep_mode; /* PS rep. mode */ u_int8_t page_scan_mode; /* page scan mode */ Modified: head/sys/netgraph/bluetooth/include/ng_btsocket.h ============================================================================== --- head/sys/netgraph/bluetooth/include/ng_btsocket.h Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/include/ng_btsocket.h Tue Apr 7 10:22:56 2015 (r281198) @@ -221,13 +221,32 @@ struct sockaddr_sco { * Bluetooth version of struct sockaddr for L2CAP sockets (RAW and SEQPACKET) */ +struct sockaddr_l2cap_compat { + u_char l2cap_len; /* total length */ + u_char l2cap_family; /* address family */ + u_int16_t l2cap_psm; /* PSM (Protocol/Service Multiplexor) */ + bdaddr_t l2cap_bdaddr; /* address */ +}; + +#define BDADDR_BREDR 0 +#define BDADDR_LE_PUBLIC 1 +#define BDADDR_LE_RANDOM 2 + struct sockaddr_l2cap { u_char l2cap_len; /* total length */ u_char l2cap_family; /* address family */ u_int16_t l2cap_psm; /* PSM (Protocol/Service Multiplexor) */ bdaddr_t l2cap_bdaddr; /* address */ + u_int16_t l2cap_cid; /*cid*/ + u_int8_t l2cap_bdaddr_type; /*address type*/ }; + +#if !defined(L2CAP_SOCKET_CHECKED) && !defined(_KERNEL) +#warning "Make sure new member of socket address initialized" +#endif + + /* L2CAP socket options */ #define SOL_L2CAP 0x1609 /* socket option level */ Modified: head/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h ============================================================================== --- head/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h Tue Apr 7 10:22:56 2015 (r281198) @@ -70,6 +70,8 @@ struct ng_btsocket_l2cap_raw_pcb { bdaddr_t src; /* source address */ bdaddr_t dst; /* dest address */ + uint8_t srctype;/*source addr type*/ + uint8_t dsttype;/*source addr type*/ ng_btsocket_l2cap_rtentry_p rt; /* routing info */ u_int32_t token; /* message token */ @@ -129,6 +131,8 @@ struct ng_btsocket_l2cap_pcb { bdaddr_t src; /* Source address */ bdaddr_t dst; /* Destination address */ + uint8_t srctype; /*source addr type*/ + uint8_t dsttype; /*source addr type*/ u_int16_t psm; /* PSM */ u_int16_t cid; /* Local channel ID */ Modified: head/sys/netgraph/bluetooth/include/ng_hci.h ============================================================================== --- head/sys/netgraph/bluetooth/include/ng_hci.h Tue Apr 7 09:52:14 2015 (r281197) +++ head/sys/netgraph/bluetooth/include/ng_hci.h Tue Apr 7 10:22:56 2015 (r281198) @@ -75,10 +75,11 @@ #define NG_HCI_KEY_SIZE 16 /* link key */ #define NG_HCI_PIN_SIZE 16 /* link PIN */ #define NG_HCI_EVENT_MASK_SIZE 8 /* event mask */ +#define NG_HCI_LE_EVENT_MASK_SIZE 8 /* event mask */ #define NG_HCI_CLASS_SIZE 3 /* unit class */ #define NG_HCI_FEATURES_SIZE 8 /* LMP features */ #define NG_HCI_UNIT_NAME_SIZE 248 /* unit name size */ - +#define NG_HCI_COMMANDS_SIZE 64 /*Command list BMP size*/ /* HCI specification */ #define NG_HCI_SPEC_V10 0x00 /* v1.0 */ #define NG_HCI_SPEC_V11 0x01 /* v1.1 */ @@ -115,6 +116,8 @@ /* Link types */ #define NG_HCI_LINK_SCO 0x00 /* Voice */ #define NG_HCI_LINK_ACL 0x01 /* Data */ *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"