Bluetooth: A2MP: Define A2MP status codes
[deliverable/linux.git] / net / bluetooth / a2mp.c
CommitLineData
466f8004
AE
1/*
2 Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
3 Copyright (c) 2011,2012 Intel Corp.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 and
7 only version 2 as published by the Free Software Foundation.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13*/
14
15#include <net/bluetooth/bluetooth.h>
16#include <net/bluetooth/hci_core.h>
17#include <net/bluetooth/l2cap.h>
9740e49d 18#include <net/bluetooth/a2mp.h>
466f8004 19
f6d3c6e7
AE
20/* A2MP build & send command helper functions */
21static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
22{
23 struct a2mp_cmd *cmd;
24 int plen;
25
26 plen = sizeof(*cmd) + len;
27 cmd = kzalloc(plen, GFP_KERNEL);
28 if (!cmd)
29 return NULL;
30
31 cmd->code = code;
32 cmd->ident = ident;
33 cmd->len = cpu_to_le16(len);
34
35 memcpy(cmd->data, data, len);
36
37 return cmd;
38}
39
40static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
41 void *data)
42{
43 struct l2cap_chan *chan = mgr->a2mp_chan;
44 struct a2mp_cmd *cmd;
45 u16 total_len = len + sizeof(*cmd);
46 struct kvec iv;
47 struct msghdr msg;
48
49 cmd = __a2mp_build(code, ident, len, data);
50 if (!cmd)
51 return;
52
53 iv.iov_base = cmd;
54 iv.iov_len = total_len;
55
56 memset(&msg, 0, sizeof(msg));
57
58 msg.msg_iov = (struct iovec *) &iv;
59 msg.msg_iovlen = 1;
60
61 l2cap_chan_send(chan, &msg, total_len, 0);
62
63 kfree(cmd);
64}
65
46d5c908
AE
66static void a2mp_chan_close_cb(struct l2cap_chan *chan)
67{
68 l2cap_chan_destroy(chan);
69}
70
71static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)
72{
73 struct amp_mgr *mgr = chan->data;
74
75 if (!mgr)
76 return;
77
78 BT_DBG("chan %p state %s", chan, state_to_string(state));
79
80 chan->state = state;
81
82 switch (state) {
83 case BT_CLOSED:
84 if (mgr)
85 amp_mgr_put(mgr);
86 break;
87 }
88}
89
90static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
91 unsigned long len, int nb)
92{
93 return bt_skb_alloc(len, GFP_KERNEL);
94}
95
96static struct l2cap_chan *a2mp_chan_no_new_conn_cb(struct l2cap_chan *chan)
97{
98 BT_ERR("new_connection for chan %p not implemented", chan);
99
100 return NULL;
101}
102
103static void a2mp_chan_no_teardown_cb(struct l2cap_chan *chan, int err)
104{
105 BT_ERR("teardown for chan %p not implemented", chan);
106}
107
108static void a2mp_chan_no_ready(struct l2cap_chan *chan)
109{
110 BT_ERR("ready for chan %p not implemented", chan);
111}
112
466f8004
AE
113static struct l2cap_ops a2mp_chan_ops = {
114 .name = "L2CAP A2MP channel",
46d5c908
AE
115 .close = a2mp_chan_close_cb,
116 .state_change = a2mp_chan_state_change_cb,
117 .alloc_skb = a2mp_chan_alloc_skb_cb,
118
119 /* Not implemented for A2MP */
120 .new_connection = a2mp_chan_no_new_conn_cb,
121 .teardown = a2mp_chan_no_teardown_cb,
122 .ready = a2mp_chan_no_ready,
466f8004
AE
123};
124
125static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
126{
127 struct l2cap_chan *chan;
128 int err;
129
130 chan = l2cap_chan_create();
131 if (!chan)
132 return NULL;
133
134 BT_DBG("chan %p", chan);
135
136 hci_conn_hold(conn->hcon);
137
138 chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
139 chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
140 chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
141
142 chan->ops = &a2mp_chan_ops;
143
144 l2cap_chan_set_defaults(chan);
145 chan->remote_max_tx = chan->max_tx;
146 chan->remote_tx_win = chan->tx_win;
147
148 chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
149 chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
150
151 skb_queue_head_init(&chan->tx_q);
152
153 chan->mode = L2CAP_MODE_ERTM;
154
155 err = l2cap_ertm_init(chan);
156 if (err < 0) {
157 l2cap_chan_del(chan, 0);
158 return NULL;
159 }
160
161 chan->conf_state = 0;
162
163 l2cap_chan_add(conn, chan);
164
165 chan->remote_mps = chan->omtu;
166 chan->mps = chan->omtu;
167
168 chan->state = BT_CONNECTED;
169
170 return chan;
171}
9740e49d
AE
172
173/* AMP Manager functions */
174void amp_mgr_get(struct amp_mgr *mgr)
175{
176 BT_DBG("mgr %p", mgr);
177
178 kref_get(&mgr->kref);
179}
180
181static void amp_mgr_destroy(struct kref *kref)
182{
183 struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
184
185 BT_DBG("mgr %p", mgr);
186
187 kfree(mgr);
188}
189
190int amp_mgr_put(struct amp_mgr *mgr)
191{
192 BT_DBG("mgr %p", mgr);
193
194 return kref_put(&mgr->kref, &amp_mgr_destroy);
195}
196
197static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
198{
199 struct amp_mgr *mgr;
200 struct l2cap_chan *chan;
201
202 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
203 if (!mgr)
204 return NULL;
205
206 BT_DBG("conn %p mgr %p", conn, mgr);
207
208 mgr->l2cap_conn = conn;
209
210 chan = a2mp_chan_open(conn);
211 if (!chan) {
212 kfree(mgr);
213 return NULL;
214 }
215
216 mgr->a2mp_chan = chan;
217 chan->data = mgr;
218
219 conn->hcon->amp_mgr = mgr;
220
221 kref_init(&mgr->kref);
222
223 return mgr;
224}
This page took 0.034597 seconds and 5 git commands to generate.