]> Pileus Git - ~andy/linux/blob - net/bluetooth/a2mp.c
Bluetooth: A2MP: Build and Send msg helpers
[~andy/linux] / net / bluetooth / a2mp.c
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>
18 #include <net/bluetooth/a2mp.h>
19
20 /* A2MP build & send command helper functions */
21 static 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
40 static 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
66 static struct l2cap_ops a2mp_chan_ops = {
67         .name = "L2CAP A2MP channel",
68 };
69
70 static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
71 {
72         struct l2cap_chan *chan;
73         int err;
74
75         chan = l2cap_chan_create();
76         if (!chan)
77                 return NULL;
78
79         BT_DBG("chan %p", chan);
80
81         hci_conn_hold(conn->hcon);
82
83         chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
84         chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
85         chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
86
87         chan->ops = &a2mp_chan_ops;
88
89         l2cap_chan_set_defaults(chan);
90         chan->remote_max_tx = chan->max_tx;
91         chan->remote_tx_win = chan->tx_win;
92
93         chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
94         chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
95
96         skb_queue_head_init(&chan->tx_q);
97
98         chan->mode = L2CAP_MODE_ERTM;
99
100         err = l2cap_ertm_init(chan);
101         if (err < 0) {
102                 l2cap_chan_del(chan, 0);
103                 return NULL;
104         }
105
106         chan->conf_state = 0;
107
108         l2cap_chan_add(conn, chan);
109
110         chan->remote_mps = chan->omtu;
111         chan->mps = chan->omtu;
112
113         chan->state = BT_CONNECTED;
114
115         return chan;
116 }
117
118 /* AMP Manager functions */
119 void amp_mgr_get(struct amp_mgr *mgr)
120 {
121         BT_DBG("mgr %p", mgr);
122
123         kref_get(&mgr->kref);
124 }
125
126 static void amp_mgr_destroy(struct kref *kref)
127 {
128         struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
129
130         BT_DBG("mgr %p", mgr);
131
132         kfree(mgr);
133 }
134
135 int amp_mgr_put(struct amp_mgr *mgr)
136 {
137         BT_DBG("mgr %p", mgr);
138
139         return kref_put(&mgr->kref, &amp_mgr_destroy);
140 }
141
142 static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
143 {
144         struct amp_mgr *mgr;
145         struct l2cap_chan *chan;
146
147         mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
148         if (!mgr)
149                 return NULL;
150
151         BT_DBG("conn %p mgr %p", conn, mgr);
152
153         mgr->l2cap_conn = conn;
154
155         chan = a2mp_chan_open(conn);
156         if (!chan) {
157                 kfree(mgr);
158                 return NULL;
159         }
160
161         mgr->a2mp_chan = chan;
162         chan->data = mgr;
163
164         conn->hcon->amp_mgr = mgr;
165
166         kref_init(&mgr->kref);
167
168         return mgr;
169 }