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