diff options
Diffstat (limited to 'net/bluetooth/a2mp.c')
| -rw-r--r-- | net/bluetooth/a2mp.c | 92 | 
1 files changed, 56 insertions, 36 deletions
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 17f33a62f6d..9514cc9e850 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -15,8 +15,9 @@  #include <net/bluetooth/bluetooth.h>  #include <net/bluetooth/hci_core.h>  #include <net/bluetooth/l2cap.h> -#include <net/bluetooth/a2mp.h> -#include <net/bluetooth/amp.h> + +#include "a2mp.h" +#include "amp.h"  /* Global AMP Manager list */  LIST_HEAD(amp_mgr_list); @@ -75,33 +76,26 @@ u8 __next_ident(struct amp_mgr *mgr)  	return mgr->ident;  } -static inline void __a2mp_cl_bredr(struct a2mp_cl *cl) -{ -	cl->id = 0; -	cl->type = 0; -	cl->status = 1; -} -  /* hci_dev_list shall be locked */ -static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl) +static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl)  { -	int i = 0;  	struct hci_dev *hdev; +	int i = 1; -	__a2mp_cl_bredr(cl); +	cl[0].id = AMP_ID_BREDR; +	cl[0].type = AMP_TYPE_BREDR; +	cl[0].status = AMP_STATUS_BLUETOOTH_ONLY;  	list_for_each_entry(hdev, &hci_dev_list, list) { -		/* Iterate through AMP controllers */ -		if (hdev->id == HCI_BREDR_ID) -			continue; - -		/* Starting from second entry */ -		if (++i >= num_ctrl) -			return; - -		cl[i].id = hdev->id; -		cl[i].type = hdev->amp_type; -		cl[i].status = hdev->amp_status; +		if (hdev->dev_type == HCI_AMP) { +			cl[i].id = hdev->id; +			cl[i].type = hdev->amp_type; +			if (test_bit(HCI_UP, &hdev->flags)) +				cl[i].status = hdev->amp_status; +			else +				cl[i].status = AMP_STATUS_POWERED_DOWN; +			i++; +		}  	}  } @@ -129,6 +123,7 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,  	struct a2mp_discov_rsp *rsp;  	u16 ext_feat;  	u8 num_ctrl; +	struct hci_dev *hdev;  	if (len < sizeof(*req))  		return -EINVAL; @@ -152,7 +147,14 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,  	read_lock(&hci_dev_list_lock); -	num_ctrl = __hci_num_ctrl(); +	/* at minimum the BR/EDR needs to be listed */ +	num_ctrl = 1; + +	list_for_each_entry(hdev, &hci_dev_list, list) { +		if (hdev->dev_type == HCI_AMP) +			num_ctrl++; +	} +  	len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);  	rsp = kmalloc(len, GFP_ATOMIC);  	if (!rsp) { @@ -160,10 +162,10 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,  		return -ENOMEM;  	} -	rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); +	rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);  	rsp->ext_feat = 0; -	__a2mp_add_cl(mgr, rsp->cl, num_ctrl); +	__a2mp_add_cl(mgr, rsp->cl);  	read_unlock(&hci_dev_list_lock); @@ -208,7 +210,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,  		BT_DBG("Remote AMP id %d type %d status %d", cl->id, cl->type,  		       cl->status); -		if (cl->id != HCI_BREDR_ID && cl->type == HCI_AMP) { +		if (cl->id != AMP_ID_BREDR && cl->type != AMP_TYPE_BREDR) {  			struct a2mp_info_req req;  			found = true; @@ -233,7 +235,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,  			BT_DBG("chan %p state %s", chan,  			       state_to_string(chan->state)); -			if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) +			if (chan->scid == L2CAP_CID_A2MP)  				continue;  			l2cap_chan_lock(chan); @@ -344,7 +346,7 @@ static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,  	tmp = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);  	hdev = hci_dev_get(req->id); -	if (!hdev || hdev->amp_type == HCI_BREDR || tmp) { +	if (!hdev || hdev->amp_type == AMP_TYPE_BREDR || tmp) {  		struct a2mp_amp_assoc_rsp rsp;  		rsp.id = req->id; @@ -451,7 +453,7 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,  	rsp.remote_id = req->local_id;  	hdev = hci_dev_get(req->remote_id); -	if (!hdev || hdev->amp_type != HCI_AMP) { +	if (!hdev || hdev->amp_type == AMP_TYPE_BREDR) {  		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;  		goto send_rsp;  	} @@ -535,7 +537,8 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,  		goto send_rsp;  	} -	hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, mgr->l2cap_conn->dst); +	hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, +				       &mgr->l2cap_conn->hcon->dst);  	if (!hcon) {  		BT_ERR("No phys link exist");  		rsp.status = A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS; @@ -646,7 +649,7 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)  	if (err) {  		struct a2mp_cmd_rej rej; -		rej.reason = __constant_cpu_to_le16(0); +		rej.reason = cpu_to_le16(0);  		hdr = (void *) skb->data;  		BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err); @@ -669,7 +672,8 @@ static void a2mp_chan_close_cb(struct l2cap_chan *chan)  	l2cap_chan_put(chan);  } -static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state) +static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state, +				      int err)  {  	struct amp_mgr *mgr = chan->data; @@ -691,7 +695,13 @@ static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)  static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,  					      unsigned long len, int nb)  { -	return bt_skb_alloc(len, GFP_KERNEL); +	struct sk_buff *skb; + +	skb = bt_skb_alloc(len, GFP_KERNEL); +	if (!skb) +		return ERR_PTR(-ENOMEM); + +	return skb;  }  static struct l2cap_ops a2mp_chan_ops = { @@ -706,6 +716,9 @@ static struct l2cap_ops a2mp_chan_ops = {  	.teardown = l2cap_chan_no_teardown,  	.ready = l2cap_chan_no_ready,  	.defer = l2cap_chan_no_defer, +	.resume = l2cap_chan_no_resume, +	.set_shutdown = l2cap_chan_no_set_shutdown, +	.get_sndtimeo = l2cap_chan_no_get_sndtimeo,  };  static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) @@ -719,7 +732,11 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)  	BT_DBG("chan %p", chan); -	chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP; +	chan->chan_type = L2CAP_CHAN_FIXED; +	chan->scid = L2CAP_CID_A2MP; +	chan->dcid = L2CAP_CID_A2MP; +	chan->omtu = L2CAP_A2MP_DEFAULT_MTU; +	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;  	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;  	chan->ops = &a2mp_chan_ops; @@ -829,6 +846,9 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,  {  	struct amp_mgr *mgr; +	if (conn->hcon->type != ACL_LINK) +		return NULL; +  	mgr = amp_mgr_create(conn, false);  	if (!mgr) {  		BT_ERR("Could not create AMP manager"); @@ -871,7 +891,7 @@ void a2mp_send_getinfo_rsp(struct hci_dev *hdev)  	rsp.id = hdev->id;  	rsp.status = A2MP_STATUS_INVALID_CTRL_ID; -	if (hdev->amp_type != HCI_BREDR) { +	if (hdev->amp_type != AMP_TYPE_BREDR) {  		rsp.status = 0;  		rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);  		rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);  | 
