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