aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorAndrei Emeltchenko <andrei.emeltchenko@intel.com>2012-05-29 06:59:07 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2012-06-04 23:34:12 -0400
commit6b44d9b8d96b37f72ccd7335b32f386a67b7f1f4 (patch)
tree5bbcf9598ae79f777e6af5fd1b2ab43fc8f34679 /net/bluetooth
parente7af522e04bcf68caae6802722efc5c6e8fa63a7 (diff)
Bluetooth: A2MP: Process A2MP messages
Implement basic processing for AMP Manager Protocol (A2MP). Example below shows processing unrecognized command. ... > ACL data: handle 11 flags 0x02 dlen 12 A2MP: code 0x00 ident 3 len 0 < ACL data: handle 11 flags 0x00 dlen 14 A2MP: Command Reject: reason (0) - Command not recognized ... Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/a2mp.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index f7c710cacf44..0726c9fe005c 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,70 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
63 kfree(cmd); 63 kfree(cmd);
64} 64}
65 65
66/* Handle A2MP signalling */
67static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
68{
69 struct a2mp_cmd *hdr = (void *) skb->data;
70 struct amp_mgr *mgr = chan->data;
71 int err = 0;
72
73 amp_mgr_get(mgr);
74
75 while (skb->len >= sizeof(*hdr)) {
76 struct a2mp_cmd *hdr = (void *) skb->data;
77 u16 len = le16_to_cpu(hdr->len);
78
79 BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
80
81 skb_pull(skb, sizeof(*hdr));
82
83 if (len > skb->len || !hdr->ident) {
84 err = -EINVAL;
85 break;
86 }
87
88 mgr->ident = hdr->ident;
89
90 switch (hdr->code) {
91 case A2MP_COMMAND_REJ:
92 case A2MP_DISCOVER_REQ:
93 case A2MP_CHANGE_NOTIFY:
94 case A2MP_GETINFO_REQ:
95 case A2MP_GETAMPASSOC_REQ:
96 case A2MP_CREATEPHYSLINK_REQ:
97 case A2MP_DISCONNPHYSLINK_REQ:
98 case A2MP_CHANGE_RSP:
99 case A2MP_DISCOVER_RSP:
100 case A2MP_GETINFO_RSP:
101 case A2MP_GETAMPASSOC_RSP:
102 case A2MP_CREATEPHYSLINK_RSP:
103 case A2MP_DISCONNPHYSLINK_RSP:
104 default:
105 BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
106 err = -EINVAL;
107 break;
108 }
109 }
110
111 if (err) {
112 struct a2mp_cmd_rej rej;
113 rej.reason = __constant_cpu_to_le16(0);
114
115 BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
116
117 a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
118 &rej);
119 }
120
121 /* Always free skb and return success error code to prevent
122 from sending L2CAP Disconnect over A2MP channel */
123 kfree_skb(skb);
124
125 amp_mgr_put(mgr);
126
127 return 0;
128}
129
66static void a2mp_chan_close_cb(struct l2cap_chan *chan) 130static void a2mp_chan_close_cb(struct l2cap_chan *chan)
67{ 131{
68 l2cap_chan_destroy(chan); 132 l2cap_chan_destroy(chan);
@@ -112,6 +176,7 @@ static void a2mp_chan_no_ready(struct l2cap_chan *chan)
112 176
113static struct l2cap_ops a2mp_chan_ops = { 177static struct l2cap_ops a2mp_chan_ops = {
114 .name = "L2CAP A2MP channel", 178 .name = "L2CAP A2MP channel",
179 .recv = a2mp_chan_recv_cb,
115 .close = a2mp_chan_close_cb, 180 .close = a2mp_chan_close_cb,
116 .state_change = a2mp_chan_state_change_cb, 181 .state_change = a2mp_chan_state_change_cb,
117 .alloc_skb = a2mp_chan_alloc_skb_cb, 182 .alloc_skb = a2mp_chan_alloc_skb_cb,