Bluetooth: A2MP: Process A2MP Get Info Request
authorAndrei Emeltchenko <andrei.emeltchenko@intel.com>
Tue, 29 May 2012 10:59:11 +0000 (13:59 +0300)
committerJohan Hedberg <johan.hedberg@intel.com>
Tue, 5 Jun 2012 03:34:13 +0000 (06:34 +0300)
Process A2MP Get Info Request.
Example of trace log for invalid controller id is shown below:

...
> ACL data: handle 11 flags 0x02 dlen 13
    A2MP: Get Info req: id 238
< ACL data: handle 11 flags 0x00 dlen 30
    A2MP: Get Info rsp: id 238 status (1) Invalid Controller ID
...

Note that If the Status field is set to Invalid Controller ID all subsequent
fields in the AMP Get Info Response shall be ignored by the receiver.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
net/bluetooth/a2mp.c

index 6cdaa85ab5e93fc9120e8797d94accd68441f1f8..350088e2015a67c66efd283ec9018a0151aa7e4a 100644 (file)
@@ -177,6 +177,40 @@ static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
        return 0;
 }
 
+static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                           struct a2mp_cmd *hdr)
+{
+       struct a2mp_info_req *req  = (void *) skb->data;
+       struct a2mp_info_rsp rsp;
+       struct hci_dev *hdev;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*req))
+               return -EINVAL;
+
+       BT_DBG("id %d", req->id);
+
+       rsp.id = req->id;
+       rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+       hdev = hci_dev_get(req->id);
+       if (hdev && hdev->amp_type != HCI_BREDR) {
+               rsp.status = 0;
+               rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+               rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+               rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+               rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+               rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+       }
+
+       if (hdev)
+               hci_dev_put(hdev);
+
+       a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+       skb_pull(skb, sizeof(*req));
+       return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
@@ -215,6 +249,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
                        break;
 
                case A2MP_GETINFO_REQ:
+                       err = a2mp_getinfo_req(mgr, skb, hdr);
+                       break;
+
                case A2MP_GETAMPASSOC_REQ:
                case A2MP_CREATEPHYSLINK_REQ:
                case A2MP_DISCONNPHYSLINK_REQ: