1 /******************************************************************************
2  *
3  *  Copyright 1999-2012 Broadcom Corporation
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 /******************************************************************************
20  *
21  *  This file contains main functions to support PAN profile
22  *  commands and events.
23  *
24  ******************************************************************************/
25 
26 #include <string.h>
27 #include "bnep_api.h"
28 #include "bt_common.h"
29 #include "bt_types.h"
30 #include "bt_utils.h"
31 #include "hcidefs.h"
32 #include "l2c_api.h"
33 #include "osi/include/osi.h"
34 #include "pan_api.h"
35 #include "pan_int.h"
36 #include "sdp_api.h"
37 #include "sdpdefs.h"
38 
39 using bluetooth::Uuid;
40 
41 tPAN_CB pan_cb;
42 
43 /*******************************************************************************
44  *
45  * Function         pan_register_with_bnep
46  *
47  * Description      This function registers PAN profile with BNEP
48  *
49  * Parameters:      none
50  *
51  * Returns          none
52  *
53  ******************************************************************************/
pan_register_with_bnep(void)54 void pan_register_with_bnep(void) {
55   tBNEP_REGISTER reg_info;
56 
57   memset(&reg_info, 0, sizeof(tBNEP_REGISTER));
58 
59   reg_info.p_conn_ind_cb = pan_conn_ind_cb;
60   reg_info.p_conn_state_cb = pan_connect_state_cb;
61   reg_info.p_data_buf_cb = pan_data_buf_ind_cb;
62   reg_info.p_data_ind_cb = NULL;
63   reg_info.p_tx_data_flow_cb = pan_tx_data_flow_cb;
64   reg_info.p_filter_ind_cb = pan_proto_filt_ind_cb;
65   reg_info.p_mfilter_ind_cb = pan_mcast_filt_ind_cb;
66 
67   BNEP_Register(&reg_info);
68 }
69 
70 /*******************************************************************************
71  *
72  * Function         pan_conn_ind_cb
73  *
74  * Description      This function is registered with BNEP as connection
75  *                  indication callback. BNEP will call this when there is
76  *                  connection request from the peer. PAN should call
77  *                  BNEP_ConnectResp to indicate whether to accept the
78  *                  connection or reject
79  *
80  * Parameters:      handle      - handle for the connection
81  *                  p_bda       - BD Addr of the peer requesting the connection
82  *                  remote_uuid     - UUID of the source role (peer device role)
83  *                  local_uuid      - UUID of the destination role (local device
84  *                                                                  role)
85  *                  is_role_change  - Flag to indicate that it is a role change
86  *
87  * Returns          none
88  *
89  ******************************************************************************/
pan_conn_ind_cb(uint16_t handle,const RawAddress & p_bda,const Uuid & remote_uuid,const Uuid & local_uuid,bool is_role_change)90 void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda,
91                      const Uuid& remote_uuid, const Uuid& local_uuid,
92                      bool is_role_change) {
93   /* If we are in GN or NAP role and have one or more active connections and the
94    * received connection is for user role reject it. If we are in user role with
95    * one connection active reject the connection. Allocate PCB and store the
96    * parameters. Make bridge request to the host system if connection is for NAP
97    */
98 
99   if (!remote_uuid.Is16Bit()) {
100     PAN_TRACE_ERROR("PAN Connection failed because of wrong remote UUID ");
101     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
102     return;
103   }
104 
105   if (!local_uuid.Is16Bit()) {
106     PAN_TRACE_ERROR("PAN Connection failed because of wrong local UUID ");
107     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
108     return;
109   }
110 
111   uint16_t remote_uuid16 = remote_uuid.As16Bit();
112   uint16_t local_uuid16 = local_uuid.As16Bit();
113 
114   PAN_TRACE_EVENT(
115       "%s - handle %d, current role %d, dst uuid 0x%x, src uuid 0x%x, role "
116       "change %s",
117       __func__, handle, pan_cb.role, local_uuid16, remote_uuid16,
118       is_role_change ? "YES" : "NO");
119 
120   /* Check if the source UUID is a valid one */
121   if (remote_uuid16 != UUID_SERVCLASS_PANU &&
122       remote_uuid16 != UUID_SERVCLASS_NAP &&
123       remote_uuid16 != UUID_SERVCLASS_GN) {
124     PAN_TRACE_ERROR("Src UUID 0x%x is not valid", remote_uuid16);
125     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
126     return;
127   }
128 
129   /* Check if the destination UUID is a valid one */
130   if (local_uuid16 != UUID_SERVCLASS_PANU &&
131       local_uuid16 != UUID_SERVCLASS_NAP && local_uuid16 != UUID_SERVCLASS_GN) {
132     PAN_TRACE_ERROR("Dst UUID 0x%x is not valid", local_uuid16);
133     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
134     return;
135   }
136 
137   /* Check if currently we support the destination role requested */
138   if (((!(pan_cb.role & UUID_SERVCLASS_PANU)) &&
139        local_uuid16 == UUID_SERVCLASS_PANU) ||
140       ((!(pan_cb.role & UUID_SERVCLASS_GN)) &&
141        local_uuid16 == UUID_SERVCLASS_GN) ||
142       ((!(pan_cb.role & UUID_SERVCLASS_NAP)) &&
143        local_uuid16 == UUID_SERVCLASS_NAP)) {
144     PAN_TRACE_ERROR(
145         "PAN Connection failed because of unsupported destination UUID 0x%x",
146         local_uuid16);
147     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
148     return;
149   }
150 
151   /* Check for valid interactions between the three PAN profile roles */
152   /*
153    * For reference, see Table 1 in PAN Profile v1.0 spec.
154    * Note: the remote is the initiator.
155    */
156   bool is_valid_interaction = false;
157   switch (remote_uuid16) {
158     case UUID_SERVCLASS_NAP:
159     case UUID_SERVCLASS_GN:
160       if (local_uuid16 == UUID_SERVCLASS_PANU) is_valid_interaction = true;
161       break;
162     case UUID_SERVCLASS_PANU:
163       is_valid_interaction = true;
164       break;
165   }
166   /*
167    * Explicitly disable connections to the local PANU if the remote is
168    * not PANU.
169    */
170   if ((local_uuid16 == UUID_SERVCLASS_PANU) &&
171       (remote_uuid16 != UUID_SERVCLASS_PANU)) {
172     is_valid_interaction = false;
173   }
174   if (!is_valid_interaction) {
175     PAN_TRACE_ERROR(
176         "PAN Connection failed because of invalid PAN profile roles "
177         "interaction: Remote UUID 0x%x Local UUID 0x%x",
178         remote_uuid16, local_uuid16);
179     BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
180     return;
181   }
182 
183   uint8_t req_role;
184   /* Requested destination role is */
185   if (local_uuid16 == UUID_SERVCLASS_PANU)
186     req_role = PAN_ROLE_CLIENT;
187   else
188     req_role = PAN_ROLE_NAP_SERVER;
189 
190   /* If the connection indication is for the existing connection
191   ** Check if the new destination role is acceptable
192   */
193   tPAN_CONN* pcb = pan_get_pcb_by_handle(handle);
194   if (pcb) {
195     if (pan_cb.num_conns > 1 && local_uuid16 == UUID_SERVCLASS_PANU) {
196       /* There are connections other than this one
197       ** so we cann't accept PANU role. Reject
198       */
199       PAN_TRACE_ERROR(
200           "Dst UUID should be either GN or NAP only because there are other "
201           "connections");
202       BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
203       return;
204     }
205 
206     /* If it is already in connected state check for bridging status */
207     if (pcb->con_state == PAN_STATE_CONNECTED) {
208       PAN_TRACE_EVENT("PAN Role changing New Src 0x%x Dst 0x%x", remote_uuid16,
209                       local_uuid16);
210 
211       pcb->prv_src_uuid = pcb->src_uuid;
212       pcb->prv_dst_uuid = pcb->dst_uuid;
213 
214       if (pcb->src_uuid == UUID_SERVCLASS_NAP &&
215           local_uuid16 != UUID_SERVCLASS_NAP) {
216         /* Remove bridging */
217         if (pan_cb.pan_bridge_req_cb)
218           (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, false);
219       }
220     }
221     /* Set the latest active PAN role */
222     pan_cb.active_role = req_role;
223     pcb->src_uuid = local_uuid16;
224     pcb->dst_uuid = remote_uuid16;
225     BNEP_ConnectResp(handle, BNEP_SUCCESS);
226     return;
227   } else {
228     /* If this a new connection and destination is PANU role and
229     ** we already have a connection then reject the request.
230     ** If we have a connection in PANU role then reject it
231     */
232     if (pan_cb.num_conns && (local_uuid16 == UUID_SERVCLASS_PANU ||
233                              pan_cb.active_role == PAN_ROLE_CLIENT)) {
234       PAN_TRACE_ERROR("PAN already have a connection and can't be user");
235       BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
236       return;
237     }
238   }
239 
240   /* This is a new connection */
241   PAN_TRACE_DEBUG("New connection indication for handle %d", handle);
242   pcb = pan_allocate_pcb(p_bda, handle);
243   if (!pcb) {
244     PAN_TRACE_ERROR("PAN no control block for new connection");
245     BNEP_ConnectResp(handle, BNEP_CONN_FAILED);
246     return;
247   }
248 
249   PAN_TRACE_EVENT("PAN connection destination UUID is 0x%x", local_uuid16);
250   /* Set the latest active PAN role */
251   pan_cb.active_role = req_role;
252   pcb->src_uuid = local_uuid16;
253   pcb->dst_uuid = remote_uuid16;
254   pcb->con_state = PAN_STATE_CONN_START;
255   pan_cb.num_conns++;
256 
257   BNEP_ConnectResp(handle, BNEP_SUCCESS);
258   return;
259 }
260 
261 /*******************************************************************************
262  *
263  * Function         pan_connect_state_cb
264  *
265  * Description      This function is registered with BNEP as connection state
266  *                  change callback. BNEP will call this when the connection
267  *                  is established successfully or terminated
268  *
269  * Parameters:      handle  - handle for the connection given in the connection
270  *                            indication callback
271  *                  rem_bda - remote device bd addr
272  *                  result  - indicates whether the connection is up or down
273  *                            BNEP_SUCCESS if the connection is up all other
274  *                            values indicate appropriate errors.
275  *                  is_role_change - flag to indicate that it is a role change
276  *
277  * Returns          none
278  *
279  ******************************************************************************/
pan_connect_state_cb(uint16_t handle,UNUSED_ATTR const RawAddress & rem_bda,tBNEP_RESULT result,bool is_role_change)280 void pan_connect_state_cb(uint16_t handle,
281                           UNUSED_ATTR const RawAddress& rem_bda,
282                           tBNEP_RESULT result, bool is_role_change) {
283   tPAN_CONN* pcb;
284   uint8_t peer_role;
285 
286   PAN_TRACE_EVENT("pan_connect_state_cb - for handle %d, result %d", handle,
287                   result);
288   pcb = pan_get_pcb_by_handle(handle);
289   if (!pcb) {
290     PAN_TRACE_ERROR("PAN State change indication for wrong handle %d", handle);
291     return;
292   }
293 
294   /* If the connection is getting terminated remove bridging */
295   if (result != BNEP_SUCCESS) {
296     /* Inform the application that connection is down */
297     if (pan_cb.pan_conn_state_cb)
298       (*pan_cb.pan_conn_state_cb)(pcb->handle, pcb->rem_bda, result,
299                                   is_role_change, PAN_ROLE_INACTIVE,
300                                   PAN_ROLE_INACTIVE);
301 
302     /* Check if this failure is for role change only */
303     if (pcb->con_state != PAN_STATE_CONNECTED &&
304         (pcb->con_flags & PAN_FLAGS_CONN_COMPLETED)) {
305       /* restore the original values */
306       PAN_TRACE_EVENT("restoring the connection state to active");
307       pcb->con_state = PAN_STATE_CONNECTED;
308       pcb->con_flags &= (~PAN_FLAGS_CONN_COMPLETED);
309 
310       pcb->src_uuid = pcb->prv_src_uuid;
311       pcb->dst_uuid = pcb->prv_dst_uuid;
312       pan_cb.active_role = pan_cb.prv_active_role;
313 
314       if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
315         (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, true);
316 
317       return;
318     }
319 
320     if (pcb->con_state == PAN_STATE_CONNECTED) {
321       /* If the connections destination role is NAP remove bridging */
322       if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
323         (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, false);
324     }
325 
326     pan_cb.num_conns--;
327     pan_release_pcb(pcb);
328     return;
329   }
330 
331   /* Requested destination role is */
332   if (pcb->src_uuid == UUID_SERVCLASS_PANU)
333     pan_cb.active_role = PAN_ROLE_CLIENT;
334   else
335     pan_cb.active_role = PAN_ROLE_NAP_SERVER;
336 
337   if (pcb->dst_uuid == UUID_SERVCLASS_PANU)
338     peer_role = PAN_ROLE_CLIENT;
339   else
340     peer_role = PAN_ROLE_NAP_SERVER;
341 
342   pcb->con_state = PAN_STATE_CONNECTED;
343 
344   /* Inform the application that connection is down */
345   if (pan_cb.pan_conn_state_cb)
346     (*pan_cb.pan_conn_state_cb)(pcb->handle, pcb->rem_bda, PAN_SUCCESS,
347                                 is_role_change, pan_cb.active_role, peer_role);
348 
349   /* Create bridge if the destination role is NAP */
350   if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP) {
351     PAN_TRACE_EVENT("PAN requesting for bridge");
352     (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, true);
353   }
354 }
355 
356 /*******************************************************************************
357  *
358  * Function         pan_data_buf_ind_cb
359  *
360  * Description      This function is registered with BNEP as data buffer
361  *                  indication callback. BNEP will call this when the peer sends
362  *                  any data on this connection. PAN is responsible to release
363  *                  the buffer
364  *
365  * Parameters:      handle      - handle for the connection
366  *                  src         - source BD Addr
367  *                  dst         - destination BD Addr
368  *                  protocol    - Network protocol of the Eth packet
369  *                  p_buf       - pointer to the data buffer
370  *                  ext         - to indicate whether the data contains any
371  *                                         extension headers before the payload
372  *
373  * Returns          none
374  *
375  ******************************************************************************/
pan_data_buf_ind_cb(uint16_t handle,const RawAddress & src,const RawAddress & dst,uint16_t protocol,BT_HDR * p_buf,bool ext)376 void pan_data_buf_ind_cb(uint16_t handle, const RawAddress& src,
377                          const RawAddress& dst, uint16_t protocol,
378                          BT_HDR* p_buf, bool ext) {
379   tPAN_CONN *pcb, *dst_pcb;
380   tBNEP_RESULT result;
381   uint16_t i, len;
382   uint8_t* p_data;
383   bool forward = false;
384 
385   /* Check if the connection is in right state */
386   pcb = pan_get_pcb_by_handle(handle);
387   if (!pcb) {
388     PAN_TRACE_ERROR("PAN Data buffer indication for wrong handle %d", handle);
389     osi_free(p_buf);
390     return;
391   }
392 
393   if (pcb->con_state != PAN_STATE_CONNECTED) {
394     PAN_TRACE_ERROR("PAN Data indication in wrong state %d for handle %d",
395                     pcb->con_state, handle);
396     osi_free(p_buf);
397     return;
398   }
399 
400   p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
401   len = p_buf->len;
402 
403   PAN_TRACE_EVENT(
404       "pan_data_buf_ind_cb - for handle %d, protocol 0x%x, length %d, ext %d",
405       handle, protocol, len, ext);
406 
407   if (pcb->src_uuid == UUID_SERVCLASS_NAP)
408     forward = true;
409   else
410     forward = false;
411 
412   /* Check if it is broadcast or multicast packet */
413   if (pcb->src_uuid != UUID_SERVCLASS_PANU) {
414     if (dst.address[0] & 0x01) {
415       PAN_TRACE_DEBUG(
416           "PAN received broadcast packet on handle %d, src uuid 0x%x", handle,
417           pcb->src_uuid);
418       for (i = 0; i < MAX_PAN_CONNS; i++) {
419         if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
420             pan_cb.pcb[i].handle != handle &&
421             pcb->src_uuid == pan_cb.pcb[i].src_uuid) {
422           BNEP_Write(pan_cb.pcb[i].handle, dst, p_data, len, protocol, &src,
423                      ext);
424         }
425       }
426 
427       if (pan_cb.pan_data_buf_ind_cb)
428         (*pan_cb.pan_data_buf_ind_cb)(pcb->handle, src, dst, protocol, p_buf,
429                                       ext, forward);
430       else if (pan_cb.pan_data_ind_cb)
431         (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len,
432                                   ext, forward);
433 
434       osi_free(p_buf);
435       return;
436     }
437 
438     /* Check if it is for any other PAN connection */
439     dst_pcb = pan_get_pcb_by_addr(dst);
440     if (dst_pcb) {
441       PAN_TRACE_EVENT(
442           "%s - destination PANU found on handle %d and sending data, len: %d",
443           __func__, dst_pcb->handle, len);
444 
445       result =
446           BNEP_Write(dst_pcb->handle, dst, p_data, len, protocol, &src, ext);
447       if (result != BNEP_SUCCESS && result != BNEP_IGNORE_CMD)
448         PAN_TRACE_ERROR("Failed to write data for PAN connection handle %d",
449                         dst_pcb->handle);
450       osi_free(p_buf);
451       return;
452     }
453   }
454 
455   /* Send it over the LAN or give it to host software */
456   if (pan_cb.pan_data_buf_ind_cb)
457     (*pan_cb.pan_data_buf_ind_cb)(pcb->handle, src, dst, protocol, p_buf, ext,
458                                   forward);
459   else if (pan_cb.pan_data_ind_cb)
460     (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len, ext,
461                               forward);
462   osi_free(p_buf);
463   return;
464 }
465 
466 /*******************************************************************************
467  *
468  * Function         pan_proto_filt_ind_cb
469  *
470  * Description      This function is registered with BNEP to receive tx data
471  *          flow status
472  *
473  * Parameters:      handle      - handle for the connection
474  *          event       - flow status
475  *
476  * Returns          none
477  *
478  ******************************************************************************/
pan_tx_data_flow_cb(uint16_t handle,tBNEP_RESULT event)479 void pan_tx_data_flow_cb(uint16_t handle, tBNEP_RESULT event) {
480   if (pan_cb.pan_tx_data_flow_cb) (*pan_cb.pan_tx_data_flow_cb)(handle, event);
481 
482   return;
483 }
484 
485 /*******************************************************************************
486  *
487  * Function         pan_proto_filt_ind_cb
488  *
489  * Description      This function is registered with BNEP as proto filter
490  *                  indication callback. BNEP will call this when the peer sends
491  *                  any protocol filter set for the connection or to indicate
492  *                  the result of the protocol filter set by the local device
493  *
494  * Parameters:      handle      - handle for the connection
495  *                  indication  - true if this is indication
496  *                                false if it is called to give the result of
497  *                                      local device protocol filter set
498  *                  result      - This gives the result of the filter set
499  *                                      operation
500  *                  num_filters - number of filters set by the peer device
501  *                  p_filters   - pointer to the filters set by the peer device
502  *
503  * Returns          none
504  *
505  ******************************************************************************/
pan_proto_filt_ind_cb(uint16_t handle,bool indication,tBNEP_RESULT result,uint16_t num_filters,uint8_t * p_filters)506 void pan_proto_filt_ind_cb(uint16_t handle, bool indication,
507                            tBNEP_RESULT result, uint16_t num_filters,
508                            uint8_t* p_filters) {
509   PAN_TRACE_EVENT(
510       "pan_proto_filt_ind_cb - called for handle %d with ind %d, result %d, "
511       "num %d",
512       handle, indication, result, num_filters);
513 
514   if (pan_cb.pan_pfilt_ind_cb)
515     (*pan_cb.pan_pfilt_ind_cb)(handle, indication, result, num_filters,
516                                p_filters);
517 }
518 
519 /*******************************************************************************
520  *
521  * Function         pan_mcast_filt_ind_cb
522  *
523  * Description      This function is registered with BNEP as mcast filter
524  *                  indication callback. BNEP will call this when the peer sends
525  *                  any multicast filter set for the connection or to indicate
526  *                  the result of the multicast filter set by the local device
527  *
528  * Parameters:      handle      - handle for the connection
529  *                  indication  - true if this is indication
530  *                                false if it is called to give the result of
531  *                                      local device multicast filter set
532  *                  result      - This gives the result of the filter set
533  *                                operation
534  *                  num_filters - number of filters set by the peer device
535  *                  p_filters   - pointer to the filters set by the peer device
536  *
537  * Returns          none
538  *
539  ******************************************************************************/
pan_mcast_filt_ind_cb(uint16_t handle,bool indication,tBNEP_RESULT result,uint16_t num_filters,uint8_t * p_filters)540 void pan_mcast_filt_ind_cb(uint16_t handle, bool indication,
541                            tBNEP_RESULT result, uint16_t num_filters,
542                            uint8_t* p_filters) {
543   PAN_TRACE_EVENT(
544       "pan_mcast_filt_ind_cb - called for handle %d with ind %d, result %d, "
545       "num %d",
546       handle, indication, result, num_filters);
547 
548   if (pan_cb.pan_mfilt_ind_cb)
549     (*pan_cb.pan_mfilt_ind_cb)(handle, indication, result, num_filters,
550                                p_filters);
551 }
552