a2mp.c revision 9740e49d17e55f3832661fd99a8e0a17e921a82e
1466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko/*
2466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
3466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko   Copyright (c) 2011,2012 Intel Corp.
4466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
5466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko   This program is free software; you can redistribute it and/or modify
6466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko   it under the terms of the GNU General Public License version 2 and
7466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko   only version 2 as published by the Free Software Foundation.
8466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
9466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko   This program is distributed in the hope that it will be useful,
10466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko   but WITHOUT ANY WARRANTY; without even the implied warranty of
11466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko   GNU General Public License for more details.
13466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko*/
14466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
15466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko#include <net/bluetooth/bluetooth.h>
16466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko#include <net/bluetooth/hci_core.h>
17466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko#include <net/bluetooth/l2cap.h>
189740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko#include <net/bluetooth/a2mp.h>
19466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
20466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenkostatic struct l2cap_ops a2mp_chan_ops = {
21466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	.name = "L2CAP A2MP channel",
22466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko};
23466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
24466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenkostatic struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
25466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko{
26466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	struct l2cap_chan *chan;
27466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	int err;
28466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
29466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan = l2cap_chan_create();
30466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	if (!chan)
31466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko		return NULL;
32466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
33466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	BT_DBG("chan %p", chan);
34466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
35466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	hci_conn_hold(conn->hcon);
36466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
37466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
38466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
39466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
40466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
41466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->ops = &a2mp_chan_ops;
42466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
43466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	l2cap_chan_set_defaults(chan);
44466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->remote_max_tx = chan->max_tx;
45466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->remote_tx_win = chan->tx_win;
46466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
47466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
48466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
49466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
50466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	skb_queue_head_init(&chan->tx_q);
51466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
52466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->mode = L2CAP_MODE_ERTM;
53466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
54466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	err = l2cap_ertm_init(chan);
55466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	if (err < 0) {
56466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko		l2cap_chan_del(chan, 0);
57466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko		return NULL;
58466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	}
59466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
60466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->conf_state = 0;
61466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
62466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	l2cap_chan_add(conn, chan);
63466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
64466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->remote_mps = chan->omtu;
65466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->mps = chan->omtu;
66466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
67466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	chan->state = BT_CONNECTED;
68466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko
69466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko	return chan;
70466f8004f364e9cb46d9124109972489eccfb404Andrei Emeltchenko}
719740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
729740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko/* AMP Manager functions */
739740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenkovoid amp_mgr_get(struct amp_mgr *mgr)
749740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko{
759740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	BT_DBG("mgr %p", mgr);
769740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
779740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	kref_get(&mgr->kref);
789740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko}
799740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
809740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenkostatic void amp_mgr_destroy(struct kref *kref)
819740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko{
829740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
839740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
849740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	BT_DBG("mgr %p", mgr);
859740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
869740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	kfree(mgr);
879740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko}
889740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
899740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenkoint amp_mgr_put(struct amp_mgr *mgr)
909740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko{
919740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	BT_DBG("mgr %p", mgr);
929740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
939740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	return kref_put(&mgr->kref, &amp_mgr_destroy);
949740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko}
959740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
969740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenkostatic struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
979740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko{
989740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	struct amp_mgr *mgr;
999740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	struct l2cap_chan *chan;
1009740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
1019740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1029740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	if (!mgr)
1039740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko		return NULL;
1049740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
1059740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	BT_DBG("conn %p mgr %p", conn, mgr);
1069740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
1079740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	mgr->l2cap_conn = conn;
1089740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
1099740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	chan = a2mp_chan_open(conn);
1109740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	if (!chan) {
1119740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko		kfree(mgr);
1129740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko		return NULL;
1139740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	}
1149740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
1159740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	mgr->a2mp_chan = chan;
1169740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	chan->data = mgr;
1179740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
1189740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	conn->hcon->amp_mgr = mgr;
1199740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
1209740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	kref_init(&mgr->kref);
1219740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko
1229740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko	return mgr;
1239740e49d17e55f3832661fd99a8e0a17e921a82eAndrei Emeltchenko}
124