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