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 <base/strings/stringprintf.h>
27 #include <string.h> // memset
28
29 #include <cstdint>
30
31 #include "main/shim/dumpsys.h"
32 #include "osi/include/allocator.h"
33 #include "osi/include/log.h"
34 #include "osi/include/osi.h" // UNUSED_ATTR
35 #include "stack/include/bnep_api.h"
36 #include "stack/include/bt_hdr.h"
37 #include "stack/include/btm_log_history.h"
38 #include "stack/include/sdpdefs.h"
39 #include "stack/pan/pan_int.h"
40 #include "types/bluetooth/uuid.h"
41 #include "types/raw_address.h"
42
43 using bluetooth::Uuid;
44
45 tPAN_CB pan_cb;
46
47 /*******************************************************************************
48 *
49 * Function pan_register_with_bnep
50 *
51 * Description This function registers PAN profile with BNEP
52 *
53 * Parameters: none
54 *
55 * Returns none
56 *
57 ******************************************************************************/
pan_register_with_bnep(void)58 void pan_register_with_bnep(void) {
59 tBNEP_REGISTER reg_info;
60
61 memset(®_info, 0, sizeof(tBNEP_REGISTER));
62
63 reg_info.p_conn_ind_cb = pan_conn_ind_cb;
64 reg_info.p_conn_state_cb = pan_connect_state_cb;
65 reg_info.p_data_buf_cb = pan_data_buf_ind_cb;
66 reg_info.p_data_ind_cb = NULL;
67 reg_info.p_tx_data_flow_cb = pan_tx_data_flow_cb;
68 reg_info.p_filter_ind_cb = pan_proto_filt_ind_cb;
69 reg_info.p_mfilter_ind_cb = pan_mcast_filt_ind_cb;
70
71 BNEP_Register(®_info);
72 }
73
74 /*******************************************************************************
75 *
76 * Function pan_conn_ind_cb
77 *
78 * Description This function is registered with BNEP as connection
79 * indication callback. BNEP will call this when there is
80 * connection request from the peer. PAN should call
81 * BNEP_ConnectResp to indicate whether to accept the
82 * connection or reject
83 *
84 * Parameters: handle - handle for the connection
85 * p_bda - BD Addr of the peer requesting the connection
86 * remote_uuid - UUID of the source role (peer device role)
87 * local_uuid - UUID of the destination role (local device
88 * role)
89 * is_role_change - Flag to indicate that it is a role change
90 *
91 * Returns none
92 *
93 ******************************************************************************/
pan_conn_ind_cb(uint16_t handle,const RawAddress & p_bda,const Uuid & remote_uuid,const Uuid & local_uuid,bool is_role_change)94 void pan_conn_ind_cb(uint16_t handle, const RawAddress& p_bda,
95 const Uuid& remote_uuid, const Uuid& local_uuid,
96 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 PAN_TRACE_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 PAN_TRACE_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 PAN_TRACE_EVENT(
119 "%s - handle %d, current role %d, dst uuid 0x%x, src uuid 0x%x, role "
120 "change %s",
121 __func__, handle, pan_cb.role, local_uuid16, remote_uuid16,
122 is_role_change ? "YES" : "NO");
123
124 /* Check if the source UUID is a valid one */
125 if (remote_uuid16 != UUID_SERVCLASS_PANU &&
126 remote_uuid16 != UUID_SERVCLASS_NAP &&
127 remote_uuid16 != UUID_SERVCLASS_GN) {
128 PAN_TRACE_ERROR("Src UUID 0x%x is not valid", remote_uuid16);
129 BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
130 return;
131 }
132
133 /* Check if the destination UUID is a valid one */
134 if (local_uuid16 != UUID_SERVCLASS_PANU &&
135 local_uuid16 != UUID_SERVCLASS_NAP && local_uuid16 != UUID_SERVCLASS_GN) {
136 PAN_TRACE_ERROR("Dst UUID 0x%x is not valid", local_uuid16);
137 BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
138 return;
139 }
140
141 /* Check if currently we support the destination role requested */
142 if (((!(pan_cb.role & UUID_SERVCLASS_PANU)) &&
143 local_uuid16 == UUID_SERVCLASS_PANU) ||
144 ((!(pan_cb.role & UUID_SERVCLASS_GN)) &&
145 local_uuid16 == UUID_SERVCLASS_GN) ||
146 ((!(pan_cb.role & UUID_SERVCLASS_NAP)) &&
147 local_uuid16 == UUID_SERVCLASS_NAP)) {
148 PAN_TRACE_ERROR(
149 "PAN Connection failed because of unsupported destination UUID 0x%x",
150 local_uuid16);
151 BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
152 return;
153 }
154
155 /* Check for valid interactions between the three PAN profile roles */
156 /*
157 * For reference, see Table 1 in PAN Profile v1.0 spec.
158 * Note: the remote is the initiator.
159 */
160 bool is_valid_interaction = false;
161 switch (remote_uuid16) {
162 case UUID_SERVCLASS_NAP:
163 case UUID_SERVCLASS_GN:
164 if (local_uuid16 == UUID_SERVCLASS_PANU) is_valid_interaction = true;
165 break;
166 case UUID_SERVCLASS_PANU:
167 is_valid_interaction = true;
168 break;
169 }
170 /*
171 * Explicitly disable connections to the local PANU if the remote is
172 * not PANU.
173 */
174 if ((local_uuid16 == UUID_SERVCLASS_PANU) &&
175 (remote_uuid16 != UUID_SERVCLASS_PANU)) {
176 is_valid_interaction = false;
177 }
178 if (!is_valid_interaction) {
179 PAN_TRACE_ERROR(
180 "PAN Connection failed because of invalid PAN profile roles "
181 "interaction: Remote UUID 0x%x Local UUID 0x%x",
182 remote_uuid16, local_uuid16);
183 BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
184 return;
185 }
186
187 uint8_t req_role;
188 /* Requested destination role is */
189 if (local_uuid16 == UUID_SERVCLASS_PANU)
190 req_role = PAN_ROLE_CLIENT;
191 else
192 req_role = PAN_ROLE_NAP_SERVER;
193
194 /* If the connection indication is for the existing connection
195 ** Check if the new destination role is acceptable
196 */
197 tPAN_CONN* pcb = pan_get_pcb_by_handle(handle);
198 if (pcb) {
199 if (pan_cb.num_conns > 1 && local_uuid16 == UUID_SERVCLASS_PANU) {
200 /* There are connections other than this one
201 ** so we cann't accept PANU role. Reject
202 */
203 PAN_TRACE_ERROR(
204 "Dst UUID should be either GN or NAP only because there are other "
205 "connections");
206 BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
207 return;
208 }
209
210 /* If it is already in connected state check for bridging status */
211 if (pcb->con_state == PAN_STATE_CONNECTED) {
212 PAN_TRACE_EVENT("PAN Role changing New Src 0x%x Dst 0x%x", remote_uuid16,
213 local_uuid16);
214
215 pcb->prv_src_uuid = pcb->src_uuid;
216 pcb->prv_dst_uuid = pcb->dst_uuid;
217
218 if (pcb->src_uuid == UUID_SERVCLASS_NAP &&
219 local_uuid16 != UUID_SERVCLASS_NAP) {
220 /* Remove bridging */
221 if (pan_cb.pan_bridge_req_cb)
222 (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, false);
223 }
224 }
225 /* Set the latest active PAN role */
226 pan_cb.active_role = req_role;
227 pcb->src_uuid = local_uuid16;
228 pcb->dst_uuid = remote_uuid16;
229 BNEP_ConnectResp(handle, BNEP_SUCCESS);
230 return;
231 } else {
232 /* If this a new connection and destination is PANU role and
233 ** we already have a connection then reject the request.
234 ** If we have a connection in PANU role then reject it
235 */
236 if (pan_cb.num_conns && (local_uuid16 == UUID_SERVCLASS_PANU ||
237 pan_cb.active_role == PAN_ROLE_CLIENT)) {
238 PAN_TRACE_ERROR("PAN already have a connection and can't be user");
239 BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
240 return;
241 }
242 }
243
244 /* This is a new connection */
245 PAN_TRACE_DEBUG("New connection indication for handle %d", handle);
246 pcb = pan_allocate_pcb(p_bda, handle);
247 if (!pcb) {
248 PAN_TRACE_ERROR("PAN no control block for new connection");
249 BNEP_ConnectResp(handle, BNEP_CONN_FAILED);
250 return;
251 }
252
253 PAN_TRACE_EVENT("PAN connection destination UUID is 0x%x", local_uuid16);
254 /* Set the latest active PAN role */
255 pan_cb.active_role = req_role;
256 pcb->src_uuid = local_uuid16;
257 pcb->dst_uuid = remote_uuid16;
258 pcb->con_state = PAN_STATE_CONN_START;
259 pan_cb.num_conns++;
260
261 BNEP_ConnectResp(handle, BNEP_SUCCESS);
262 return;
263 }
264
265 /*******************************************************************************
266 *
267 * Function pan_connect_state_cb
268 *
269 * Description This function is registered with BNEP as connection state
270 * change callback. BNEP will call this when the connection
271 * is established successfully or terminated
272 *
273 * Parameters: handle - handle for the connection given in the connection
274 * indication callback
275 * rem_bda - remote device bd addr
276 * result - indicates whether the connection is up or down
277 * BNEP_SUCCESS if the connection is up all other
278 * values indicate appropriate errors.
279 * is_role_change - flag to indicate that it is a role change
280 *
281 * Returns none
282 *
283 ******************************************************************************/
pan_connect_state_cb(uint16_t handle,UNUSED_ATTR const RawAddress & rem_bda,tBNEP_RESULT result,bool is_role_change)284 void pan_connect_state_cb(uint16_t handle,
285 UNUSED_ATTR const RawAddress& rem_bda,
286 tBNEP_RESULT result, bool is_role_change) {
287 tPAN_CONN* pcb;
288 uint8_t peer_role;
289
290 PAN_TRACE_EVENT("pan_connect_state_cb - for handle %d, result %d", handle,
291 result);
292 pcb = pan_get_pcb_by_handle(handle);
293 if (!pcb) {
294 PAN_TRACE_ERROR("PAN State change indication for wrong handle %d", 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 PAN_TRACE_EVENT("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 PAN_TRACE_EVENT("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 PAN_TRACE_ERROR("PAN Data buffer indication for wrong handle %d", handle);
393 osi_free(p_buf);
394 return;
395 }
396
397 if (pcb->con_state != PAN_STATE_CONNECTED) {
398 PAN_TRACE_ERROR("PAN Data indication in wrong state %d for handle %d",
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 PAN_TRACE_EVENT(
412 "pan_data_buf_ind_cb - for handle %d, protocol 0x%x, length %d, ext %d",
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 PAN_TRACE_DEBUG(
424 "PAN received broadcast packet on handle %d, 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 PAN_TRACE_EVENT(
450 "%s - destination PANU found on handle %d and sending data, len: %d",
451 __func__, 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 PAN_TRACE_ERROR("Failed to write data for PAN connection handle %d",
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 PAN_TRACE_EVENT(
520 "pan_proto_filt_ind_cb - called for handle %d with ind %d, result %d, "
521 "num %d",
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 PAN_TRACE_EVENT(
554 "pan_mcast_filt_ind_cb - called for handle %d with ind %d, result %d, "
555 "num %d",
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