1 /******************************************************************************
3 * Copyright (C) 1999-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * This file contains main functions to support PAN profile
22 * commands and events.
24 ******************************************************************************/
27 #include "bt_common.h"
39 #if PAN_DYNAMIC_MEMORY == FALSE
43 #define UUID_CONSTANT_PART 12
44 UINT8 constant_pan_uuid[UUID_CONSTANT_PART] = {0, 0, 0x10, 0, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
47 /*******************************************************************************
49 ** Function pan_register_with_bnep
51 ** Description This function registers PAN profile with BNEP
57 *******************************************************************************/
58 void pan_register_with_bnep (void)
60 tBNEP_REGISTER reg_info;
62 memset (®_info, 0, sizeof (tBNEP_REGISTER));
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;
72 BNEP_Register (®_info);
76 /*******************************************************************************
78 ** Function pan_conn_ind_cb
80 ** Description This function is registered with BNEP as connection indication
81 ** callback. BNEP will call this when there is connection
82 ** request from the peer. PAN should call BNEP_ConnectResp to
83 ** indicate whether to accept the connection or reject
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 role)
89 ** is_role_change - Flag to indicate that it is a role change
93 *******************************************************************************/
94 void pan_conn_ind_cb (UINT16 handle,
96 tBT_UUID *remote_uuid,
98 BOOLEAN is_role_change)
105 ** If we are in GN or NAP role and have one or more
106 ** active connections and the received connection is
107 ** for user role reject it.
108 ** If we are in user role with one connection active
109 ** reject the connection.
110 ** Allocate PCB and store the parameters
111 ** Make bridge request to the host system if connection
115 if (remote_uuid->len == 16)
118 ** If the UUID is 16 bytes forst two bytes should be zeros
119 ** and last 12 bytes should match the spec defined constant value
121 if (memcmp (constant_pan_uuid, remote_uuid->uu.uuid128 + 4, UUID_CONSTANT_PART))
124 if (remote_uuid->uu.uuid128[0] || remote_uuid->uu.uuid128[1])
127 /* Extract the 16 bit equivalent of the UUID */
128 remote_uuid->uu.uuid16 = (UINT16)((remote_uuid->uu.uuid128[2] << 8) | remote_uuid->uu.uuid128[3]);
129 remote_uuid->len = 2;
131 if (remote_uuid->len == 4)
133 /* First two bytes should be zeros */
134 if (remote_uuid->uu.uuid32 & 0xFFFF0000)
137 remote_uuid->uu.uuid16 = (UINT16)remote_uuid->uu.uuid32;
138 remote_uuid->len = 2;
143 PAN_TRACE_ERROR ("PAN Connection failed because of wrong remote UUID ");
144 BNEP_ConnectResp (handle, BNEP_CONN_FAILED_SRC_UUID);
149 if (local_uuid->len == 16)
152 ** If the UUID is 16 bytes forst two bytes should be zeros
153 ** and last 12 bytes should match the spec defined constant value
155 if (memcmp (constant_pan_uuid, local_uuid->uu.uuid128 + 4, UUID_CONSTANT_PART))
158 if (local_uuid->uu.uuid128[0] || local_uuid->uu.uuid128[1])
161 /* Extract the 16 bit equivalent of the UUID */
162 local_uuid->uu.uuid16 = (UINT16)((local_uuid->uu.uuid128[2] << 8) | local_uuid->uu.uuid128[3]);
165 if (local_uuid->len == 4)
167 /* First two bytes should be zeros */
168 if (local_uuid->uu.uuid32 & 0xFFFF0000)
171 local_uuid->uu.uuid16 = (UINT16)local_uuid->uu.uuid32;
177 PAN_TRACE_ERROR ("PAN Connection failed because of wrong local UUID ");
178 BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
182 PAN_TRACE_EVENT ("pan_conn_ind_cb - for handle %d, current role %d, dst uuid 0x%x, src uuid 0x%x, role change %s",
183 handle, pan_cb.role, local_uuid->uu.uuid16, remote_uuid->uu.uuid16, is_role_change?"YES":"NO");
184 /* The acceptable UUID size is only 2 */
185 if (remote_uuid->len != 2)
187 PAN_TRACE_ERROR ("PAN Connection failed because of wrong UUID size %d", remote_uuid->len);
188 BNEP_ConnectResp (handle, BNEP_CONN_FAILED_UUID_SIZE);
192 /* Check if the source UUID is a valid one */
193 if (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
194 remote_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
195 remote_uuid->uu.uuid16 != UUID_SERVCLASS_GN)
197 PAN_TRACE_ERROR ("Src UUID 0x%x is not valid", remote_uuid->uu.uuid16);
198 BNEP_ConnectResp (handle, BNEP_CONN_FAILED_SRC_UUID);
202 /* Check if the destination UUID is a valid one */
203 if (local_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
204 local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
205 local_uuid->uu.uuid16 != UUID_SERVCLASS_GN)
207 PAN_TRACE_ERROR ("Dst UUID 0x%x is not valid", remote_uuid->uu.uuid16);
208 BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
212 /* Check if currently we support the destination role requested */
213 if (((!(pan_cb.role & UUID_SERVCLASS_PANU))
214 && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) ||
215 ((!(pan_cb.role & UUID_SERVCLASS_GN))
216 && local_uuid->uu.uuid16 == UUID_SERVCLASS_GN) ||
217 ((!(pan_cb.role & UUID_SERVCLASS_NAP))
218 && local_uuid->uu.uuid16 == UUID_SERVCLASS_NAP))
220 PAN_TRACE_ERROR ("PAN Connection failed because of unsupported destination UUID 0x%x", local_uuid->uu.uuid16);
221 BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
225 /* Requested destination role is */
226 if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
227 req_role = PAN_ROLE_CLIENT;
228 else if (local_uuid->uu.uuid16 == UUID_SERVCLASS_GN)
229 req_role = PAN_ROLE_GN_SERVER;
231 req_role = PAN_ROLE_NAP_SERVER;
233 /* If the connection indication is for the existing connection
234 ** Check if the new destination role is acceptable
236 pcb = pan_get_pcb_by_handle (handle);
239 if (pan_cb.num_conns > 1 && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
241 /* There are connections other than this one
242 ** so we cann't accept PANU role. Reject
244 PAN_TRACE_ERROR ("Dst UUID should be either GN or NAP only because there are other connections");
245 BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
249 /* If it is already in connected state check for bridging status */
250 if (pcb->con_state == PAN_STATE_CONNECTED)
252 PAN_TRACE_EVENT ("PAN Role changing New Src 0x%x Dst 0x%x",
253 remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
255 pcb->prv_src_uuid = pcb->src_uuid;
256 pcb->prv_dst_uuid = pcb->dst_uuid;
258 if (pcb->src_uuid == UUID_SERVCLASS_NAP &&
259 local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP)
261 /* Remove bridging */
262 if (pan_cb.pan_bridge_req_cb)
263 (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, FALSE);
266 /* Set the latest active PAN role */
267 pan_cb.active_role = req_role;
268 pcb->src_uuid = local_uuid->uu.uuid16;
269 pcb->dst_uuid = remote_uuid->uu.uuid16;
270 BNEP_ConnectResp (handle, BNEP_SUCCESS);
275 /* If this a new connection and destination is PANU role and
276 ** we already have a connection then reject the request.
277 ** If we have a connection in PANU role then reject it
279 if (pan_cb.num_conns &&
280 (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU ||
281 pan_cb.active_role == PAN_ROLE_CLIENT))
283 PAN_TRACE_ERROR ("PAN already have a connection and can't be user");
284 BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID);
289 /* This is a new connection */
290 PAN_TRACE_DEBUG ("New connection indication for handle %d", handle);
291 pcb = pan_allocate_pcb (p_bda, handle);
294 PAN_TRACE_ERROR ("PAN no control block for new connection");
295 BNEP_ConnectResp (handle, BNEP_CONN_FAILED);
299 PAN_TRACE_EVENT ("PAN connection destination UUID is 0x%x", local_uuid->uu.uuid16);
300 /* Set the latest active PAN role */
301 pan_cb.active_role = req_role;
302 pcb->src_uuid = local_uuid->uu.uuid16;
303 pcb->dst_uuid = remote_uuid->uu.uuid16;
304 pcb->con_state = PAN_STATE_CONN_START;
307 BNEP_ConnectResp (handle, BNEP_SUCCESS);
312 /*******************************************************************************
314 ** Function pan_connect_state_cb
316 ** Description This function is registered with BNEP as connection state
317 ** change callback. BNEP will call this when the connection
318 ** is established successfully or terminated
320 ** Parameters: handle - handle for the connection given in the connection
321 ** indication callback
322 ** rem_bda - remote device bd addr
323 ** result - indicates whether the connection is up or down
324 ** BNEP_SUCCESS if the connection is up
325 ** all other values indicates appropriate errors
326 ** is_role_change - flag to indicate that it is a role change
330 *******************************************************************************/
331 void pan_connect_state_cb (UINT16 handle, BD_ADDR rem_bda, tBNEP_RESULT result, BOOLEAN is_role_change)
337 PAN_TRACE_EVENT ("pan_connect_state_cb - for handle %d, result %d", handle, result);
338 pcb = pan_get_pcb_by_handle (handle);
341 PAN_TRACE_ERROR ("PAN State change indication for wrong handle %d", handle);
345 /* If the connection is getting terminated remove bridging */
346 if (result != BNEP_SUCCESS)
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, result, is_role_change, PAN_ROLE_INACTIVE, PAN_ROLE_INACTIVE);
352 /* Check if this failure is for role change only */
353 if (pcb->con_state != PAN_STATE_CONNECTED &&
354 (pcb->con_flags & PAN_FLAGS_CONN_COMPLETED))
356 /* restore the original values */
357 PAN_TRACE_EVENT ("restoring the connection state to active");
358 pcb->con_state = PAN_STATE_CONNECTED;
359 pcb->con_flags &= (~PAN_FLAGS_CONN_COMPLETED);
361 pcb->src_uuid = pcb->prv_src_uuid;
362 pcb->dst_uuid = pcb->prv_dst_uuid;
363 pan_cb.active_role = pan_cb.prv_active_role;
365 if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
366 (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, TRUE);
371 if (pcb->con_state == PAN_STATE_CONNECTED)
373 /* If the connections destination role is NAP remove bridging */
374 if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
375 (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, FALSE);
379 pan_release_pcb (pcb);
383 /* Requested destination role is */
384 if (pcb->src_uuid == UUID_SERVCLASS_PANU)
385 pan_cb.active_role = PAN_ROLE_CLIENT;
386 else if (pcb->src_uuid == UUID_SERVCLASS_GN)
387 pan_cb.active_role = PAN_ROLE_GN_SERVER;
389 pan_cb.active_role = PAN_ROLE_NAP_SERVER;
391 if (pcb->dst_uuid == UUID_SERVCLASS_PANU)
392 peer_role = PAN_ROLE_CLIENT;
393 else if (pcb->dst_uuid == UUID_SERVCLASS_GN)
394 peer_role = PAN_ROLE_GN_SERVER;
396 peer_role = PAN_ROLE_NAP_SERVER;
398 pcb->con_state = PAN_STATE_CONNECTED;
400 /* Inform the application that connection is down */
401 if (pan_cb.pan_conn_state_cb)
402 (*pan_cb.pan_conn_state_cb) (pcb->handle, pcb->rem_bda, PAN_SUCCESS, is_role_change, pan_cb.active_role, peer_role);
404 /* Create bridge if the destination role is NAP */
405 if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP)
407 PAN_TRACE_EVENT ("PAN requesting for bridge");
408 (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, TRUE);
413 /*******************************************************************************
415 ** Function pan_data_ind_cb
417 ** Description This function is registered with BNEP as data indication
418 ** callback. BNEP will call this when the peer sends any data
419 ** on this connection
421 ** Parameters: handle - handle for the connection
422 ** src - source BD Addr
423 ** dst - destination BD Addr
424 ** protocol - Network protocol of the Eth packet
425 ** p_data - pointer to the data
426 ** len - length of the data
427 ** fw_ext_present - to indicate whether the data contains any
428 ** extension headers before the payload
432 *******************************************************************************/
433 void pan_data_ind_cb (UINT16 handle,
446 ** Check the connection status
447 ** If the destination address is MAC broadcast send on all links
448 ** except on the one received
449 ** If the destination uuid is for NAP send to host system also
450 ** If the destination address is one of the devices connected
451 ** send the packet to over that link
452 ** If the destination address is unknown and destination uuid is NAP
453 ** send it to the host system
456 PAN_TRACE_EVENT ("pan_data_ind_cb - for handle %d", handle);
457 pcb = pan_get_pcb_by_handle (handle);
460 PAN_TRACE_ERROR ("PAN Data indication for wrong handle %d", handle);
464 if (pcb->con_state != PAN_STATE_CONNECTED)
466 PAN_TRACE_ERROR ("PAN Data indication in wrong state %d for handle %d",
467 pcb->con_state, handle);
471 /* Check if it is broadcast packet */
474 PAN_TRACE_DEBUG ("PAN received broadcast packet on handle %d, src uuid 0x%x",
475 handle, pcb->src_uuid);
476 for (i=0; i<MAX_PAN_CONNS; i++)
478 if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
479 pan_cb.pcb[i].handle != handle &&
480 pcb->src_uuid == pan_cb.pcb[i].src_uuid)
482 BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
486 if (pan_cb.pan_data_ind_cb)
487 (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, TRUE);
492 /* Check if it is for any other PAN connection */
493 for (i=0; i<MAX_PAN_CONNS; i++)
495 if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
496 pcb->src_uuid == pan_cb.pcb[i].src_uuid)
498 if (memcmp (pan_cb.pcb[i].rem_bda, dst, BD_ADDR_LEN) == 0)
500 BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
506 if (pcb->src_uuid == UUID_SERVCLASS_NAP)
511 /* Send it over the LAN or give it to host software */
512 if (pan_cb.pan_data_ind_cb)
513 (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
519 /*******************************************************************************
521 ** Function pan_data_buf_ind_cb
523 ** Description This function is registered with BNEP as data buffer indication
524 ** callback. BNEP will call this when the peer sends any data
525 ** on this connection. PAN is responsible to release the buffer
527 ** Parameters: handle - handle for the connection
528 ** src - source BD Addr
529 ** dst - destination BD Addr
530 ** protocol - Network protocol of the Eth packet
531 ** p_buf - pointer to the data buffer
532 ** ext - to indicate whether the data contains any
533 ** extension headers before the payload
537 *******************************************************************************/
538 void pan_data_buf_ind_cb (UINT16 handle,
545 tPAN_CONN *pcb, *dst_pcb;
549 BOOLEAN forward = FALSE;
551 /* Check if the connection is in right state */
552 pcb = pan_get_pcb_by_handle (handle);
555 PAN_TRACE_ERROR ("PAN Data buffer indication for wrong handle %d", handle);
560 if (pcb->con_state != PAN_STATE_CONNECTED)
562 PAN_TRACE_ERROR ("PAN Data indication in wrong state %d for handle %d",
563 pcb->con_state, handle);
568 p_data = (UINT8 *)(p_buf + 1) + p_buf->offset;
571 PAN_TRACE_EVENT ("pan_data_buf_ind_cb - for handle %d, protocol 0x%x, length %d, ext %d",
572 handle, protocol, len, ext);
574 if (pcb->src_uuid == UUID_SERVCLASS_NAP)
579 /* Check if it is broadcast or multicast packet */
580 if (pcb->src_uuid != UUID_SERVCLASS_PANU)
584 PAN_TRACE_DEBUG ("PAN received broadcast packet on handle %d, src uuid 0x%x",
585 handle, pcb->src_uuid);
586 for (i=0; i<MAX_PAN_CONNS; i++)
588 if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
589 pan_cb.pcb[i].handle != handle &&
590 pcb->src_uuid == pan_cb.pcb[i].src_uuid)
592 BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
596 if (pan_cb.pan_data_buf_ind_cb)
597 (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
598 else if (pan_cb.pan_data_ind_cb)
600 (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
607 /* Check if it is for any other PAN connection */
608 dst_pcb = pan_get_pcb_by_addr (dst);
611 PAN_TRACE_EVENT ("%s - destination PANU found on handle %d and sending data, len: %d",
612 __func__, dst_pcb->handle, len);
614 result = BNEP_Write (dst_pcb->handle, dst, p_data, len, protocol, src, ext);
615 if (result != BNEP_SUCCESS && result != BNEP_IGNORE_CMD)
616 PAN_TRACE_ERROR ("Failed to write data for PAN connection handle %d", dst_pcb->handle);
622 /* Send it over the LAN or give it to host software */
623 if (pan_cb.pan_data_buf_ind_cb)
624 (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward);
625 else if (pan_cb.pan_data_ind_cb)
627 (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward);
636 /*******************************************************************************
638 ** Function pan_proto_filt_ind_cb
640 ** Description This function is registered with BNEP to receive tx data
643 ** Parameters: handle - handle for the connection
644 ** event - flow status
648 *******************************************************************************/
649 void pan_tx_data_flow_cb (UINT16 handle,
653 if (pan_cb.pan_tx_data_flow_cb)
654 (*pan_cb.pan_tx_data_flow_cb) (handle, event);
659 /*******************************************************************************
661 ** Function pan_proto_filt_ind_cb
663 ** Description This function is registered with BNEP as proto filter indication
664 ** callback. BNEP will call this when the peer sends any protocol
665 ** filter set for the connection or to indicate the result of the
666 ** protocol filter set by the local device
668 ** Parameters: handle - handle for the connection
669 ** indication - TRUE if this is indication
670 ** FALSE if it is called to give the result of local
671 ** device protocol filter set
672 ** result - This gives the result of the filter set operation
673 ** num_filters - number of filters set by the peer device
674 ** p_filters - pointer to the filters set by the peer device
678 *******************************************************************************/
679 void pan_proto_filt_ind_cb (UINT16 handle,
685 PAN_TRACE_EVENT ("pan_proto_filt_ind_cb - called for handle %d with ind %d, result %d, num %d",
686 handle, indication, result, num_filters);
688 if (pan_cb.pan_pfilt_ind_cb)
689 (*pan_cb.pan_pfilt_ind_cb) (handle, indication, result, num_filters, p_filters);
693 /*******************************************************************************
695 ** Function pan_mcast_filt_ind_cb
697 ** Description This function is registered with BNEP as mcast filter indication
698 ** callback. BNEP will call this when the peer sends any multicast
699 ** filter set for the connection or to indicate the result of the
700 ** multicast filter set by the local device
702 ** Parameters: handle - handle for the connection
703 ** indication - TRUE if this is indication
704 ** FALSE if it is called to give the result of local
705 ** device multicast filter set
706 ** result - This gives the result of the filter set operation
707 ** num_filters - number of filters set by the peer device
708 ** p_filters - pointer to the filters set by the peer device
712 *******************************************************************************/
713 void pan_mcast_filt_ind_cb (UINT16 handle,
719 PAN_TRACE_EVENT ("pan_mcast_filt_ind_cb - called for handle %d with ind %d, result %d, num %d",
720 handle, indication, result, num_filters);
722 if (pan_cb.pan_mfilt_ind_cb)
723 (*pan_cb.pan_mfilt_ind_cb) (handle, indication, result, num_filters, p_filters);