* [Bluez-users] Microsoft IntelliMouse with kernel 2.6.18 and patch-2.6.18-mh1 is broken (fix provided)
@ 2006-09-27 6:29 Andrey Jivsov
2006-09-27 7:52 ` Marcel Holtmann
0 siblings, 1 reply; 5+ messages in thread
From: Andrey Jivsov @ 2006-09-27 6:29 UTC (permalink / raw)
To: bluez-users
Here is my report on successfully configuring IntellMiouse. Also it's a
bug report on latest bluez patch that breaks this mouse.
Microsoft IntelliMouse Explorer for Bluetooth had decent support in
older version of kernel patch, I believe patch-2.6.15-mh2. I could use
scroll wheel and additional buttons. The only issues that I could not
solve satisfactory were smooth activation from sleep, on boot, and
after a timeout. "Smooth" means without reseting the mouse every time by
pressing small button on its bottom.
I decided to give a try to the latest kernel 2.6.18 with Fedora Core 5
and patch-2.6.18-mh1 with latest bluez tools. The start appeared
promising: unpatched kernel 2.6.18 with FC5 and bluez 2.25 enables
IntelliMouse via Boot protocol with the resumption from sleep working!
This is an improvement from earlier versions. This doesn't bring the
closure, though, because the boot protocol lacks the support for scroll
wheel and additional buttons.
I upgraded to bluez 3.5 but this didn't make any difference. I then
patched the kernel with patch-2.6.18-mh1. This killed the mouse: the
cursor would not move.
I finally was able to solve the problem by using the previous
patch-2.6.15-mh2 against the 2.6.18 kernel with minor cleanup. The
patch is here:
http://www.brainhub.org/patch-2.6.18-mh1aj.bz2
Note that it will produce a few harmless warnings.
The above steps result in fully functional IntelliMouse.
Here is the rest of steps needed to fix the resumption from the sleep.
* set this in the rc.local:
/usr/local/sbin/hcid
/usr/local/bin/hidd -t 10 --connect 00:50:F2:E8:E0:71 --server
/usr/local/sbin/hciconfig hci0 down
usleep 500000
/usr/local/sbin/hciconfig hci0 up
* Set this in the "sleep script":
before sleep:
/usr/local/bin/hidd --killall
echo disable > /proc/acpi/ibm/bluetooth
/sbin/rmmod hci_usb
after sleep:
/sbin/modprobe hci_usb
echo enable > /proc/acpi/ibm/bluetooth
Sleep steps above may not be needed at all with your hardware and
distribution.
Many people suggested to use "hidd --connect 00:50:F2:E8:E0:71" alone.
It never work for me. Seems like hciconfig hci0 down/up made the difference.
I hope this helps.
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Bluez-users mailing list
Bluez-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-users
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Bluez-users] Microsoft IntelliMouse with kernel 2.6.18 and patch-2.6.18-mh1 is broken (fix provided)
2006-09-27 6:29 [Bluez-users] Microsoft IntelliMouse with kernel 2.6.18 and patch-2.6.18-mh1 is broken (fix provided) Andrey Jivsov
@ 2006-09-27 7:52 ` Marcel Holtmann
2006-09-27 8:26 ` [Bluez-users] Microsoft IntelliMouse with kernel 2.6.1 " Andrey Jivsov
0 siblings, 1 reply; 5+ messages in thread
From: Marcel Holtmann @ 2006-09-27 7:52 UTC (permalink / raw)
To: BlueZ users
Hi Andrey,
> Microsoft IntelliMouse Explorer for Bluetooth had decent support in
> older version of kernel patch, I believe patch-2.6.15-mh2. I could use
> scroll wheel and additional buttons. The only issues that I could not
> solve satisfactory were smooth activation from sleep, on boot, and
> after a timeout. "Smooth" means without reseting the mouse every time by
> pressing small button on its bottom.
>
> I decided to give a try to the latest kernel 2.6.18 with Fedora Core 5
> and patch-2.6.18-mh1 with latest bluez tools. The start appeared
> promising: unpatched kernel 2.6.18 with FC5 and bluez 2.25 enables
> IntelliMouse via Boot protocol with the resumption from sleep working!
> This is an improvement from earlier versions. This doesn't bring the
> closure, though, because the boot protocol lacks the support for scroll
> wheel and additional buttons.
>
> I upgraded to bluez 3.5 but this didn't make any difference. I then
> patched the kernel with patch-2.6.18-mh1. This killed the mouse: the
> cursor would not move.
>
> I finally was able to solve the problem by using the previous
> patch-2.6.15-mh2 against the 2.6.18 kernel with minor cleanup. The
> patch is here:
>
> http://www.brainhub.org/patch-2.6.18-mh1aj.bz2
>
> Note that it will produce a few harmless warnings.
can you send your changes against a recent 2.6.18-mhX kernel. Sending
the whole patch doesn't help to identify the problem.
Regards
Marcel
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Bluez-users mailing list
Bluez-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-users
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Bluez-users] Microsoft IntelliMouse with kernel 2.6.1 and patch-2.6.18-mh1 is broken (fix provided)
2006-09-27 7:52 ` Marcel Holtmann
@ 2006-09-27 8:26 ` Andrey Jivsov
2006-09-29 11:52 ` Marcel Holtmann
0 siblings, 1 reply; 5+ messages in thread
From: Andrey Jivsov @ 2006-09-27 8:26 UTC (permalink / raw)
To: BlueZ users
[-- Attachment #1: Type: text/plain, Size: 470 bytes --]
Hi Marcel, here is the patch against linux-2.6.18-mh1 to fix
IntelliMouse. That's the best range of changes I have time to provide:
somewhere in these changes IntelliMouse was broken. I believe this
happened between patch-2.6.15-mh2 and linux-2.6.18-mh1. While there are
a lot of changes in these 17 files, but most of them are variable
renames. I hope this helps you to narrow down the issue.
[ Does sending compressed patched works? Trying uncompressed first. ]
[-- Attachment #2: patch-2.6.18-2-mh1aj.diff --]
[-- Type: text/x-patch, Size: 91953 bytes --]
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/drivers/bluetooth/bfusb.c linux-2.6.18-my-bt/drivers/bluetooth/bfusb.c
--- linux-2.6.18-mh1/drivers/bluetooth/bfusb.c 2006-09-23 19:59:12.000000000 -0700
+++ linux-2.6.18-my-bt/drivers/bluetooth/bfusb.c 2006-09-23 22:53:14.000000000 -0700
@@ -2,7 +2,7 @@
*
* AVM BlueFRITZ! USB driver
*
- * Copyright (C) 2003-2006 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -59,6 +59,7 @@
MODULE_DEVICE_TABLE(usb, bfusb_table);
+
#define BFUSB_MAX_BLOCK_SIZE 256
#define BFUSB_BLOCK_TIMEOUT 3000
@@ -69,7 +70,7 @@
#define BFUSB_MAX_BULK_TX 2
#define BFUSB_MAX_BULK_RX 2
-struct bfusb_data {
+struct bfusb {
struct hci_dev *hdev;
unsigned long state;
@@ -91,136 +92,137 @@
struct sk_buff_head completed_q;
};
-struct bfusb_data_scb {
+struct bfusb_scb {
struct urb *urb;
};
static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs);
static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs);
-static struct urb *bfusb_get_completed(struct bfusb_data *data)
+static struct urb *bfusb_get_completed(struct bfusb *bfusb)
{
struct sk_buff *skb;
struct urb *urb = NULL;
- BT_DBG("bfusb %p", data);
+ BT_DBG("bfusb %p", bfusb);
- skb = skb_dequeue(&data->completed_q);
+ skb = skb_dequeue(&bfusb->completed_q);
if (skb) {
- urb = ((struct bfusb_data_scb *) skb->cb)->urb;
+ urb = ((struct bfusb_scb *) skb->cb)->urb;
kfree_skb(skb);
}
return urb;
}
-static void bfusb_unlink_urbs(struct bfusb_data *data)
+static void bfusb_unlink_urbs(struct bfusb *bfusb)
{
struct sk_buff *skb;
struct urb *urb;
- BT_DBG("bfusb %p", data);
+ BT_DBG("bfusb %p", bfusb);
- while ((skb = skb_dequeue(&data->pending_q))) {
- urb = ((struct bfusb_data_scb *) skb->cb)->urb;
+ while ((skb = skb_dequeue(&bfusb->pending_q))) {
+ urb = ((struct bfusb_scb *) skb->cb)->urb;
usb_kill_urb(urb);
- skb_queue_tail(&data->completed_q, skb);
+ skb_queue_tail(&bfusb->completed_q, skb);
}
- while ((urb = bfusb_get_completed(data)))
+ while ((urb = bfusb_get_completed(bfusb)))
usb_free_urb(urb);
}
-static int bfusb_send_bulk(struct bfusb_data *data, struct sk_buff *skb)
+
+static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
{
- struct bfusb_data_scb *scb = (void *) skb->cb;
- struct urb *urb = bfusb_get_completed(data);
+ struct bfusb_scb *scb = (void *) skb->cb;
+ struct urb *urb = bfusb_get_completed(bfusb);
int err, pipe;
- BT_DBG("bfusb %p skb %p len %d", data, skb, skb->len);
+ BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
return -ENOMEM;
- pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
- usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len,
+ usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, skb->len,
bfusb_tx_complete, skb);
scb->urb = urb;
- skb_queue_tail(&data->pending_q, skb);
+ skb_queue_tail(&bfusb->pending_q, skb);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk tx submit failed urb %p err %d",
- data->hdev->name, urb, err);
- skb_unlink(skb, &data->pending_q);
+ bfusb->hdev->name, urb, err);
+ skb_unlink(skb, &bfusb->pending_q);
usb_free_urb(urb);
} else
- atomic_inc(&data->pending_tx);
+ atomic_inc(&bfusb->pending_tx);
return err;
}
-static void bfusb_tx_wakeup(struct bfusb_data *data)
+static void bfusb_tx_wakeup(struct bfusb *bfusb)
{
struct sk_buff *skb;
- BT_DBG("bfusb %p", data);
+ BT_DBG("bfusb %p", bfusb);
- if (test_and_set_bit(BFUSB_TX_PROCESS, &data->state)) {
- set_bit(BFUSB_TX_WAKEUP, &data->state);
+ if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
+ set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
return;
}
do {
- clear_bit(BFUSB_TX_WAKEUP, &data->state);
+ clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
- while ((atomic_read(&data->pending_tx) < BFUSB_MAX_BULK_TX) &&
- (skb = skb_dequeue(&data->transmit_q))) {
- if (bfusb_send_bulk(data, skb) < 0) {
- skb_queue_head(&data->transmit_q, skb);
+ while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
+ (skb = skb_dequeue(&bfusb->transmit_q))) {
+ if (bfusb_send_bulk(bfusb, skb) < 0) {
+ skb_queue_head(&bfusb->transmit_q, skb);
break;
}
}
- } while (test_bit(BFUSB_TX_WAKEUP, &data->state));
+ } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
- clear_bit(BFUSB_TX_PROCESS, &data->state);
+ clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
}
static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
- struct bfusb_data *data = (struct bfusb_data *) skb->dev;
+ struct bfusb *bfusb = (struct bfusb *) skb->dev;
- BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len);
+ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
- atomic_dec(&data->pending_tx);
+ atomic_dec(&bfusb->pending_tx);
- if (!test_bit(HCI_RUNNING, &data->hdev->flags))
+ if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags))
return;
if (!urb->status)
- data->hdev->stat.byte_tx += skb->len;
+ bfusb->hdev->stat.byte_tx += skb->len;
else
- data->hdev->stat.err_tx++;
+ bfusb->hdev->stat.err_tx++;
- read_lock(&data->lock);
+ read_lock(&bfusb->lock);
- skb_unlink(skb, &data->pending_q);
- skb_queue_tail(&data->completed_q, skb);
+ skb_unlink(skb, &bfusb->pending_q);
+ skb_queue_tail(&bfusb->completed_q, skb);
- bfusb_tx_wakeup(data);
+ bfusb_tx_wakeup(bfusb);
- read_unlock(&data->lock);
+ read_unlock(&bfusb->lock);
}
-static int bfusb_rx_submit(struct bfusb_data *data, struct urb *urb)
+static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
{
- struct bfusb_data_scb *scb;
+ struct bfusb_scb *scb;
struct sk_buff *skb;
int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
@@ -229,29 +231,28 @@
if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
return -ENOMEM;
- skb = bt_skb_alloc(size, GFP_ATOMIC);
- if (!skb) {
+ if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) {
usb_free_urb(urb);
return -ENOMEM;
}
- skb->dev = (void *) data;
+ skb->dev = (void *) bfusb;
- scb = (struct bfusb_data_scb *) skb->cb;
+ scb = (struct bfusb_scb *) skb->cb;
scb->urb = urb;
- pipe = usb_rcvbulkpipe(data->udev, data->bulk_in_ep);
+ pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
- usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, size,
+ usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, size,
bfusb_rx_complete, skb);
- skb_queue_tail(&data->pending_q, skb);
+ skb_queue_tail(&bfusb->pending_q, skb);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk rx submit failed urb %p err %d",
- data->hdev->name, urb, err);
- skb_unlink(skb, &data->pending_q);
+ bfusb->hdev->name, urb, err);
+ skb_unlink(skb, &bfusb->pending_q);
kfree_skb(skb);
usb_free_urb(urb);
}
@@ -259,15 +260,15 @@
return err;
}
-static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned char *buf, int len)
+static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
{
- BT_DBG("bfusb %p hdr 0x%02x data %p len %d", data, hdr, buf, len);
+ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
if (hdr & 0x10) {
- BT_ERR("%s error in block", data->hdev->name);
- if (data->reassembly)
- kfree_skb(data->reassembly);
- data->reassembly = NULL;
+ BT_ERR("%s error in block", bfusb->hdev->name);
+ if (bfusb->reassembly)
+ kfree_skb(bfusb->reassembly);
+ bfusb->reassembly = NULL;
return -EIO;
}
@@ -276,46 +277,46 @@
unsigned char pkt_type;
int pkt_len = 0;
- if (data->reassembly) {
- BT_ERR("%s unexpected start block", data->hdev->name);
- kfree_skb(data->reassembly);
- data->reassembly = NULL;
+ if (bfusb->reassembly) {
+ BT_ERR("%s unexpected start block", bfusb->hdev->name);
+ kfree_skb(bfusb->reassembly);
+ bfusb->reassembly = NULL;
}
if (len < 1) {
- BT_ERR("%s no packet type found", data->hdev->name);
+ BT_ERR("%s no packet type found", bfusb->hdev->name);
return -EPROTO;
}
- pkt_type = *buf++; len--;
+ pkt_type = *data++; len--;
switch (pkt_type) {
case HCI_EVENT_PKT:
if (len >= HCI_EVENT_HDR_SIZE) {
- struct hci_event_hdr *hdr = (struct hci_event_hdr *) buf;
+ struct hci_event_hdr *hdr = (struct hci_event_hdr *) data;
pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
} else {
- BT_ERR("%s event block is too short", data->hdev->name);
+ BT_ERR("%s event block is too short", bfusb->hdev->name);
return -EILSEQ;
}
break;
case HCI_ACLDATA_PKT:
if (len >= HCI_ACL_HDR_SIZE) {
- struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) buf;
+ struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) data;
pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
} else {
- BT_ERR("%s data block is too short", data->hdev->name);
+ BT_ERR("%s data block is too short", bfusb->hdev->name);
return -EILSEQ;
}
break;
case HCI_SCODATA_PKT:
if (len >= HCI_SCO_HDR_SIZE) {
- struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) buf;
+ struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) data;
pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
} else {
- BT_ERR("%s audio block is too short", data->hdev->name);
+ BT_ERR("%s audio block is too short", bfusb->hdev->name);
return -EILSEQ;
}
break;
@@ -323,27 +324,27 @@
skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
if (!skb) {
- BT_ERR("%s no memory for the packet", data->hdev->name);
+ BT_ERR("%s no memory for the packet", bfusb->hdev->name);
return -ENOMEM;
}
- skb->dev = (void *) data->hdev;
+ skb->dev = (void *) bfusb->hdev;
bt_cb(skb)->pkt_type = pkt_type;
- data->reassembly = skb;
+ bfusb->reassembly = skb;
} else {
- if (!data->reassembly) {
- BT_ERR("%s unexpected continuation block", data->hdev->name);
+ if (!bfusb->reassembly) {
+ BT_ERR("%s unexpected continuation block", bfusb->hdev->name);
return -EIO;
}
}
if (len > 0)
- memcpy(skb_put(data->reassembly, len), buf, len);
+ memcpy(skb_put(bfusb->reassembly, len), data, len);
if (hdr & 0x08) {
- hci_recv_frame(data->reassembly);
- data->reassembly = NULL;
+ hci_recv_frame(bfusb->reassembly);
+ bfusb->reassembly = NULL;
}
return 0;
@@ -352,22 +353,22 @@
static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
- struct bfusb_data *data = (struct bfusb_data *) skb->dev;
+ struct bfusb *bfusb = (struct bfusb *) skb->dev;
unsigned char *buf = urb->transfer_buffer;
int count = urb->actual_length;
int err, hdr, len;
BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
- read_lock(&data->lock);
+ read_lock(&bfusb->lock);
- if (!test_bit(HCI_RUNNING, &data->hdev->flags))
+ if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags))
goto unlock;
if (urb->status || !count)
goto resubmit;
- data->hdev->stat.byte_rx += count;
+ bfusb->hdev->stat.byte_rx += count;
skb_put(skb, count);
@@ -386,89 +387,90 @@
if (count < len) {
BT_ERR("%s block extends over URB buffer ranges",
- data->hdev->name);
+ bfusb->hdev->name);
}
if ((hdr & 0xe1) == 0xc1)
- bfusb_recv_block(data, hdr, buf, len);
+ bfusb_recv_block(bfusb, hdr, buf, len);
count -= len;
buf += len;
}
- skb_unlink(skb, &data->pending_q);
+ skb_unlink(skb, &bfusb->pending_q);
kfree_skb(skb);
- bfusb_rx_submit(data, urb);
+ bfusb_rx_submit(bfusb, urb);
- read_unlock(&data->lock);
+ read_unlock(&bfusb->lock);
return;
resubmit:
- urb->dev = data->udev;
+ urb->dev = bfusb->udev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk resubmit failed urb %p err %d",
- data->hdev->name, urb, err);
+ bfusb->hdev->name, urb, err);
}
unlock:
- read_unlock(&data->lock);
+ read_unlock(&bfusb->lock);
}
+
static int bfusb_open(struct hci_dev *hdev)
{
- struct bfusb_data *data = hdev->driver_data;
+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
unsigned long flags;
int i, err;
- BT_DBG("hdev %p bfusb %p", hdev, data);
+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return 0;
- write_lock_irqsave(&data->lock, flags);
+ write_lock_irqsave(&bfusb->lock, flags);
- err = bfusb_rx_submit(data, NULL);
+ err = bfusb_rx_submit(bfusb, NULL);
if (!err) {
for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
- bfusb_rx_submit(data, NULL);
+ bfusb_rx_submit(bfusb, NULL);
} else {
clear_bit(HCI_RUNNING, &hdev->flags);
}
- write_unlock_irqrestore(&data->lock, flags);
+ write_unlock_irqrestore(&bfusb->lock, flags);
return err;
}
static int bfusb_flush(struct hci_dev *hdev)
{
- struct bfusb_data *data = hdev->driver_data;
+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
- BT_DBG("hdev %p bfusb %p", hdev, data);
+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
- skb_queue_purge(&data->transmit_q);
+ skb_queue_purge(&bfusb->transmit_q);
return 0;
}
static int bfusb_close(struct hci_dev *hdev)
{
- struct bfusb_data *data = hdev->driver_data;
+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
unsigned long flags;
- BT_DBG("hdev %p bfusb %p", hdev, data);
+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
- write_lock_irqsave(&data->lock, flags);
- write_unlock_irqrestore(&data->lock, flags);
+ write_lock_irqsave(&bfusb->lock, flags);
+ write_unlock_irqrestore(&bfusb->lock, flags);
- bfusb_unlink_urbs(data);
+ bfusb_unlink_urbs(bfusb);
bfusb_flush(hdev);
return 0;
@@ -477,7 +479,7 @@
static int bfusb_send_frame(struct sk_buff *skb)
{
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
- struct bfusb_data *data;
+ struct bfusb *bfusb;
struct sk_buff *nskb;
unsigned char buf[3];
int sent = 0, size, count;
@@ -492,7 +494,7 @@
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
- data = hdev->driver_data;
+ bfusb = (struct bfusb *) hdev->driver_data;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
@@ -512,13 +514,12 @@
count = skb->len;
/* Max HCI frame size seems to be 1511 + 1 */
- nskb = bt_skb_alloc(count + 32, GFP_ATOMIC);
- if (!nskb) {
+ if (!(nskb = bt_skb_alloc(count + 32, GFP_ATOMIC))) {
BT_ERR("Can't allocate memory for new packet");
return -ENOMEM;
}
- nskb->dev = (void *) data;
+ nskb->dev = (void *) bfusb;
while (count) {
size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
@@ -535,18 +536,18 @@
}
/* Don't send frame with multiple size of bulk max packet */
- if ((nskb->len % data->bulk_pkt_size) == 0) {
+ if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
buf[0] = 0xdd;
buf[1] = 0x00;
memcpy(skb_put(nskb, 2), buf, 2);
}
- read_lock(&data->lock);
+ read_lock(&bfusb->lock);
- skb_queue_tail(&data->transmit_q, nskb);
- bfusb_tx_wakeup(data);
+ skb_queue_tail(&bfusb->transmit_q, nskb);
+ bfusb_tx_wakeup(bfusb);
- read_unlock(&data->lock);
+ read_unlock(&bfusb->lock);
kfree_skb(skb);
@@ -555,11 +556,11 @@
static void bfusb_destruct(struct hci_dev *hdev)
{
- struct bfusb_data *data = hdev->driver_data;
+ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
- BT_DBG("hdev %p bfusb %p", hdev, data);
+ BT_DBG("hdev %p bfusb %p", hdev, bfusb);
- kfree(data);
+ kfree(bfusb);
}
static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
@@ -567,24 +568,25 @@
return -ENOIOCTLCMD;
}
-static int bfusb_load_firmware(struct bfusb_data *data, unsigned char *firmware, int count)
+
+static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
{
unsigned char *buf;
int err, pipe, len, size, sent = 0;
- BT_DBG("bfusb %p udev %p", data, data->udev);
+ BT_DBG("bfusb %p udev %p", bfusb, bfusb->udev);
BT_INFO("BlueFRITZ! USB loading firmware");
- pipe = usb_sndctrlpipe(data->udev, 0);
+ pipe = usb_sndctrlpipe(bfusb->udev, 0);
- if (usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ if (usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) {
BT_ERR("Can't change to loading configuration");
return -EBUSY;
}
- data->udev->toggle[0] = data->udev->toggle[1] = 0;
+ bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
if (!buf) {
@@ -592,14 +594,14 @@
return -ENOMEM;
}
- pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
+ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
while (count) {
size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
memcpy(buf, firmware + sent, size);
- err = usb_bulk_msg(data->udev, pipe, buf, size,
+ err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
&len, BFUSB_BLOCK_TIMEOUT);
if (err || (len != size)) {
@@ -611,23 +613,21 @@
count -= size;
}
- err = usb_bulk_msg(data->udev, pipe, NULL, 0,
- &len, BFUSB_BLOCK_TIMEOUT);
- if (err < 0) {
+ if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
+ &len, BFUSB_BLOCK_TIMEOUT)) < 0) {
BT_ERR("Error in null packet request");
goto error;
}
- pipe = usb_sndctrlpipe(data->udev, 0);
+ pipe = usb_sndctrlpipe(bfusb->udev, 0);
- err = usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
- 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
- if (err < 0) {
+ if ((err = usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
BT_ERR("Can't change to running configuration");
goto error;
}
- data->udev->toggle[0] = data->udev->toggle[1] = 0;
+ bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
BT_INFO("BlueFRITZ! USB device ready");
@@ -637,9 +637,9 @@
error:
kfree(buf);
- pipe = usb_sndctrlpipe(data->udev, 0);
+ pipe = usb_sndctrlpipe(bfusb->udev, 0);
- usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
0, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
return err;
@@ -652,7 +652,7 @@
struct usb_host_endpoint *bulk_out_ep;
struct usb_host_endpoint *bulk_in_ep;
struct hci_dev *hdev;
- struct bfusb_data *data;
+ struct bfusb *bfusb;
BT_DBG("intf %p id %p", intf, id);
@@ -672,24 +672,23 @@
}
/* Initialize control structure and load firmware */
- data = kzalloc(sizeof(struct bfusb_data), GFP_KERNEL);
- if (!data) {
+ if (!(bfusb = kzalloc(sizeof(struct bfusb), GFP_KERNEL))) {
BT_ERR("Can't allocate memory for control structure");
goto done;
}
- data->udev = udev;
- data->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress;
- data->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
- data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
-
- rwlock_init(&data->lock);
-
- data->reassembly = NULL;
-
- skb_queue_head_init(&data->transmit_q);
- skb_queue_head_init(&data->pending_q);
- skb_queue_head_init(&data->completed_q);
+ bfusb->udev = udev;
+ bfusb->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress;
+ bfusb->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
+ bfusb->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
+
+ rwlock_init(&bfusb->lock);
+
+ bfusb->reassembly = NULL;
+
+ skb_queue_head_init(&bfusb->transmit_q);
+ skb_queue_head_init(&bfusb->pending_q);
+ skb_queue_head_init(&bfusb->completed_q);
if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
BT_ERR("Firmware request failed");
@@ -698,7 +697,7 @@
BT_DBG("firmware data %p size %d", firmware->data, firmware->size);
- if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) {
+ if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
BT_ERR("Firmware loading failed");
goto release;
}
@@ -712,10 +711,10 @@
goto error;
}
- data->hdev = hdev;
+ bfusb->hdev = hdev;
hdev->type = HCI_USB;
- hdev->driver_data = data;
+ hdev->driver_data = bfusb;
SET_HCIDEV_DEV(hdev, &intf->dev);
hdev->open = bfusb_open;
@@ -733,7 +732,7 @@
goto error;
}
- usb_set_intfdata(intf, data);
+ usb_set_intfdata(intf, bfusb);
return 0;
@@ -741,7 +740,7 @@
release_firmware(firmware);
error:
- kfree(data);
+ kfree(bfusb);
done:
return -EIO;
@@ -749,8 +748,8 @@
static void bfusb_disconnect(struct usb_interface *intf)
{
- struct bfusb_data *data = usb_get_intfdata(intf);
- struct hci_dev *hdev = data->hdev;
+ struct bfusb *bfusb = usb_get_intfdata(intf);
+ struct hci_dev *hdev = bfusb->hdev;
BT_DBG("intf %p", intf);
@@ -780,8 +779,7 @@
BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
- err = usb_register(&bfusb_driver);
- if (err < 0)
+ if ((err = usb_register(&bfusb_driver)) < 0)
BT_ERR("Failed to register BlueFRITZ! USB driver");
return err;
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/drivers/bluetooth/hci_ldisc.c linux-2.6.18-my-bt/drivers/bluetooth/hci_ldisc.c
--- linux-2.6.18-mh1/drivers/bluetooth/hci_ldisc.c 2006-09-23 19:59:12.000000000 -0700
+++ linux-2.6.18-my-bt/drivers/bluetooth/hci_ldisc.c 2006-09-23 22:53:14.000000000 -0700
@@ -241,11 +241,15 @@
static void hci_uart_destruct(struct hci_dev *hdev)
{
+ struct hci_uart *hu;
+
if (!hdev)
return;
BT_DBG("%s", hdev->name);
- kfree(hdev->driver_data);
+
+ hu = (struct hci_uart *) hdev->driver_data;
+ kfree(hu);
}
/* ------ LDISC part ------ */
@@ -268,7 +272,7 @@
return -EEXIST;
if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
- BT_ERR("Can't allocate control structure");
+ BT_ERR("Can't allocate controll structure");
return -ENFILE;
}
@@ -356,7 +360,7 @@
*
* Return Value: None
*/
-static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
+static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
{
struct hci_uart *hu = (void *)tty->disc_data;
@@ -371,8 +375,7 @@
hu->hdev->stat.byte_rx += count;
spin_unlock(&hu->rx_lock);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->unthrottle)
+ if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver->unthrottle)
tty->driver->unthrottle(tty);
}
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/drivers/bluetooth/hci_usb.c linux-2.6.18-my-bt/drivers/bluetooth/hci_usb.c
--- linux-2.6.18-mh1/drivers/bluetooth/hci_usb.c 2006-09-23 19:59:11.000000000 -0700
+++ linux-2.6.18-my-bt/drivers/bluetooth/hci_usb.c 2006-09-23 22:53:13.000000000 -0700
@@ -96,9 +96,6 @@
/* Ericsson with non-standard id */
{ USB_DEVICE(0x0bdb, 0x1002) },
- /* Canyon CN-BTU1 with HID interfaces */
- { USB_DEVICE(0x0c10, 0x0000), .driver_info = HCI_RESET },
-
{ } /* Terminating entry */
};
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/drivers/bluetooth/hci_vhci.c linux-2.6.18-my-bt/drivers/bluetooth/hci_vhci.c
--- linux-2.6.18-mh1/drivers/bluetooth/hci_vhci.c 2006-09-23 19:59:12.000000000 -0700
+++ linux-2.6.18-my-bt/drivers/bluetooth/hci_vhci.c 2006-09-23 22:53:14.000000000 -0700
@@ -2,9 +2,9 @@
*
* Bluetooth virtual HCI driver
*
- * Copyright (C) 2000-2001 Qualcomm Incorporated
- * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -72,21 +72,21 @@
static int vhci_close_dev(struct hci_dev *hdev)
{
- struct vhci_data *data = hdev->driver_data;
+ struct vhci_data *vhci = hdev->driver_data;
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
- skb_queue_purge(&data->readq);
+ skb_queue_purge(&vhci->readq);
return 0;
}
static int vhci_flush(struct hci_dev *hdev)
{
- struct vhci_data *data = hdev->driver_data;
+ struct vhci_data *vhci = hdev->driver_data;
- skb_queue_purge(&data->readq);
+ skb_queue_purge(&vhci->readq);
return 0;
}
@@ -94,7 +94,7 @@
static int vhci_send_frame(struct sk_buff *skb)
{
struct hci_dev* hdev = (struct hci_dev *) skb->dev;
- struct vhci_data *data;
+ struct vhci_data *vhci;
if (!hdev) {
BT_ERR("Frame for unknown HCI device (hdev=NULL)");
@@ -104,15 +104,15 @@
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
- data = hdev->driver_data;
+ vhci = hdev->driver_data;
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
- skb_queue_tail(&data->readq, skb);
+ skb_queue_tail(&vhci->readq, skb);
- if (data->flags & VHCI_FASYNC)
- kill_fasync(&data->fasync, SIGIO, POLL_IN);
+ if (vhci->flags & VHCI_FASYNC)
+ kill_fasync(&vhci->fasync, SIGIO, POLL_IN);
- wake_up_interruptible(&data->read_wait);
+ wake_up_interruptible(&vhci->read_wait);
return 0;
}
@@ -122,7 +122,7 @@
kfree(hdev->driver_data);
}
-static inline ssize_t vhci_get_user(struct vhci_data *data,
+static inline ssize_t vhci_get_user(struct vhci_data *vhci,
const char __user *buf, size_t count)
{
struct sk_buff *skb;
@@ -139,7 +139,7 @@
return -EFAULT;
}
- skb->dev = (void *) data->hdev;
+ skb->dev = (void *) vhci->hdev;
bt_cb(skb)->pkt_type = *((__u8 *) skb->data);
skb_pull(skb, 1);
@@ -148,7 +148,7 @@
return count;
}
-static inline ssize_t vhci_put_user(struct vhci_data *data,
+static inline ssize_t vhci_put_user(struct vhci_data *vhci,
struct sk_buff *skb, char __user *buf, int count)
{
char __user *ptr = buf;
@@ -161,43 +161,42 @@
total += len;
- data->hdev->stat.byte_tx += len;
+ vhci->hdev->stat.byte_tx += len;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
- data->hdev->stat.cmd_tx++;
+ vhci->hdev->stat.cmd_tx++;
break;
case HCI_ACLDATA_PKT:
- data->hdev->stat.acl_tx++;
+ vhci->hdev->stat.acl_tx++;
break;
case HCI_SCODATA_PKT:
- data->hdev->stat.cmd_tx++;
+ vhci->hdev->stat.cmd_tx++;
break;
};
return total;
}
-static loff_t vhci_llseek(struct file *file, loff_t offset, int origin)
+static loff_t vhci_llseek(struct file * file, loff_t offset, int origin)
{
return -ESPIPE;
}
-static ssize_t vhci_read(struct file *file,
- char __user *buf, size_t count, loff_t *pos)
+static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, loff_t *pos)
{
DECLARE_WAITQUEUE(wait, current);
- struct vhci_data *data = file->private_data;
+ struct vhci_data *vhci = file->private_data;
struct sk_buff *skb;
ssize_t ret = 0;
- add_wait_queue(&data->read_wait, &wait);
+ add_wait_queue(&vhci->read_wait, &wait);
while (count) {
set_current_state(TASK_INTERRUPTIBLE);
- skb = skb_dequeue(&data->readq);
+ skb = skb_dequeue(&vhci->readq);
if (!skb) {
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
@@ -214,7 +213,7 @@
}
if (access_ok(VERIFY_WRITE, buf, count))
- ret = vhci_put_user(data, skb, buf, count);
+ ret = vhci_put_user(vhci, skb, buf, count);
else
ret = -EFAULT;
@@ -222,7 +221,7 @@
break;
}
set_current_state(TASK_RUNNING);
- remove_wait_queue(&data->read_wait, &wait);
+ remove_wait_queue(&vhci->read_wait, &wait);
return ret;
}
@@ -230,21 +229,21 @@
static ssize_t vhci_write(struct file *file,
const char __user *buf, size_t count, loff_t *pos)
{
- struct vhci_data *data = file->private_data;
+ struct vhci_data *vhci = file->private_data;
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
- return vhci_get_user(data, buf, count);
+ return vhci_get_user(vhci, buf, count);
}
static unsigned int vhci_poll(struct file *file, poll_table *wait)
{
- struct vhci_data *data = file->private_data;
+ struct vhci_data *vhci = file->private_data;
- poll_wait(file, &data->read_wait, wait);
+ poll_wait(file, &vhci->read_wait, wait);
- if (!skb_queue_empty(&data->readq))
+ if (!skb_queue_empty(&vhci->readq))
return POLLIN | POLLRDNORM;
return POLLOUT | POLLWRNORM;
@@ -258,26 +257,26 @@
static int vhci_open(struct inode *inode, struct file *file)
{
- struct vhci_data *data;
+ struct vhci_data *vhci;
struct hci_dev *hdev;
- data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
- if (!data)
+ vhci = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
+ if (!vhci)
return -ENOMEM;
- skb_queue_head_init(&data->readq);
- init_waitqueue_head(&data->read_wait);
+ skb_queue_head_init(&vhci->readq);
+ init_waitqueue_head(&vhci->read_wait);
hdev = hci_alloc_dev();
if (!hdev) {
- kfree(data);
+ kfree(vhci);
return -ENOMEM;
}
- data->hdev = hdev;
+ vhci->hdev = hdev;
- hdev->type = HCI_VIRTUAL;
- hdev->driver_data = data;
+ hdev->type = HCI_VHCI;
+ hdev->driver_data = vhci;
hdev->open = vhci_open_dev;
hdev->close = vhci_close_dev;
@@ -289,20 +288,20 @@
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
- kfree(data);
+ kfree(vhci);
hci_free_dev(hdev);
return -EBUSY;
}
- file->private_data = data;
+ file->private_data = vhci;
return nonseekable_open(inode, file);
}
static int vhci_release(struct inode *inode, struct file *file)
{
- struct vhci_data *data = file->private_data;
- struct hci_dev *hdev = data->hdev;
+ struct vhci_data *vhci = file->private_data;
+ struct hci_dev *hdev = vhci->hdev;
if (hci_unregister_dev(hdev) < 0) {
BT_ERR("Can't unregister HCI device %s", hdev->name);
@@ -317,17 +316,17 @@
static int vhci_fasync(int fd, struct file *file, int on)
{
- struct vhci_data *data = file->private_data;
+ struct vhci_data *vhci = file->private_data;
int err;
- err = fasync_helper(fd, file, on, &data->fasync);
+ err = fasync_helper(fd, file, on, &vhci->fasync);
if (err < 0)
return err;
if (on)
- data->flags |= VHCI_FASYNC;
+ vhci->flags |= VHCI_FASYNC;
else
- data->flags &= ~VHCI_FASYNC;
+ vhci->flags &= ~VHCI_FASYNC;
return 0;
}
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/include/net/bluetooth/hci_core.h linux-2.6.18-my-bt/include/net/bluetooth/hci_core.h
--- linux-2.6.18-mh1/include/net/bluetooth/hci_core.h 2006-09-23 20:00:59.000000000 -0700
+++ linux-2.6.18-my-bt/include/net/bluetooth/hci_core.h 2006-09-23 22:54:33.000000000 -0700
@@ -165,10 +165,6 @@
struct timer_list disc_timer;
struct timer_list idle_timer;
- struct work_struct work;
-
- struct device dev;
-
struct hci_dev *hdev;
void *l2cap_data;
void *sco_data;
@@ -416,8 +412,6 @@
int hci_register_sysfs(struct hci_dev *hdev);
void hci_unregister_sysfs(struct hci_dev *hdev);
-void hci_conn_add_sysfs(struct hci_conn *conn);
-void hci_conn_del_sysfs(struct hci_conn *conn);
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev))
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/include/net/bluetooth/hci.h linux-2.6.18-my-bt/include/net/bluetooth/hci.h
--- linux-2.6.18-mh1/include/net/bluetooth/hci.h 2006-09-23 20:00:59.000000000 -0700
+++ linux-2.6.18-my-bt/include/net/bluetooth/hci.h 2006-09-23 22:54:33.000000000 -0700
@@ -44,13 +44,12 @@
#define HCI_NOTIFY_VOICE_SETTING 3
/* HCI device types */
-#define HCI_VIRTUAL 0
+#define HCI_VHCI 0
#define HCI_USB 1
#define HCI_PCCARD 2
#define HCI_UART 3
#define HCI_RS232 4
#define HCI_PCI 5
-#define HCI_SDIO 6
/* HCI device quirks */
enum {
@@ -340,8 +339,6 @@
#define OCF_INQUIRY_CANCEL 0x0002
-#define OCF_EXIT_PERIODIC_INQ 0x0004
-
#define OCF_LINK_KEY_REPLY 0x000B
struct hci_cp_link_key_reply {
bdaddr_t bdaddr;
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/include/net/bluetooth/l2cap.h linux-2.6.18-my-bt/include/net/bluetooth/l2cap.h
--- linux-2.6.18-mh1/include/net/bluetooth/l2cap.h 2006-09-23 20:00:59.000000000 -0700
+++ linux-2.6.18-my-bt/include/net/bluetooth/l2cap.h 2006-09-23 23:00:22.000000000 -0700
@@ -27,19 +27,7 @@
/* L2CAP defaults */
#define L2CAP_DEFAULT_MTU 672
-#define L2CAP_MIN_MTU 48
#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
-#define L2CAP_DEFAULT_TXW 32
-#define L2CAP_MIN_TXW 1
-#define L2CAP_MAX_TXW 32
-#define L2CAP_DEFAULT_MAXT 32
-#define L2CAP_DEFAULT_RETTO 1000
-#define L2CAP_DEFAULT_MONTO 1000
-#define L2CAP_DEFAULT_MPS 65531
-#define L2CAP_MAX_MPS 65531
-
-/* maximum possible options for one request/response */
-#define L2CAP_MAX_OPTS 128
#define L2CAP_CONN_TIMEOUT (HZ * 40)
@@ -59,10 +47,6 @@
__u8 mode;
};
-#define L2CAP_MODE_BASIC 0x00
-#define L2CAP_MODE_RET 0x01
-#define L2CAP_MODE_FLOW 0x02
-
#define L2CAP_CONNINFO 0x02
struct l2cap_conninfo {
__u16 hci_handle;
@@ -106,14 +90,8 @@
struct l2cap_cmd_rej {
__le16 reason;
- __le16 data[0];
} __attribute__ ((packed));
-/* command reject reasons */
-#define L2CAP_CMD_NOT_UNDERSTOOD 0x0000
-#define L2CAP_MTU_EXCEEDED 0x0001
-#define L2CAP_INVALID_CID 0x0002
-
struct l2cap_conn_req {
__le16 psm;
__le16 scid;
@@ -151,10 +129,8 @@
__u8 data[0];
} __attribute__ ((packed));
-#define L2CAP_CONF_SUCCESS 0x0000
-#define L2CAP_CONF_UNACCEPT 0x0001
-#define L2CAP_CONF_REJ 0x0002
-#define L2CAP_CONF_UNKNOWN 0x0003
+#define L2CAP_CONF_SUCCESS 0x00
+#define L2CAP_CONF_UNACCEPT 0x01
struct l2cap_conf_opt {
__u8 type;
@@ -170,15 +146,6 @@
#define L2CAP_CONF_MAX_SIZE 22
-struct l2cap_conf_rfc {
- __u8 mode;
- __u8 txw;
- __u8 maxt;
- __le16 ret_to;
- __le16 mon_to;
- __le16 mps;
-} __attribute__ ((packed));
-
struct l2cap_disconn_req {
__le16 dcid;
__le16 scid;
@@ -191,6 +158,7 @@
struct l2cap_info_req {
__le16 type;
+ __u8 data[0];
} __attribute__ ((packed));
struct l2cap_info_rsp {
@@ -200,17 +168,12 @@
} __attribute__ ((packed));
/* info type */
-#define L2CAP_IT_CL_MTU 0x0001
-#define L2CAP_IT_FEAT_MASK 0x0002
-
-/* bits for extended features */
-#define L2CAP_EXT_FCM 0x0001
-#define L2CAP_EXT_RTM 0x0002
-#define L2CAP_EXT_QOS 0x0004
+#define L2CAP_IT_CL_MTU 0x0001
+#define L2CAP_IT_FEAT_MASK 0x0002
/* info result */
-#define L2CAP_IR_SUCCESS 0x0000
-#define L2CAP_IR_NOTSUPP 0x0001
+#define L2CAP_IR_SUCCESS 0x0000
+#define L2CAP_IR_NOTSUPP 0x0001
/* ----- L2CAP connections ----- */
struct l2cap_chan_list {
@@ -250,103 +213,24 @@
__u16 imtu;
__u16 omtu;
__u16 flush_to;
- __u8 mode;
__u32 link_mode;
- /* connectionless MTU size from info response */
- __u16 info_mtu;
- /* extended feature mask from info response */
- __u32 info_ext;
- /* bitmask for current config state */
- __u16 conf_state;
+ __u8 conf_state;
__u8 conf_retry;
__u16 conf_mtu;
- /* Configuration Request RFC Options */
- __u8 conf_mode;
- __u8 conf_txw;
- __u8 conf_maxt;
- __u16 conf_ret_to;
- __u16 conf_mon_to;
- __u16 conf_mps;
-
- /* incoming RFC Options */
- __u8 itxw;
- __u8 imaxt;
- __u16 iret_to;
- __u16 imon_to;
- __u16 imps;
-
- /* outgoing RFC Options */
- __u8 otxw;
- __u8 omaxt;
- __u16 oret_to;
- __u16 omon_to;
- __u16 omps;
-
- /* flow control mode */
- __u8 tx_seq;
- __u8 next_txseq;
- __u8 exp_ackseq;
- __u8 req_seq;
- __u8 exp_txseq;
- __u8 buffer_seq;
- __u16 sdu_len;
- struct sk_buff *sdu;
-
- __u32 tx_queue_frames;
- struct sk_buff_head tx_queue;
-
__u8 ident;
- struct timer_list ret_timer;
- struct timer_list mon_timer;
struct l2cap_conn *conn;
struct sock *next_c;
struct sock *prev_c;
};
-#define L2CAP_CONF_MAX_RETRIES 2
-
-/* different conf_states */
-#define L2CAP_INFO_REQ_SENT 0x01
-#define L2CAP_CONF_REQ_SENT 0x02
-#define L2CAP_CONF_INPUT_DONE 0x04
-#define L2CAP_CONF_OUTPUT_DONE 0x08
-#define L2CAP_CONF_UNACCEPT_MTU 0x10
-#define L2CAP_CONF_UNACCEPT_RFC 0x20
-#define L2CAP_INFO_INPUT_DONE 0x40
-
-/* RFC definitions */
-#define L2CAP_MAX_DATA_LEN 65531
-#define L2CAP_CONTROL_SIZE 2
-#define L2CAP_FCS_SIZE 2
-#define L2CAP_SFRAME_SIZE 8
-
-#define L2CAP_SAR_UNSEGMENTED 0x0000
-#define L2CAP_SAR_START 0x4000
-#define L2CAP_SAR_END 0x8000
-#define L2CAP_SAR_CONTINUE 0xC000
-#define L2CAP_SAR_MASK 0xC000
-#define L2CAP_TXSEQ_MASK 0x007E
-#define L2CAP_REQSEQ_MASK 0x3F00
-
-#define L2CAP_GET_TXSEQ(control) ((__le16_to_cpu(control) \
- & L2CAP_TXSEQ_MASK) >> 1)
-#define L2CAP_GET_REQSEQ(control) ((__le16_to_cpu(control) \
- & L2CAP_REQSEQ_MASK) >> 8)
-#define L2CAP_GET_SAR(control) (__le16_to_cpu(control) & L2CAP_SAR_MASK)
-
-#define L2CAP_SET_TXSEQ(control, txseq) control = \
- (__cpu_to_le16((txseq << 1) & L2CAP_TXSEQ_MASK)) | \
- (__cpu_to_le16(control) & ~L2CAP_TXSEQ_MASK)
-#define L2CAP_SET_REQSEQ(control, reqseq) control = \
- (__cpu_to_le16((reqseq << 8) & L2CAP_REQSEQ_MASK)) | \
- (__cpu_to_le16(control) & ~L2CAP_REQSEQ_MASK)
-#define L2CAP_SET_SAR(control, sar) control = \
- (__cpu_to_le16(sar & L2CAP_SAR_MASK)) | \
- (__cpu_to_le16(control) & ~L2CAP_SAR_MASK)
+#define L2CAP_CONF_REQ_SENT 0x01
+#define L2CAP_CONF_INPUT_DONE 0x02
+#define L2CAP_CONF_OUTPUT_DONE 0x04
+#define L2CAP_CONF_MAX_RETRIES 2
void l2cap_load(void);
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/Makefile linux-2.6.18-my-bt/Makefile
--- linux-2.6.18-mh1/Makefile 2006-09-23 19:55:32.000000000 -0700
+++ linux-2.6.18-my-bt/Makefile 2006-09-24 00:24:58.000000000 -0700
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 18
-EXTRAVERSION = -mh1
+EXTRAVERSION = -mh1aj
NAME=Avast! A bilge rat!
# *DOCUMENTATION*
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/bnep/bnep.h linux-2.6.18-my-bt/net/bluetooth/bnep/bnep.h
--- linux-2.6.18-mh1/net/bluetooth/bnep/bnep.h 2006-09-23 19:56:07.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/bnep/bnep.h 2006-09-23 23:00:22.000000000 -0700
@@ -86,29 +86,29 @@
#define BNEP_EXT_HEADER 0x80
struct bnep_setup_conn_req {
- __u8 type;
- __u8 ctrl;
- __u8 uuid_size;
- __u8 service[0];
+ __u8 type;
+ __u8 ctrl;
+ __u8 uuid_size;
+ __u8 service[0];
} __attribute__((packed));
struct bnep_set_filter_req {
- __u8 type;
- __u8 ctrl;
- __u16 len;
- __u8 list[0];
+ __u8 type;
+ __u8 ctrl;
+ __le16 len;
+ __u8 list[0];
} __attribute__((packed));
struct bnep_control_rsp {
- __u8 type;
- __u8 ctrl;
- __u16 resp;
+ __u8 type;
+ __u8 ctrl;
+ __le16 resp;
} __attribute__((packed));
struct bnep_ext_hdr {
- __u8 type;
- __u8 len;
- __u8 data[0];
+ __u8 type;
+ __u8 len;
+ __u8 data[0];
} __attribute__((packed));
/* BNEP ioctl defines */
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/bnep/core.c linux-2.6.18-my-bt/net/bluetooth/bnep/core.c
--- linux-2.6.18-mh1/net/bluetooth/bnep/core.c 2006-09-23 19:56:06.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/bnep/core.c 2006-09-23 22:46:43.000000000 -0700
@@ -51,7 +51,6 @@
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include "bnep.h"
@@ -516,26 +515,6 @@
return 0;
}
-static struct device *bnep_get_device(struct bnep_session *session)
-{
- bdaddr_t *src = &bt_sk(session->sock->sk)->src;
- bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
- struct hci_dev *hdev;
- struct hci_conn *conn;
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return NULL;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (!conn)
- return NULL;
-
- hci_dev_put(hdev);
-
- return &conn->dev;
-}
-
int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
{
struct net_device *dev;
@@ -555,6 +534,7 @@
if (!dev)
return -ENOMEM;
+
down_write(&bnep_session_sem);
ss = __bnep_get_session(dst);
@@ -571,7 +551,7 @@
memcpy(s->eh.h_source, &dst, ETH_ALEN);
memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
- s->dev = dev;
+ s->dev = dev;
s->sock = sock;
s->role = req->role;
s->state = BT_CONNECTED;
@@ -588,8 +568,6 @@
bnep_set_default_proto_filter(s);
#endif
- SET_NETDEV_DEV(dev, bnep_get_device(s));
-
err = register_netdev(dev);
if (err) {
goto failed;
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/hci_conn.c linux-2.6.18-my-bt/net/bluetooth/hci_conn.c
--- linux-2.6.18-mh1/net/bluetooth/hci_conn.c 2006-09-23 19:56:08.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/hci_conn.c 2006-09-23 22:46:43.000000000 -0700
@@ -179,8 +179,6 @@
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
- hci_conn_add_sysfs(conn);
-
tasklet_enable(&hdev->tx_task);
return conn;
@@ -213,8 +211,6 @@
tasklet_disable(&hdev->tx_task);
- hci_conn_del_sysfs(conn);
-
hci_conn_hash_del(hdev, conn);
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -225,9 +221,7 @@
hci_dev_put(hdev);
- /* will free via device release */
- put_device(&conn->dev);
-
+ kfree(conn);
return 0;
}
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/hci_core.c linux-2.6.18-my-bt/net/bluetooth/hci_core.c
--- linux-2.6.18-mh1/net/bluetooth/hci_core.c 2006-09-23 19:56:07.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/hci_core.c 2006-09-23 22:46:43.000000000 -0700
@@ -850,7 +850,7 @@
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
hdev->link_mode = (HCI_LM_ACCEPT);
- hdev->idle_timeout = HCI_IDLE_TIMEOUT;
+ hdev->idle_timeout = 0;
hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/hci_event.c linux-2.6.18-my-bt/net/bluetooth/hci_event.c
--- linux-2.6.18-mh1/net/bluetooth/hci_event.c 2006-09-23 19:56:06.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/hci_event.c 2006-09-23 22:46:43.000000000 -0700
@@ -62,7 +62,6 @@
switch (ocf) {
case OCF_INQUIRY_CANCEL:
- case OCF_EXIT_PERIODIC_INQ:
status = *((__u8 *) skb->data);
if (status) {
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/hci_sysfs.c linux-2.6.18-my-bt/net/bluetooth/hci_sysfs.c
--- linux-2.6.18-mh1/net/bluetooth/hci_sysfs.c 2006-09-23 19:56:06.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/hci_sysfs.c 2006-09-23 22:46:43.000000000 -0700
@@ -13,32 +13,16 @@
#define BT_DBG(D...)
#endif
-static inline char *typetostr(int type)
+static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
{
- switch (type) {
- case HCI_VIRTUAL:
- return "VIRTUAL";
- case HCI_USB:
- return "USB";
- case HCI_PCCARD:
- return "PCCARD";
- case HCI_UART:
- return "UART";
- case HCI_RS232:
- return "RS232";
- case HCI_PCI:
- return "PCI";
- case HCI_SDIO:
- return "SDIO";
- default:
- return "UNKNOWN";
- }
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", hdev->name);
}
static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", typetostr(hdev->type));
+ return sprintf(buf, "%d\n", hdev->type);
}
static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
@@ -49,6 +33,12 @@
return sprintf(buf, "%s\n", batostr(&bdaddr));
}
+static ssize_t show_flags(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ return sprintf(buf, "0x%lx\n", hdev->flags);
+}
+
static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
@@ -151,8 +141,10 @@
return count;
}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
static DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);
static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
@@ -163,8 +155,10 @@
show_sniff_min_interval, store_sniff_min_interval);
static struct device_attribute *bt_attrs[] = {
+ &dev_attr_name,
&dev_attr_type,
&dev_attr_address,
+ &dev_attr_flags,
&dev_attr_inquiry_cache,
&dev_attr_idle_timeout,
&dev_attr_sniff_max_interval,
@@ -172,32 +166,6 @@
NULL
};
-static ssize_t show_conn_type(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_conn *conn = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", conn->type == ACL_LINK ? "ACL" : "SCO");
-}
-
-static ssize_t show_conn_address(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct hci_conn *conn = dev_get_drvdata(dev);
- bdaddr_t bdaddr;
- baswap(&bdaddr, &conn->dst);
- return sprintf(buf, "%s\n", batostr(&bdaddr));
-}
-
-#define CONN_ATTR(_name,_mode,_show,_store) \
-struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)
-
-static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL);
-static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL);
-
-static struct device_attribute *conn_attrs[] = {
- &conn_attr_type,
- &conn_attr_address,
- NULL
-};
-
struct class *bt_class = NULL;
EXPORT_SYMBOL_GPL(bt_class);
@@ -209,57 +177,8 @@
static void bt_release(struct device *dev)
{
- void *data = dev_get_drvdata(dev);
- kfree(data);
-}
-
-static void add_conn(void *data)
-{
- struct hci_conn *conn = data;
- int i;
-
- device_register(&conn->dev);
-
- for (i = 0; conn_attrs[i]; i++)
- device_create_file(&conn->dev, conn_attrs[i]);
-}
-
-void hci_conn_add_sysfs(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- bdaddr_t *ba = &conn->dst;
-
- BT_DBG("conn %p", conn);
-
- conn->dev.parent = &hdev->dev;
- conn->dev.release = bt_release;
-
- snprintf(conn->dev.bus_id, BUS_ID_SIZE,
- "%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
- conn->type == ACL_LINK ? "acl" : "sco",
- ba->b[5], ba->b[4], ba->b[3],
- ba->b[2], ba->b[1], ba->b[0]);
-
- dev_set_drvdata(&conn->dev, conn);
-
- INIT_WORK(&conn->work, add_conn, (void *) conn);
-
- schedule_work(&conn->work);
-}
-
-static void del_conn(void *data)
-{
- struct hci_conn *conn = data;
- device_del(&conn->dev);
-}
-
-void hci_conn_del_sysfs(struct hci_conn *conn)
-{
- BT_DBG("conn %p", conn);
-
- INIT_WORK(&conn->work, del_conn, (void *) conn);
-
- schedule_work(&conn->work);
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ kfree(hdev);
}
int hci_register_sysfs(struct hci_dev *hdev)
@@ -295,9 +214,11 @@
void hci_unregister_sysfs(struct hci_dev *hdev)
{
+ struct device *dev = &hdev->dev;
+
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
- device_del(&hdev->dev);
+ device_del(dev);
}
int __init bt_sysfs_init(void)
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/hidp/core.c linux-2.6.18-my-bt/net/bluetooth/hidp/core.c
--- linux-2.6.18-mh1/net/bluetooth/hidp/core.c 2006-09-23 19:56:07.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/hidp/core.c 2006-09-23 23:00:22.000000000 -0700
@@ -41,7 +41,6 @@
#include "hid.h"
#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include "hidp.h"
@@ -573,26 +572,6 @@
return 0;
}
-static struct device *hidp_get_device(struct hidp_session *session)
-{
- bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
- bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
- struct hci_dev *hdev;
- struct hci_conn *conn;
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return NULL;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (!conn)
- return NULL;
-
- hci_dev_put(hdev);
-
- return &conn->dev;
-}
-
static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
{
struct input_dev *input = session->input;
@@ -631,8 +610,6 @@
input->relbit[0] |= BIT(REL_WHEEL);
}
- input->cdev.dev = hidp_get_device(session);
-
input->event = hidp_input_event;
input_register_device(input);
@@ -660,8 +637,6 @@
strncpy(hid->phys, batostr(&src), 64);
strncpy(hid->uniq, batostr(&dst), 64);
- hid->dev = hidp_get_device(session);
-
hid->send = hid_send_report;
hid_register_device(hid);
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/l2cap.c linux-2.6.18-my-bt/net/bluetooth/l2cap.c
--- linux-2.6.18-mh1/net/bluetooth/l2cap.c 2006-09-23 19:56:08.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/l2cap.c 2006-09-23 23:00:22.000000000 -0700
@@ -40,20 +40,16 @@
#include <linux/skbuff.h>
#include <linux/list.h>
#include <linux/device.h>
-#include <linux/crc16.h>
#include <net/sock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
-#include <asm/bitops.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
-#define CONFIG_BT_L2CAP_DEBUG
-
#ifndef CONFIG_BT_L2CAP_DEBUG
#undef BT_DBG
#define BT_DBG(D...)
@@ -70,8 +66,6 @@
static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk);
static void l2cap_sock_kill(struct sock *sk);
-static inline int l2cap_do_send_rfc(struct sock *sk);
-static int l2cap_send_sframe(struct sock *sk, u8 reqseq);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
@@ -110,52 +104,6 @@
sk->sk_timer.data = (unsigned long)sk;
}
-static void l2cap_start_ret_timer(struct sock *sk, u16 timeout)
-{
- BT_DBG("sk %p timeout %d", sk, timeout);
- if (timeout <= jiffies) return;
- mod_timer(&l2cap_pi(sk)->ret_timer, timeout);
-}
-
-static void l2cap_start_mon_timer(struct sock *sk, u16 timeout)
-{
- BT_DBG("sk %p timeout %d", sk, timeout);
- if (timeout <= jiffies) return;
- mod_timer(&l2cap_pi(sk)->mon_timer, timeout);
-}
-
-static void l2cap_retransmission_timer(unsigned long data)
-{
- struct sock *sk = (struct sock *) data;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
-
- BT_DBG("sk %p", sk);
-
- pi->exp_ackseq = (pi->exp_ackseq + 1) % 64;
- if (pi->exp_ackseq == pi->next_txseq) {
- l2cap_start_mon_timer(sk, pi->imon_to * HZ / 1000);
- } else {
- l2cap_start_ret_timer(sk, pi->iret_to * HZ / 1000);
-
- lock_sock(sk);
- if (sk->sk_state == BT_CONNECTED)
- l2cap_do_send_rfc(sk);
- release_sock(sk);
- }
-}
-
-static void l2cap_monitor_timer(unsigned long data)
-{
- struct sock *sk = (struct sock *) data;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
-
- BT_DBG("sk %p", sk);
-
- l2cap_send_sframe(sk, pi->exp_txseq);
-
- l2cap_start_mon_timer(sk, pi->imon_to * HZ / 1000);
-}
-
/* ---- L2CAP channels ---- */
static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
{
@@ -410,7 +358,8 @@
struct sock *sk;
struct hlist_node *node;
sk_for_each(sk, node, &l2cap_sk_list.head)
- if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src))
+ if (l2cap_pi(sk)->sport == (__le16 __force) psm &&
+ !bacmp(&bt_sk(sk)->src, src))
goto found;
sk = NULL;
found:
@@ -429,7 +378,7 @@
if (state && sk->sk_state != state)
continue;
- if (l2cap_pi(sk)->psm == psm) {
+ if (l2cap_pi(sk)->psm == (__le16 __force) psm) {
/* Exact match. */
if (!bacmp(&bt_sk(sk)->src, src))
break;
@@ -551,38 +500,16 @@
sk->sk_type = parent->sk_type;
pi->imtu = l2cap_pi(parent)->imtu;
pi->omtu = l2cap_pi(parent)->omtu;
- pi->mode = l2cap_pi(parent)->mode;
pi->link_mode = l2cap_pi(parent)->link_mode;
} else {
pi->imtu = L2CAP_DEFAULT_MTU;
pi->omtu = 0;
- pi->mode = L2CAP_MODE_BASIC;
pi->link_mode = 0;
}
/* Default config options */
pi->conf_mtu = L2CAP_DEFAULT_MTU;
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
- pi->conf_mode = L2CAP_MODE_FLOW;
- pi->conf_txw = L2CAP_DEFAULT_TXW;
- pi->conf_maxt = L2CAP_DEFAULT_MAXT;
- pi->conf_ret_to = L2CAP_DEFAULT_RETTO;
- pi->conf_mon_to = L2CAP_DEFAULT_MONTO;
- pi->conf_mps = L2CAP_DEFAULT_MPS;
-
- pi->next_txseq = 0;
- pi->exp_ackseq = 0;
-
- skb_queue_head_init(&pi->tx_queue);
- pi->tx_queue_frames = 0;
-
- init_timer(&l2cap_pi(sk)->ret_timer);
- l2cap_pi(sk)->ret_timer.function = l2cap_retransmission_timer;
- l2cap_pi(sk)->ret_timer.data = (unsigned long)l2cap_pi(sk);
-
- init_timer(&l2cap_pi(sk)->mon_timer);
- l2cap_pi(sk)->mon_timer.function = l2cap_monitor_timer;
- l2cap_pi(sk)->mon_timer.data = (unsigned long)l2cap_pi(sk);
}
static struct proto l2cap_proto = {
@@ -666,8 +593,8 @@
} else {
/* Save source address */
bacpy(&bt_sk(sk)->src, &la->l2_bdaddr);
- l2cap_pi(sk)->psm = la->l2_psm;
- l2cap_pi(sk)->sport = la->l2_psm;
+ l2cap_pi(sk)->psm = (__le16 __force) la->l2_psm;
+ l2cap_pi(sk)->sport = (__le16 __force) la->l2_psm;
sk->sk_state = BT_BOUND;
}
@@ -779,7 +706,7 @@
/* Set destination address and psm */
bacpy(&bt_sk(sk)->dst, &la->l2_bdaddr);
- l2cap_pi(sk)->psm = la->l2_psm;
+ l2cap_pi(sk)->psm = (__le16 __force) la->l2_psm;
if ((err = l2cap_do_connect(sk)))
goto done;
@@ -908,7 +835,7 @@
else
bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
- la->l2_psm = l2cap_pi(sk)->psm;
+ la->l2_psm = (unsigned short __force) l2cap_pi(sk)->psm;
return 0;
}
@@ -940,7 +867,7 @@
lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
if (sk->sk_type == SOCK_DGRAM)
- put_unaligned(l2cap_pi(sk)->psm, (u16 *) skb_put(skb, 2));
+ put_unaligned(l2cap_pi(sk)->psm, (__le16 *) skb_put(skb, 2));
if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
err = -EFAULT;
@@ -980,164 +907,6 @@
return err;
}
-static inline int l2cap_do_send_rfc(struct sock *sk)
-{
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- struct sk_buff *skb;
- int err = 0;
- u8 occupied;
-
- occupied = (pi->next_txseq - pi->exp_ackseq + 64) % 64;
-
- BT_DBG("sk %p occ %d frames %d", sk, occupied, pi->tx_queue_frames);
-
- /* no frames in TxQueue */
- if (!pi->tx_queue_frames)
- return -1;
-
- if (pi->otxw <= occupied)
- return -1;
-
- while ((pi->tx_queue_frames > 0) && (pi->otxw > occupied)) {
- skb = skb_dequeue(&pi->tx_queue);
- if (skb == NULL) {
- goto fail;
- }
- if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
- goto fail;
-
- pi->tx_queue_frames--;
- occupied++;
- }
-
- return 0;
-
-fail:
- kfree(skb);
- return -1;
-}
-
-static int l2cap_segment_sdu(struct sock *sk, struct msghdr *msg, int len)
-{
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct sk_buff *skb;
- int err, hlen, count, sent = 0;
- struct l2cap_hdr *lh;
- u16 control = 0, fcs, sar;
-
- BT_DBG("sk %p len %d", sk, len);
-
- /* length, cid, control, fcs */
- hlen = L2CAP_HDR_SIZE + 4;
-
- /* count reflects the size of the information payload field */
- count = min_t(unsigned int, (conn->mtu - hlen), len);
-
- /* one single frame */
- if (len == count) {
- skb = bt_skb_send_alloc(sk, hlen + len,
- msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb)
- return err;
-
- /* Create L2CAP header */
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
- lh->len = __cpu_to_le16(len + 4);
-
- L2CAP_SET_SAR(control, L2CAP_SAR_UNSEGMENTED);
- L2CAP_SET_TXSEQ(control, l2cap_pi(sk)->next_txseq);
- L2CAP_SET_REQSEQ(control, l2cap_pi(sk)->exp_txseq);
-
- put_unaligned(__cpu_to_le16(control), (u16 *) skb_put(skb, 2));
-
- if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
- err = -EFAULT;
- goto fail;
- }
-
- /* calculate fcs over information payload plus
- * len, cid and control fields */
- fcs = crc16(0, skb->data, len + 6);
-
- put_unaligned(__cpu_to_le16(fcs), (u16 *) skb_put(skb, 2));
-
- l2cap_pi(sk)->next_txseq = (l2cap_pi(sk)->next_txseq + 1) % 64;
-
- skb_queue_tail(&l2cap_pi(sk)->tx_queue, skb);
- l2cap_pi(sk)->tx_queue_frames++;
-
- sent = len;
-
- goto out;
- }
-
- sar = L2CAP_SAR_START;
- hlen += 2;
- count -= 2;
-
- /* build segmented i-frames */
- while (len) {
- skb = bt_skb_send_alloc(sk, hlen + count,
- msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb)
- return err;
-
- /* Create L2CAP header */
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
- lh->len = __cpu_to_le16(count + hlen - L2CAP_HDR_SIZE);
-
- /* Control and SDU len field */
- L2CAP_SET_SAR(control, sar);
- L2CAP_SET_TXSEQ(control, l2cap_pi(sk)->next_txseq);
- L2CAP_SET_REQSEQ(control, l2cap_pi(sk)->exp_txseq);
-
- put_unaligned(__cpu_to_le16(control), (u16 *) skb_put(skb, 2));
-
- if (sar == L2CAP_SAR_START)
- put_unaligned(__cpu_to_le16(len), (u16 *) skb_put(skb, 2));
-
- /* Information payload */
- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
- err = -EFAULT;
- goto fail;
- }
-
- /* calculate fcs over information payload plus
- * len, cid and control fields (plus sdu len if present) */
- fcs = crc16(0, skb->data, hlen + count);
-
- put_unaligned(__cpu_to_le16(fcs), (u16 *) skb_put(skb, 2));
-
- l2cap_pi(sk)->next_txseq = (l2cap_pi(sk)->next_txseq + 1) % 64;
-
- skb_queue_tail(&l2cap_pi(sk)->tx_queue, skb);
- l2cap_pi(sk)->tx_queue_frames++;
-
- sent += count;
- len -= count;
-
- if (sar == L2CAP_SAR_START) {
- hlen -= 2;
- count += 2;
- }
-
- if (len <= count)
- sar = L2CAP_SAR_END;
- else
- sar = L2CAP_SAR_CONTINUE;
- }
-
-out:
- return sent;
-
-fail:
- kfree_skb(skb);
- return err;
-}
-
static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
@@ -1158,22 +927,11 @@
lock_sock(sk);
- if (!(sk->sk_state == BT_CONNECTED)) {
- err = -ENOTCONN;
- goto out;
- }
-
- if (l2cap_pi(sk)->mode == L2CAP_MODE_FLOW) {
- err = l2cap_segment_sdu(sk, msg, len);
- if (err < 0)
- goto out;
- if (l2cap_do_send_rfc(sk) < 0)
- err = -1;
- } else {
+ if (sk->sk_state == BT_CONNECTED)
err = l2cap_do_send(sk, msg, len);
- }
+ else
+ err = -ENOTCONN;
-out:
release_sock(sk);
return err;
}
@@ -1237,7 +995,7 @@
opts.imtu = l2cap_pi(sk)->imtu;
opts.omtu = l2cap_pi(sk)->omtu;
opts.flush_to = l2cap_pi(sk)->flush_to;
- opts.mode = l2cap_pi(sk)->mode;
+ opts.mode = 0x00;
len = min_t(unsigned int, len, sizeof(opts));
if (copy_to_user(optval, (char *) &opts, len))
@@ -1469,207 +1227,102 @@
return NULL;
}
-/**
- * l2cap_check_conf_opt - checks an incoming option for valid parameters
- * @sk: corresponding socket
- * @option: option that's parameters will be checked
- * @return: result code for this request's option
- *
- * All parameters of a particular option from an incoming request will be
- * checked. The result code for this option (e.g. L2CAP_CONF_UNACCEPT) is
- * returned.
- */
-static inline int l2cap_check_conf_opt(struct sock *sk, int option)
+static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
{
- int result = L2CAP_CONF_SUCCESS;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
+ struct l2cap_conf_opt *opt = *ptr;
+ int len;
+
+ len = L2CAP_CONF_OPT_SIZE + opt->len;
+ *ptr += len;
- switch (option) {
- case L2CAP_CONF_MTU:
- if (pi->conf_mtu < L2CAP_MIN_MTU)
- result = L2CAP_CONF_UNACCEPT;
+ *type = opt->type;
+ *olen = opt->len;
+
+ switch (opt->len) {
+ case 1:
+ *val = *((__u8 *) opt->val);
break;
- case L2CAP_CONF_FLUSH_TO:
+
+ case 2:
+ *val = __le16_to_cpu(*((__le16 *) opt->val));
break;
- case L2CAP_CONF_QOS:
+
+ case 4:
+ *val = __le32_to_cpu(*((__le32 *) opt->val));
break;
- case L2CAP_CONF_RFC:
- if (pi->conf_mode == L2CAP_MODE_BASIC) {
- pi->mode = L2CAP_MODE_BASIC;
- break;
- }
- /* Retransmission Mode not supported yet */
- if (pi->conf_mode != L2CAP_MODE_FLOW) {
- pi->conf_mode = L2CAP_MODE_FLOW;
- result = L2CAP_CONF_UNACCEPT;
- }
- if (pi->conf_txw < 1 || pi->conf_txw > 32) {
- pi->conf_txw = 32;
- result = L2CAP_CONF_UNACCEPT;
- }
- if (pi->conf_maxt < 1) {
- pi->conf_maxt = 8;
- result = L2CAP_CONF_UNACCEPT;
- }
- if (pi->conf_ret_to < 100) {
- pi->conf_ret_to = 1000;
- result = L2CAP_CONF_UNACCEPT;
- }
- if (pi->conf_mon_to < 100) {
- pi->conf_mon_to = 1000;
- result = L2CAP_CONF_UNACCEPT;
- }
+
+ default:
+ *val = (unsigned long) opt->val;
break;
}
- return result;
+ BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
+ return len;
}
-/**
- * l2cap_parse_conf_req - parses a configuration request packet for options
- * @sk: corresponding socket structure
- * @data: conf request data that consists of type, length and option data
- * @len: length of the whole configuration request packet
- * @result: array (128 Bytes) of collected result codes
- *
- * Parses a configuration request that may contain multiple configuration
- * options. Sets the appropriate configuration request parameters from the
- * remote peer if all options are valid and understood. Rejects them if
- * they are malformed and prepares an unknown status for options that we
- * do not support yet.
- */
-static inline void l2cap_parse_conf_req(struct sock *sk, void *data, u16 len, u8 *result)
+static inline void l2cap_parse_conf_req(struct sock *sk, void *data, u16 len)
{
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- int type, hint;
- u8 *ptr = data;
- /* bit flag to avoid multiple examination of already parsed options */
- unsigned long options = 0;
+ int type, hint, olen;
+ unsigned long val;
+ void *ptr = data;
BT_DBG("sk %p len %d", sk, len);
- memset(result, 255, L2CAP_MAX_OPTS);
-
- /* result[0] stays 255 for an empty request */
- if (len != 0)
- result[0] = L2CAP_CONF_SUCCESS;
-
while (len >= L2CAP_CONF_OPT_SIZE) {
- u8 req_len = *(u8 *)(ptr + 1);
-
- /* bail out if req length > packet length */
- if (len < req_len) return;
-
- len -= req_len + 2;
- type = *(u8 *)(ptr + 0);
+ len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val);
hint = type & 0x80;
type &= 0x7f;
switch (type) {
- case 0:
- result[0] = L2CAP_CONF_REJ;
- break;
case L2CAP_CONF_MTU:
- if (test_bit(L2CAP_CONF_MTU, &options))
- break;
- if (req_len != 2) {
- result[0] = L2CAP_CONF_REJ;
- break;
- }
- pi->conf_mtu = __le16_to_cpup((__le16 *)(ptr + 2));
- set_bit(L2CAP_CONF_MTU, &options);
- result[L2CAP_CONF_MTU] = l2cap_check_conf_opt(sk, L2CAP_CONF_MTU);
- if (result[L2CAP_CONF_MTU] == L2CAP_CONF_UNACCEPT)
- result[0] = L2CAP_CONF_UNACCEPT;
-
+ l2cap_pi(sk)->conf_mtu = val;
break;
case L2CAP_CONF_FLUSH_TO:
- if (test_bit(L2CAP_CONF_FLUSH_TO, &options))
- break;
- if (req_len != 2) {
- result[0] = L2CAP_CONF_REJ;
- break;
- }
- pi->flush_to = __le16_to_cpup((__le16 *)(ptr + 2));
- set_bit(L2CAP_CONF_FLUSH_TO, &options);
- result[L2CAP_CONF_FLUSH_TO] = l2cap_check_conf_opt(sk, L2CAP_CONF_FLUSH_TO);
- if (result[L2CAP_CONF_FLUSH_TO] == L2CAP_CONF_UNACCEPT)
- result[0] = L2CAP_CONF_UNACCEPT;
-
+ l2cap_pi(sk)->flush_to = val;
break;
- case L2CAP_CONF_RFC:
- if (test_bit(L2CAP_CONF_RFC, &options))
- break;
- if (req_len != 9) {
- result[0] = L2CAP_CONF_REJ;
- break;
- }
- pi->conf_mode = *(__u8 *)(ptr + 2);
- pi->conf_txw = *(__u8 *)(ptr + 3);
- pi->conf_maxt = *(__u8 *)(ptr + 4);
- pi->conf_ret_to = __le16_to_cpup((__le16 *)(ptr + 5));
- pi->conf_mon_to = __le16_to_cpup((__le16 *)(ptr + 7));
- pi->conf_mps = __le16_to_cpup((__le16 *)(ptr + 9));
- set_bit(L2CAP_CONF_RFC, &options);
- result[L2CAP_CONF_RFC] = l2cap_check_conf_opt(sk, L2CAP_CONF_RFC);
- if (result[L2CAP_CONF_RFC] == L2CAP_CONF_UNACCEPT)
- result[0] = L2CAP_CONF_UNACCEPT;
-
+ case L2CAP_CONF_QOS:
break;
default:
- result[0] = L2CAP_CONF_UNKNOWN;
- result[type] = L2CAP_CONF_UNKNOWN;
- /* TODO: hints are not supported yet */
if (hint)
break;
- }
- /* go to start of (possible) next request */
- ptr += req_len + L2CAP_CONF_OPT_SIZE;
+ /* FIXME: Reject unknown option */
+ break;
+ }
}
}
-/**
- * l2cap_add_conf_opt - adds a configuration option to a rsp or req
- * @ptr: pointer to location where all options are finally stored
- * @data: data for one option (type, len, and all parameters)
- * @type: option type
- * @len: option length
- *
- * Adds a complete configuration parameter option to a configuration
- * response or a configuration request
- */
-static void l2cap_add_conf_opt(void **ptr, void *data, u8 type, u8 len)
+static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
{
struct l2cap_conf_opt *opt = *ptr;
- BT_DBG("type 0x%2.2x len %d", type, len);
+ BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
opt->type = type;
opt->len = len;
- switch (type) {
- case L2CAP_CONF_MTU:
- *((__le16 *) opt->val) = cpu_to_le16(*(__le16 *) data);
+ switch (len) {
+ case 1:
+ *((__u8 *) opt->val) = val;
break;
- case L2CAP_CONF_RFC: {
- struct l2cap_conf_rfc *tmp = (struct l2cap_conf_rfc *) data;
- struct l2cap_conf_rfc *rfc = (struct l2cap_conf_rfc *) opt->val;
- rfc->mode = tmp->mode;
- rfc->txw = tmp->txw;
- rfc->maxt = tmp->maxt;
- rfc->ret_to = tmp->ret_to;
- rfc->mon_to = tmp->mon_to;
- rfc->mps = tmp->mps;
+
+ case 2:
+ *((__le16 *) opt->val) = __cpu_to_le16(val);
+ break;
+
+ case 4:
+ *((__le32 *) opt->val) = __cpu_to_le32(val);
+ break;
+
+ default:
+ memcpy(opt->val, (void *) val, len);
break;
- }
}
- /* increase pointer for next (possible) option */
*ptr += L2CAP_CONF_OPT_SIZE + len;
}
@@ -1677,193 +1330,59 @@
{
struct l2cap_pinfo *pi = l2cap_pi(sk);
struct l2cap_conf_req *req = data;
- void *opts = req->data;
+ void *ptr = req->data;
BT_DBG("sk %p", sk);
- if ((pi->conf_state & L2CAP_CONF_UNACCEPT_MTU) ||
- (pi->imtu != L2CAP_DEFAULT_MTU)) {
- l2cap_add_conf_opt(&opts, &(pi->conf_mtu), L2CAP_CONF_MTU, 2);
- /* clear bit in conf_state */
- pi->conf_state &= (~L2CAP_CONF_UNACCEPT_MTU);
- }
-
- /* either we got unacceptable rfc options in former response
- * or we discovered support for rfc in an information request */
- if ((pi->conf_state & L2CAP_CONF_UNACCEPT_RFC) ||
- (pi->info_ext & L2CAP_EXT_FCM)) {
- struct l2cap_conf_rfc rfc;
- rfc.mode = pi->conf_mode;
- rfc.txw = pi->conf_txw;
- rfc.maxt = pi->conf_maxt;
- rfc.ret_to = pi->conf_ret_to;
- rfc.mon_to = pi->conf_mon_to;
- rfc.mps = pi->conf_mps;
- l2cap_add_conf_opt(&opts, &(pi->conf_mtu), L2CAP_CONF_MTU, 2);
- l2cap_add_conf_opt(&opts, &rfc, L2CAP_CONF_RFC, 9);
- /* clear bit in conf_state */
- pi->conf_state &= (~L2CAP_CONF_UNACCEPT_RFC);
- }
+ if (pi->imtu != L2CAP_DEFAULT_MTU)
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+
+ /* FIXME: Need actual value of the flush timeout */
+ //if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
+ // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
req->dcid = __cpu_to_le16(pi->dcid);
req->flags = __cpu_to_le16(0);
- return opts - data;
+ return ptr - data;
}
-/**
- * l2cap_build_conf_rsp - builds a configuration response
- * @sk: corresponding socket
- * @data: data portion of rsp packet (scid, flags, result, config)
- * @complete: indicates whether C flag is set (0 == incomplete)
- * @result: pointer to collected result codes of result[128]
- *
- * Building a configuration response on base of the collected result codes.
- * The fundamental result code result[0] delegates the action that is taken.
- * For each result[i] that is set appropriately the response packet will be
- * built.
- * Returns the length of the data field in octets of the command only (does
- * not cover the Code, Identifier, and Length field): scid + flags + result +
- * configuration options.
- */
-static int l2cap_build_conf_rsp(struct sock *sk, void *data, int complete, u8 *result)
+static inline int l2cap_conf_output(struct sock *sk, void **ptr)
{
- struct l2cap_conf_rsp *rsp = data;
struct l2cap_pinfo *pi = l2cap_pi(sk);
- void *opts = rsp->data;
- u16 flags = 0;
- int i, len = 0;
-
- BT_DBG("sk %p complete %d", sk, complete);
+ int result = 0;
- switch (result[0]) {
- /* 255 represents the case for an empty request */
- case 255:
+ /* Configure output options and let the other side know
+ * which ones we don't like. */
+ if (pi->conf_mtu < pi->omtu) {
+ l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+ result = L2CAP_CONF_UNACCEPT;
+ } else {
pi->omtu = pi->conf_mtu;
- result[0] = L2CAP_CONF_SUCCESS;
- break;
-
- case L2CAP_CONF_SUCCESS:
- for (i = 1; i < L2CAP_MAX_OPTS; ++i) {
- if (result[i] == L2CAP_CONF_SUCCESS) {
- switch (i) {
- case L2CAP_CONF_MTU:
- pi->omtu = pi->conf_mtu;
- len = 2;
- l2cap_add_conf_opt(&opts, &(pi->omtu), i, len);
- break;
- case L2CAP_CONF_RFC: {
- struct l2cap_conf_rfc params;
- struct l2cap_conf_rfc *rfc = ¶ms;
- pi->mode = pi->conf_mode;
- pi->otxw = pi->conf_txw;
- pi->omaxt = pi->conf_maxt;
- pi->oret_to = pi->conf_ret_to;
- pi->omon_to = pi->conf_mon_to;
- pi->omps = pi->conf_mps;
- len = 9;
- rfc->mode = pi->mode;
- rfc->txw = pi->otxw;
- rfc->maxt = pi->omaxt;
- rfc->ret_to = pi->oret_to;
- rfc->mon_to = pi->omon_to;
- rfc->mps = pi->omps;
- l2cap_add_conf_opt(&opts, rfc, i, len);
- break;
- }
- }
- }
- }
- break;
-
- case L2CAP_CONF_UNACCEPT:
- for (i = 1; i < L2CAP_MAX_OPTS; ++i) {
- if (result[i] == L2CAP_CONF_UNACCEPT) {
- switch (i) {
- case L2CAP_CONF_MTU: {
- __le16 mtu = L2CAP_DEFAULT_MTU;
- len = 2;
- l2cap_add_conf_opt(&opts, &mtu, i, len);
- break;
- }
- case L2CAP_CONF_RFC: {
- struct l2cap_conf_rfc params;
- struct l2cap_conf_rfc *rfc = ¶ms;
- rfc->mode = pi->conf_mode;
- rfc->txw = pi->conf_txw;
- rfc->maxt = pi->conf_maxt;
- rfc->ret_to = pi->conf_ret_to;
- rfc->mon_to = pi->conf_mon_to;
- rfc->mps = pi->conf_mps;
- len = 9;
- l2cap_add_conf_opt(&opts, rfc, i, len);
- break;
- }
- }
- }
- }
- break;
-
- case L2CAP_CONF_REJ:
- /* send plain reject response */
- l2cap_add_conf_opt(&opts, NULL, 0, 0);
- break;
-
- case L2CAP_CONF_UNKNOWN:
- for (i = 1; i < L2CAP_MAX_OPTS; ++i) {
- if (result[i] == L2CAP_CONF_UNKNOWN) {
- l2cap_add_conf_opt(&opts, NULL, i, 0);
- }
- }
- break;
}
- rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
- rsp->result = __cpu_to_le16(result[0] == 255 ? 0 : result[0]);
- rsp->flags = __cpu_to_le16(flags);
-
- /* return length of actual data */
- return opts - data;
-}
-
-static int l2cap_build_info_req(void *data)
-{
- struct l2cap_info_req *info = data;
- u8 len = 2;
-
- info->type = __cpu_to_le16(L2CAP_IT_FEAT_MASK);
-
- return len;
+ BT_DBG("sk %p result %d", sk, result);
+ return result;
}
-static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result)
{
- struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
- u16 reason;
- u8 len; /* depends on reason code */
- __le16 *ptr = rej->data;
+ struct l2cap_conf_rsp *rsp = data;
+ void *ptr = rsp->data;
+ u16 flags = 0;
- reason = __le16_to_cpu(rej->reason);
+ BT_DBG("sk %p complete %d", sk, result ? 1 : 0);
- BT_DBG("reason 0x%4.4x", reason);
+ if (result)
+ *result = l2cap_conf_output(sk, &ptr);
+ else
+ flags = 0x0001;
- switch (reason) {
- case L2CAP_CMD_NOT_UNDERSTOOD:
- len = 0;
- break;
- case L2CAP_MTU_EXCEEDED:
- len = 2;
- BT_DBG("max acceptable signalling MTU 0x%02X", ptr[0]);
- break;
- case L2CAP_INVALID_CID:
- len = 4;
- BT_DBG("invalid channel 0x%04X 0x%04X", ptr[0], ptr[1]);
- break;
- default:
- return reason;
- }
+ rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+ rsp->result = __cpu_to_le16(result ? *result : 0);
+ rsp->flags = __cpu_to_le16(flags);
- return 0;
+ return ptr - data;
}
static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
@@ -1875,12 +1394,12 @@
int result = 0, status = 0;
u16 dcid = 0, scid = __le16_to_cpu(req->scid);
- u16 psm = req->psm;
+ __le16 psm = req->psm;
BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
/* Check if we have socket listening on psm */
- parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
+ parent = l2cap_get_sock_by_psm(BT_LISTEN, (u16 __force) psm, conn->src);
if (!parent) {
result = L2CAP_CR_BAD_PSM;
goto sendresp;
@@ -1959,7 +1478,7 @@
struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
u16 scid, dcid, result, status;
struct sock *sk;
- u16 info;
+ u8 req[128];
scid = __le16_to_cpu(rsp->scid);
dcid = __le16_to_cpu(rsp->dcid);
@@ -1979,12 +1498,12 @@
switch (result) {
case L2CAP_CR_SUCCESS:
sk->sk_state = BT_CONFIG;
- l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+ l2cap_pi(sk)->ident = 0;
l2cap_pi(sk)->dcid = dcid;
- /* send information request first */
- l2cap_pi(sk)->conf_state |= L2CAP_INFO_REQ_SENT;
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_INFO_REQ,
- l2cap_build_info_req(&info), &info);
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, req), req);
break;
case L2CAP_CR_PEND:
@@ -2002,13 +1521,10 @@
static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
{
struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
- u16 dcid, flags;
- u8 rsp[128];
+ u16 dcid, flags, cmd_len = __le16_to_cpu(cmd->len);
+ u8 rsp[64];
struct sock *sk;
- /* collected result codes for theor. max 128 possible options
- * result[0] indicates the general result code for all options */
- u8 result[L2CAP_MAX_OPTS];
- int temp_len;
+ int result;
dcid = __le16_to_cpu(req->dcid);
flags = __le16_to_cpu(req->flags);
@@ -2018,41 +1534,32 @@
if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
return -ENOENT;
- l2cap_parse_conf_req(sk, req->data, cmd->len - sizeof(*req), result);
+ l2cap_parse_conf_req(sk, req->data, cmd_len - sizeof(*req));
if (flags & 0x0001) {
/* Incomplete config. Send empty response. */
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
- l2cap_build_conf_rsp(sk, rsp, 0, NULL), rsp);
+ l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
goto unlock;
}
/* Complete config. */
- temp_len = l2cap_build_conf_rsp(sk, rsp, 1, result);
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
- temp_len, rsp);
+ l2cap_build_conf_rsp(sk, rsp, &result), rsp);
- if (result[0])
+ if (result)
goto unlock;
/* Output config done */
l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
- l2cap_pi(sk)->ident = l2cap_get_ident(conn);
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
sk->sk_state = BT_CONNECTED;
l2cap_chan_ready(sk);
- } /* don't send conf req if we still await an information rsp */
- else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) &&
- (l2cap_pi(sk)->conf_state & L2CAP_INFO_INPUT_DONE)) {
- u8 req[128];
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONF_REQ,
+ } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
+ u8 req[64];
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
- } /* send information request */
- else {
- u16 info;
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_INFO_REQ,
- l2cap_build_info_req(&info), &info);
}
unlock:
@@ -2062,14 +1569,9 @@
static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
{
- struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *) data;
- u16 scid, flags, result, len;
+ struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
+ u16 scid, flags, result;
struct sock *sk;
- struct l2cap_pinfo *pi;
- u8 type;
- u8 *ptr = rsp->data;
- /* length of all options in config data field */
- len = __le16_to_cpu(cmd->len) - sizeof(*rsp);
scid = __le16_to_cpu(rsp->scid);
flags = __le16_to_cpu(rsp->flags);
@@ -2079,96 +1581,23 @@
if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
return 0;
- pi = l2cap_pi(sk);
switch (result) {
case L2CAP_CONF_SUCCESS:
- while (len >= L2CAP_CONF_OPT_SIZE) {
- u8 rsp_len = *(u8 *)(ptr + 1);
- /* bail out if rsp len > packet len */
- if (len < rsp_len) return 0;
-
- len -= rsp_len + 2;
- type = *(u8 *)(ptr + 0);
-
- switch (type) {
- case L2CAP_CONF_MTU:
- pi->imtu = *(__le16 *)(ptr + 2);
- break;
- case L2CAP_CONF_RFC:
- pi->mode = *(u8 *)(ptr + 2);
- pi->itxw = *(u8 *)(ptr + 3);
- pi->imaxt = *(u8 *)(ptr + 4);
- pi->iret_to = __le16_to_cpup((__le16 *)(ptr + 5));
- pi->imon_to = __le16_to_cpup((__le16 *)(ptr + 7));
- pi->imps = __le16_to_cpup((__le16 *)(ptr + 9));
- break;
- }
-
- /* go to start of (possible) next request */
- ptr += rsp_len + L2CAP_CONF_OPT_SIZE;
- }
break;
- case L2CAP_CONF_UNACCEPT: {
- u8 req[128];
- while (len >= L2CAP_CONF_OPT_SIZE) {
- u8 rsp_len = *(u8 *)(ptr + 1);
- /* bail out if rsp len > packet len */
- if (len < rsp_len) return 0;
-
- len -= rsp_len + 2;
- type = *(u8 *)(ptr + 0);
-
- switch (type) {
- case L2CAP_CONF_MTU:
- pi->conf_mtu = *(__le16 *)(ptr + 2);
- /* add MTU option to new request */
- pi->conf_state |= L2CAP_CONF_UNACCEPT_MTU;
- break;
- case L2CAP_CONF_RFC:
- pi->conf_mode = *(u8 *)(ptr + 2);
- pi->conf_txw = *(u8 *)(ptr + 3);
- pi->conf_maxt = *(u8 *)(ptr + 4);
- pi->conf_ret_to = __le16_to_cpup((__le16 *)(ptr + 5));
- pi->conf_mon_to = __le16_to_cpup((__le16 *)(ptr + 7));
- pi->conf_mps = __le16_to_cpup((__le16 *)(ptr + 9));
- /* add RFC option to new request */
- pi->conf_state |= L2CAP_CONF_UNACCEPT_RFC;
- break;
- }
-
- /* go to start of (possible) next request */
- ptr += rsp_len + L2CAP_CONF_OPT_SIZE;
- }
- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(sk, req), req);
- goto done;
- }
-
- case L2CAP_CONF_UNKNOWN: {
- u8 req[128];
- while (len >= L2CAP_CONF_OPT_SIZE) {
- u8 rsp_len = *(u8 *)(ptr + 1);
- /* bail out if rsp len > packet len */
- if (len < rsp_len) return 0;
-
- len -= rsp_len + 2;
- type = *(u8 *)(ptr + 0);
-
- switch (type) {
- case L2CAP_CONF_RFC:
- pi->conf_mode = L2CAP_MODE_BASIC;
- break;
- }
-
- /* go to start of (possible) next request */
- ptr += rsp_len + L2CAP_CONF_OPT_SIZE;
+ case L2CAP_CONF_UNACCEPT:
+ if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) {
+ char req[128];
+ /* It does not make sense to adjust L2CAP parameters
+ * that are currently defined in the spec. We simply
+ * resend config request that we sent earlier. It is
+ * stupid, but it helps qualification testing which
+ * expects at least some response from us. */
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, req), req);
+ goto done;
}
- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(sk, req), req);
- goto done;
- }
default:
sk->sk_state = BT_DISCONN;
@@ -2253,8 +1682,6 @@
{
struct l2cap_info_req *req = (struct l2cap_info_req *) data;
struct l2cap_info_rsp rsp;
- /* length of data field in information response */
- u8 len_data;
u16 type;
type = __le16_to_cpu(req->type);
@@ -2262,26 +1689,8 @@
BT_DBG("type 0x%4.4x", type);
rsp.type = __cpu_to_le16(type);
- switch (type) {
- case L2CAP_IT_CL_MTU:
- len_data = 2;
- rsp.result = __cpu_to_le16(L2CAP_IR_SUCCESS);
- *(__le16 *)(rsp.data) = __cpu_to_le16(L2CAP_DEFAULT_MTU);
- break;
- case L2CAP_IT_FEAT_MASK:
- len_data = 4;
- rsp.result = __cpu_to_le16(L2CAP_IR_SUCCESS);
- /* currently only Flow Control Mode supported */
- *(__le32 *)(rsp.data) = __cpu_to_le32(L2CAP_EXT_FCM);
- break;
- default:
- len_data = 0;
- rsp.result = __cpu_to_le16(L2CAP_IR_NOTSUPP);
- break;
- }
-
- /* send information response */
- l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp) + len_data, &rsp);
+ rsp.result = __cpu_to_le16(L2CAP_IR_NOTSUPP);
+ l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
return 0;
}
@@ -2290,40 +1699,11 @@
{
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
u16 type, result;
- struct sock *sk;
- u8 req[128];
- u8 *ptr = rsp->data;
type = __le16_to_cpu(rsp->type);
result = __le16_to_cpu(rsp->result);
- BT_DBG("type 0x%4.4x result 0x%2.2x ident %d", type, result, cmd->ident);
-
- if (!(sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident)))
- return 0;
-
- if (result == L2CAP_IR_SUCCESS) {
- switch (type) {
- case L2CAP_IT_CL_MTU:
- l2cap_pi(sk)->info_mtu = __le16_to_cpup((__le16 *) ptr);
- break;
- case L2CAP_IT_FEAT_MASK:
- if (*ptr & L2CAP_EXT_FCM)
- l2cap_pi(sk)->info_ext |= L2CAP_EXT_FCM;
- break;
- }
- } else {
- l2cap_pi(sk)->conf_mode = L2CAP_MODE_BASIC;
- }
-
- l2cap_pi(sk)->conf_state |= L2CAP_INFO_INPUT_DONE;
-
- /* build configuration request */
- l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(sk, req), req);
-
- bh_unlock_sock(sk);
+ BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
return 0;
}
@@ -2333,6 +1713,7 @@
u8 *data = skb->data;
int len = skb->len;
struct l2cap_cmd_hdr cmd;
+ u16 cmd_len;
int err = 0;
l2cap_raw_recv(conn, skb);
@@ -2342,18 +1723,18 @@
data += L2CAP_CMD_HDR_SIZE;
len -= L2CAP_CMD_HDR_SIZE;
- cmd.len = __le16_to_cpu(cmd.len);
+ cmd_len = __le16_to_cpu(cmd.len);
- BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
+ BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, cmd.ident);
- if (cmd.len > len || !cmd.ident) {
+ if (cmd_len > len || !cmd.ident) {
BT_DBG("corrupted command");
break;
}
switch (cmd.code) {
case L2CAP_COMMAND_REJ:
- err = l2cap_command_rej(conn, &cmd, data);
+ /* FIXME: We should process this */
break;
case L2CAP_CONN_REQ:
@@ -2381,7 +1762,7 @@
break;
case L2CAP_ECHO_REQ:
- l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
+ l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, cmd_len, data);
break;
case L2CAP_ECHO_RSP:
@@ -2410,245 +1791,13 @@
l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
}
- data += cmd.len;
- len -= cmd.len;
+ data += cmd_len;
+ len -= cmd_len;
}
kfree_skb(skb);
}
-static int l2cap_send_sframe(struct sock *sk, u8 reqseq)
-{
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- struct sk_buff *skb = NULL;
- struct l2cap_hdr *lh;
- __le16 *control, *fcs;
- int err = 0;
-
- BT_DBG("sk %p reqseq %d", sk, reqseq);
-
- skb = bt_skb_send_alloc(sk, L2CAP_SFRAME_SIZE, MSG_DONTWAIT, &err);
- if (!skb)
- return err;
-
- /* Create L2CAP header */
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
- lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
- lh->len = __cpu_to_le16(4);
-
- /* Create control field */
- control = (__le16 *) skb_put(skb, 2);
- *control = __cpu_to_le16((reqseq << 8) | 1);
-
- fcs = (__le16 *) skb_put(skb, 2);
- *fcs = __cpu_to_le16(crc16(0, skb->data, 6));
-
- if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
- goto fail;
-
- l2cap_start_mon_timer(sk, l2cap_pi(sk)->imon_to * HZ / 1000);
-
- return err;
-
-fail:
- kfree_skb(skb);
- return err;
-}
-
-static int l2cap_invalid_frame_detection(struct sock *sk, struct sk_buff *skb)
-{
- int err = 0;
- u16 len, cid, control, sdu_len, fcs;
-
- /* value of length field in frame */
- len = get_unaligned((u16 *) skb->data);
- cid = get_unaligned((u16 *) (skb->data + 2));
-
- if (len != (skb->len - L2CAP_HDR_SIZE))
- err = -1;
-
- /* contains an unknown (reserved) cid */
- if (cid < 0x003F)
- err = -2;
-
- /* contains an fcs error */
- fcs = get_unaligned((u16 *) (skb->tail - 2));
- if (unlikely(fcs != crc16(0, skb->data, skb->len - 2)))
- err = -3;
-
- /* contains a length > max possible mps */
- if (len > L2CAP_MAX_DATA_LEN)
- err = -4;
-
- control = get_unaligned((u16 *) (skb->data + L2CAP_HDR_SIZE));
- sdu_len = get_unaligned((u16 *) (skb->data + L2CAP_HDR_SIZE + L2CAP_CONTROL_SIZE));
-
- if (control & 0x01) {
- /* s-frame with length != 4 */
- if (len != 4) err = -8;
- } else {
- /* i-frame that has fewer than 8 octets */
- if (skb->len < 8)
- err = -5;
- if ((L2CAP_SAR_MASK & control) == L2CAP_SAR_START) {
- /* contains a length > max possible mps (with SAR) */
- if (len > L2CAP_MAX_DATA_LEN - 2)
- err = -4;
- /* i-frame with SAR=01 with < 10 octets */
- if (skb->len < 10)
- err = -6;
- /* requested sdu len is bigger than configured mps */
- if (sdu_len > l2cap_pi(sk)->imps)
- err = -7;
- }
- }
-
- BT_DBG("err %d", err);
-
- return err;
-}
-
-static int l2cap_process_txseq(struct sock *sk, struct sk_buff *skb, u16 control)
-{
- int err = 0;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- u8 txseq = L2CAP_GET_TXSEQ(control);
-
- if (txseq == pi->exp_txseq) {
- pi->exp_txseq = (pi->exp_txseq + 1) % 64;
- } else if (((txseq - pi->buffer_seq + 64) % 64) < pi->itxw) {
- /* out-of-sequence i-frame */
- pi->exp_txseq = (txseq + 1) % 64;
- } else if ((txseq >= pi->buffer_seq) && (txseq <= pi->exp_txseq - 1)) {
- /* duplicated i-frame */
- err = -1;
- } else {
- /* invalid txseq */
- err = -2;
- }
-
- BT_DBG("err %d", err);
-
- return err;
-}
-
-static int l2cap_process_reqseq(struct sock *sk, struct sk_buff *skb, u16 control)
-{
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- u8 reqseq = L2CAP_GET_REQSEQ(control);
-
- BT_DBG("sk %p reqseq %d", sk, reqseq);
-
- /* accept only i-frame or s-frame with S bits set to 00 (RR) */
- if (!(((control & 0x01) == 0x00) || ((control & 0x0F) == 0x01)))
- return -1;
-
- /* reqseq sequence error */
- if (!((reqseq - pi->exp_ackseq + 64) % 64 <=
- (pi->next_txseq - pi->exp_ackseq + 64) % 64)) {
- /* close channel -> send disconnect request */
- struct l2cap_disconn_req req;
- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
- sk->sk_state = BT_DISCONN;
- sk->sk_err = ECONNRESET;
- l2cap_sock_set_timer(sk, HZ * 5);
- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
- l2cap_send_cmd(conn, l2cap_get_ident(conn),
- L2CAP_DISCONN_REQ, sizeof(req), &req);
- return -2;
- }
-
- pi->exp_ackseq = reqseq;
-
- /*
- if (reqseq != pi->next_txseq)
- l2cap_start_ret_timer(sk, pi->iret_to * HZ / 1000);
- else
- l2cap_start_mon_timer(sk, pi->imon_to * HZ / 1000);
- */
- /* FIXME: transmit any I-Frames awaiting transmission */
-
- return 0;
-}
-
-static int l2cap_reassembly(struct sock *sk, struct sk_buff *skb, u16 control)
-{
- u16 sdu_len = 0;
-
- BT_DBG("sk %p control %04X", sk, control);
-
- /* remove header, control and fcs from i-frame */
- skb_pull(skb, L2CAP_HDR_SIZE + L2CAP_CONTROL_SIZE);
- skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
-
- switch (L2CAP_GET_SAR(control)) {
- case L2CAP_SAR_UNSEGMENTED:
- l2cap_pi(sk)->buffer_seq = l2cap_pi(sk)->exp_txseq;
- if (sock_queue_rcv_skb(sk, skb))
- return -1;
- if (l2cap_send_sframe(sk, l2cap_pi(sk)->buffer_seq))
- return -6;
- break;
-
- case L2CAP_SAR_START:
- sdu_len = get_unaligned((u16 *) skb->data);
- /* remove sdu len field */
- skb_pull(skb, 2);
-
- /* in case a SAR_END frame got lost make sure to free the
- * allocated buffer space of the last sdu */
- kfree_skb(l2cap_pi(sk)->sdu);
- l2cap_pi(sk)->sdu = NULL;
- l2cap_pi(sk)->sdu_len = 0;
-
- /* allocate skb for complete new sdu */
- if (!(l2cap_pi(sk)->sdu = bt_skb_alloc(sdu_len, GFP_ATOMIC)))
- return -2;
-
- memcpy(skb_put(l2cap_pi(sk)->sdu, skb->len), skb->data, skb->len);
- l2cap_pi(sk)->sdu_len = sdu_len - skb->len;
- l2cap_pi(sk)->buffer_seq = l2cap_pi(sk)->exp_txseq;
- if (l2cap_send_sframe(sk, l2cap_pi(sk)->buffer_seq))
- return -6;
- break;
-
- default:
- /* continuation or end of sdu frame */
- if (!l2cap_pi(sk)->sdu_len) {
- BT_ERR("Unexpected continuation frame (len %d)", skb->len);
- return -3;
- }
-
- if (skb->len > l2cap_pi(sk)->sdu_len) {
- BT_ERR("Fragment is too long (len %d, expected %d)",
- skb->len, l2cap_pi(sk)->sdu_len);
- kfree_skb(l2cap_pi(sk)->sdu);
- l2cap_pi(sk)->sdu = NULL;
- l2cap_pi(sk)->sdu_len = 0;
- return -4;
- }
-
- memcpy(skb_put(l2cap_pi(sk)->sdu, skb->len), skb->data, skb->len);
- l2cap_pi(sk)->sdu_len -= skb->len;
- l2cap_pi(sk)->buffer_seq = l2cap_pi(sk)->exp_txseq;
- if (l2cap_send_sframe(sk, l2cap_pi(sk)->buffer_seq))
- return -6;
-
- /* last frame for sdu */
- if ((L2CAP_GET_SAR(control) == L2CAP_SAR_END) &&
- (l2cap_pi(sk)->sdu_len == 0)) {
- if (sock_queue_rcv_skb(sk, l2cap_pi(sk)->sdu))
- return -1;
- kfree_skb(l2cap_pi(sk)->sdu);
- l2cap_pi(sk)->sdu = NULL;
- l2cap_pi(sk)->sdu_len = 0;
- }
- }
-
- return 0;
-}
-
static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
{
struct sock *sk;
@@ -2659,44 +1808,19 @@
goto drop;
}
- BT_DBG("sk %p len %d mode 0x%02X", sk, skb->len, l2cap_pi(sk)->mode);
+ BT_DBG("sk %p, len %d", sk, skb->len);
if (sk->sk_state != BT_CONNECTED)
goto drop;
- /* s-frame or i-frame */
- if (l2cap_pi(sk)->mode == L2CAP_MODE_FLOW) {
- u16 control;
-
- if (l2cap_invalid_frame_detection(sk, skb))
- goto drop;
-
- control = get_unaligned((u16 *) (skb->data + L2CAP_HDR_SIZE));
-
- if (control & 0x01) {
- /* process s-frame */
- if (l2cap_process_reqseq(sk, skb, control))
- goto drop;
- } else {
- /* process i-frame */
- if (l2cap_process_txseq(sk, skb, control))
- goto drop;
- if (l2cap_process_reqseq(sk, skb, control))
- goto drop;
- if (l2cap_reassembly(sk, skb, control))
- goto drop;
- }
-
- goto done;
- }
-
- skb_pull(skb, L2CAP_HDR_SIZE);
-
- /* b-frame with too large information payload */
if (l2cap_pi(sk)->imtu < skb->len)
goto drop;
- /* ordinary b-frame */
+ /* If socket recv buffers overflows we drop data here
+ * which is *bad* because L2CAP has to be reliable.
+ * But we don't have any other choice. L2CAP doesn't
+ * provide flow control mechanism. */
+
if (!sock_queue_rcv_skb(sk, skb))
goto done;
@@ -2742,6 +1866,7 @@
struct l2cap_hdr *lh = (void *) skb->data;
u16 cid, psm, len;
+ skb_pull(skb, L2CAP_HDR_SIZE);
cid = __le16_to_cpu(lh->cid);
len = __le16_to_cpu(lh->len);
@@ -2749,12 +1874,10 @@
switch (cid) {
case 0x0001:
- skb_pull(skb, L2CAP_HDR_SIZE);
l2cap_sig_channel(conn, skb);
break;
case 0x0002:
- skb_pull(skb, L2CAP_HDR_SIZE);
psm = get_unaligned((u16 *) skb->data);
skb_pull(skb, 2);
l2cap_conless_channel(conn, psm, skb);
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/rfcomm/tty.c linux-2.6.18-my-bt/net/bluetooth/rfcomm/tty.c
--- linux-2.6.18-mh1/net/bluetooth/rfcomm/tty.c 2006-09-23 19:56:08.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/rfcomm/tty.c 2006-09-23 22:46:43.000000000 -0700
@@ -38,7 +38,6 @@
#include <linux/skbuff.h>
#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/rfcomm.h>
#ifndef CONFIG_BT_RFCOMM_DEBUG
@@ -162,24 +161,6 @@
return dev;
}
-static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
-{
- struct hci_dev *hdev;
- struct hci_conn *conn;
-
- hdev = hci_get_route(&dev->dst, &dev->src);
- if (!hdev)
- return NULL;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
- if (!conn)
- return NULL;
-
- hci_dev_put(hdev);
-
- return &conn->dev;
-}
-
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
{
struct rfcomm_dev *dev;
@@ -263,7 +244,7 @@
return err;
}
- tty_register_device(rfcomm_tty_driver, dev->id, rfcomm_get_device(dev));
+ tty_register_device(rfcomm_tty_driver, dev->id, NULL);
return dev->id;
}
[-- Attachment #3: Type: text/plain, Size: 348 bytes --]
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
[-- Attachment #4: Type: text/plain, Size: 164 bytes --]
_______________________________________________
Bluez-users mailing list
Bluez-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-users
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Bluez-users] Microsoft IntelliMouse with kernel 2.6.1 and patch-2.6.18-mh1 is broken (fix provided)
2006-09-27 8:26 ` [Bluez-users] Microsoft IntelliMouse with kernel 2.6.1 " Andrey Jivsov
@ 2006-09-29 11:52 ` Marcel Holtmann
2006-09-29 17:58 ` Andrey Jivsov
0 siblings, 1 reply; 5+ messages in thread
From: Marcel Holtmann @ 2006-09-29 11:52 UTC (permalink / raw)
To: BlueZ users
Hi Andrey,
> here is the patch against linux-2.6.18-mh1 to fix
> IntelliMouse. That's the best range of changes I have time to provide:
> somewhere in these changes IntelliMouse was broken. I believe this
> happened between patch-2.6.15-mh2 and linux-2.6.18-mh1. While there are
> a lot of changes in these 17 files, but most of them are variable
> renames. I hope this helps you to narrow down the issue.
I only care about changes in net/bluetooth/hidp/. All others are not
relevant. Can't you show me your changes from that directory.
> [ Does sending compressed patched works? Trying uncompressed first. ]
Keep them uncompressed, then I can read them in my email client.
Regards
Marcel
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Bluez-users mailing list
Bluez-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-users
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Bluez-users] Microsoft IntelliMouse with kernel 2.6.1 and patch-2.6.18-mh1 is broken (fix provided)
2006-09-29 11:52 ` Marcel Holtmann
@ 2006-09-29 17:58 ` Andrey Jivsov
0 siblings, 0 replies; 5+ messages in thread
From: Andrey Jivsov @ 2006-09-29 17:58 UTC (permalink / raw)
To: BlueZ users
[-- Attachment #1: Type: text/plain, Size: 738 bytes --]
Marcel Holtmann wrote:
> Hi Andrey,
>
>> here is the patch against linux-2.6.18-mh1 to fix
>> IntelliMouse. That's the best range of changes I have time to provide:
>> somewhere in these changes IntelliMouse was broken. I believe this
>> happened between patch-2.6.15-mh2 and linux-2.6.18-mh1. While there are
>> a lot of changes in these 17 files, but most of them are variable
>> renames. I hope this helps you to narrow down the issue.
>
> I only care about changes in net/bluetooth/hidp/. All others are not
> relevant. Can't you show me your changes from that directory.
>
Marcel, there is only one file changed in this directory:
net/bluetooth/hidp/core.c. The changes are rollback of hidp_get_device call.
Thank you.
[-- Attachment #2: patch-2.6.18-hidp-only-mh1aj --]
[-- Type: text/plain, Size: 1476 bytes --]
diff -ur --exclude-from=kernel-diff-exclude.txt linux-2.6.18-mh1/net/bluetooth/hidp/core.c linux-2.6.18-my-bt/net/bluetooth/hidp/core.c
--- linux-2.6.18-mh1/net/bluetooth/hidp/core.c 2006-09-23 19:56:07.000000000 -0700
+++ linux-2.6.18-my-bt/net/bluetooth/hidp/core.c 2006-09-23 23:00:22.000000000 -0700
@@ -41,7 +41,6 @@
#include "hid.h"
#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include "hidp.h"
@@ -573,26 +572,6 @@
return 0;
}
-static struct device *hidp_get_device(struct hidp_session *session)
-{
- bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
- bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
- struct hci_dev *hdev;
- struct hci_conn *conn;
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return NULL;
-
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (!conn)
- return NULL;
-
- hci_dev_put(hdev);
-
- return &conn->dev;
-}
-
static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
{
struct input_dev *input = session->input;
@@ -631,8 +610,6 @@
input->relbit[0] |= BIT(REL_WHEEL);
}
- input->cdev.dev = hidp_get_device(session);
-
input->event = hidp_input_event;
input_register_device(input);
@@ -660,8 +637,6 @@
strncpy(hid->phys, batostr(&src), 64);
strncpy(hid->uniq, batostr(&dst), 64);
- hid->dev = hidp_get_device(session);
-
hid->send = hid_send_report;
hid_register_device(hid);
[-- Attachment #3: Type: text/plain, Size: 348 bytes --]
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
[-- Attachment #4: Type: text/plain, Size: 164 bytes --]
_______________________________________________
Bluez-users mailing list
Bluez-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-users
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2006-09-29 17:58 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-27 6:29 [Bluez-users] Microsoft IntelliMouse with kernel 2.6.18 and patch-2.6.18-mh1 is broken (fix provided) Andrey Jivsov
2006-09-27 7:52 ` Marcel Holtmann
2006-09-27 8:26 ` [Bluez-users] Microsoft IntelliMouse with kernel 2.6.1 " Andrey Jivsov
2006-09-29 11:52 ` Marcel Holtmann
2006-09-29 17:58 ` Andrey Jivsov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox