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, &_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