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