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