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"

Reply via email to