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(®_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(®_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