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