aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2005-08-09 23:27:49 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-29 18:54:47 -0400
commit45bb4bf08b9c16122af84d3f26a018c8022b24e5 (patch)
treef8eb941e9ba34345652ab6330ab6b84c8598dec1
parent4aa769b99724953a6f322c648c0cfbe8c6616382 (diff)
[Bluetooth]: Workaround for inquiry results with RSSI and page scan mode
This patch implements a workaround for buggy Bluetooth 1.2 devices from Silicon Wave. Their inquiry results with RSSI contain the page scan mode field. This field was removed in the final Bluetooth 1.2 specification. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/bluetooth/hci.h9
-rw-r--r--net/bluetooth/hci_event.c55
2 files changed, 51 insertions, 13 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 6f0706f4af68..cd075f197983 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -453,6 +453,15 @@ struct inquiry_info_with_rssi {
453 __u16 clock_offset; 453 __u16 clock_offset;
454 __s8 rssi; 454 __s8 rssi;
455} __attribute__ ((packed)); 455} __attribute__ ((packed));
456struct inquiry_info_with_rssi_and_pscan_mode {
457 bdaddr_t bdaddr;
458 __u8 pscan_rep_mode;
459 __u8 pscan_period_mode;
460 __u8 pscan_mode;
461 __u8 dev_class[3];
462 __u16 clock_offset;
463 __s8 rssi;
464} __attribute__ ((packed));
456 465
457#define HCI_EV_CONN_COMPLETE 0x03 466#define HCI_EV_CONN_COMPLETE 0x03
458struct hci_ev_conn_complete { 467struct hci_ev_conn_complete {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 46367bd129c3..632f7a9c2bcb 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -484,14 +484,18 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
484/* Inquiry Result */ 484/* Inquiry Result */
485static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) 485static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
486{ 486{
487 struct inquiry_data data;
487 struct inquiry_info *info = (struct inquiry_info *) (skb->data + 1); 488 struct inquiry_info *info = (struct inquiry_info *) (skb->data + 1);
488 int num_rsp = *((__u8 *) skb->data); 489 int num_rsp = *((__u8 *) skb->data);
489 490
490 BT_DBG("%s num_rsp %d", hdev->name, num_rsp); 491 BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
491 492
493 if (!num_rsp)
494 return;
495
492 hci_dev_lock(hdev); 496 hci_dev_lock(hdev);
497
493 for (; num_rsp; num_rsp--) { 498 for (; num_rsp; num_rsp--) {
494 struct inquiry_data data;
495 bacpy(&data.bdaddr, &info->bdaddr); 499 bacpy(&data.bdaddr, &info->bdaddr);
496 data.pscan_rep_mode = info->pscan_rep_mode; 500 data.pscan_rep_mode = info->pscan_rep_mode;
497 data.pscan_period_mode = info->pscan_period_mode; 501 data.pscan_period_mode = info->pscan_period_mode;
@@ -502,30 +506,55 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
502 info++; 506 info++;
503 hci_inquiry_cache_update(hdev, &data); 507 hci_inquiry_cache_update(hdev, &data);
504 } 508 }
509
505 hci_dev_unlock(hdev); 510 hci_dev_unlock(hdev);
506} 511}
507 512
508/* Inquiry Result With RSSI */ 513/* Inquiry Result With RSSI */
509static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb) 514static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
510{ 515{
511 struct inquiry_info_with_rssi *info = (struct inquiry_info_with_rssi *) (skb->data + 1); 516 struct inquiry_data data;
512 int num_rsp = *((__u8 *) skb->data); 517 int num_rsp = *((__u8 *) skb->data);
513 518
514 BT_DBG("%s num_rsp %d", hdev->name, num_rsp); 519 BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
515 520
521 if (!num_rsp)
522 return;
523
516 hci_dev_lock(hdev); 524 hci_dev_lock(hdev);
517 for (; num_rsp; num_rsp--) { 525
518 struct inquiry_data data; 526 if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
519 bacpy(&data.bdaddr, &info->bdaddr); 527 struct inquiry_info_with_rssi_and_pscan_mode *info =
520 data.pscan_rep_mode = info->pscan_rep_mode; 528 (struct inquiry_info_with_rssi_and_pscan_mode *) (skb->data + 1);
521 data.pscan_period_mode = info->pscan_period_mode; 529
522 data.pscan_mode = 0x00; 530 for (; num_rsp; num_rsp--) {
523 memcpy(data.dev_class, info->dev_class, 3); 531 bacpy(&data.bdaddr, &info->bdaddr);
524 data.clock_offset = info->clock_offset; 532 data.pscan_rep_mode = info->pscan_rep_mode;
525 data.rssi = info->rssi; 533 data.pscan_period_mode = info->pscan_period_mode;
526 info++; 534 data.pscan_mode = info->pscan_mode;
527 hci_inquiry_cache_update(hdev, &data); 535 memcpy(data.dev_class, info->dev_class, 3);
536 data.clock_offset = info->clock_offset;
537 data.rssi = info->rssi;
538 info++;
539 hci_inquiry_cache_update(hdev, &data);
540 }
541 } else {
542 struct inquiry_info_with_rssi *info =
543 (struct inquiry_info_with_rssi *) (skb->data + 1);
544
545 for (; num_rsp; num_rsp--) {
546 bacpy(&data.bdaddr, &info->bdaddr);
547 data.pscan_rep_mode = info->pscan_rep_mode;
548 data.pscan_period_mode = info->pscan_period_mode;
549 data.pscan_mode = 0x00;
550 memcpy(data.dev_class, info->dev_class, 3);
551 data.clock_offset = info->clock_offset;
552 data.rssi = info->rssi;
553 info++;
554 hci_inquiry_cache_update(hdev, &data);
555 }
528 } 556 }
557
529 hci_dev_unlock(hdev); 558 hci_dev_unlock(hdev);
530} 559}
531 560