Handle some ``Quality of Service'' configuration options, to

help devices requesting them blindly succeed in connecting.

should fix a problem analysed by Nat Sloss on current-users
This commit is contained in:
plunky 2011-11-29 13:16:27 +00:00
parent 47be4b7567
commit 07449e2f8a

View File

@ -1,4 +1,4 @@
/* $NetBSD: l2cap_signal.c,v 1.14 2011/07/27 10:25:09 plunky Exp $ */
/* $NetBSD: l2cap_signal.c,v 1.15 2011/11/29 13:16:27 plunky Exp $ */
/*-
* Copyright (c) 2005 Iain Hibbert.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: l2cap_signal.c,v 1.14 2011/07/27 10:25:09 plunky Exp $");
__KERNEL_RCSID(0, "$NetBSD: l2cap_signal.c,v 1.15 2011/11/29 13:16:27 plunky Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -59,6 +59,8 @@ static void l2cap_recv_disconnect_rsp(struct mbuf *, struct hci_link *);
static void l2cap_recv_info_req(struct mbuf *, struct hci_link *);
static int l2cap_send_signal(struct hci_link *, uint8_t, uint8_t, uint16_t, void *);
static int l2cap_send_command_rej(struct hci_link *, uint8_t, uint16_t, ...);
static void l2cap_qos_btoh(l2cap_qos_t *, void *);
static void l2cap_qos_htob(void *, l2cap_qos_t *);
/*
* process incoming signal packets (CID 0x0001). Can contain multiple
@ -518,6 +520,57 @@ l2cap_recv_config_req(struct mbuf *m, struct hci_link *link)
break;
case L2CAP_OPT_QOS:
if (rp.result == L2CAP_UNKNOWN_OPTION)
break;
if (opt.length != L2CAP_OPT_QOS_SIZE)
goto reject;
/*
* We don't actually support QoS, but an incoming
* config request is merely advising us of their
* outgoing traffic flow, so be nice.
*/
m_copydata(m, 0, L2CAP_OPT_QOS_SIZE, &val);
switch (val.qos.service_type) {
case L2CAP_QOS_NO_TRAFFIC:
/*
* "No traffic" means they don't plan to send
* any data and the fields should be ignored.
*/
chan->lc_iqos = l2cap_default_qos;
chan->lc_iqos.service_type = L2CAP_QOS_NO_TRAFFIC;
break;
case L2CAP_QOS_BEST_EFFORT:
/*
* "Best effort" is the default, and we may
* choose to ignore the fields, try to satisfy
* the parameters while giving no response, or
* respond with the settings we will try to
* meet.
*/
l2cap_qos_btoh(&chan->lc_iqos, &val.qos);
break;
case L2CAP_QOS_GUARANTEED:
default:
/*
* Anything else we don't support, so make a
* counter-offer with the current settings.
*/
if (len + sizeof(opt) + L2CAP_OPT_QOS_SIZE > sizeof(buf))
goto reject;
rp.result = L2CAP_UNACCEPTABLE_PARAMS;
memcpy(buf + len, &opt, sizeof(opt));
len += sizeof(opt);
l2cap_qos_htob(buf + len, &chan->lc_iqos);
len += L2CAP_OPT_QOS_SIZE;
break;
}
break;
default:
/* ignore hints */
if (opt.type & L2CAP_OPT_HINT_BIT)
@ -688,6 +741,27 @@ l2cap_recv_config_rsp(struct mbuf *m, struct hci_link *link)
goto discon;
case L2CAP_OPT_QOS:
if (opt.length != L2CAP_OPT_QOS_SIZE)
goto discon;
/*
* This may happen even if we haven't sent a
* QoS request, where they need to state their
* preferred incoming traffic flow.
* We don't support anything, but copy in the
* parameters if no action is good enough.
*/
m_copydata(m, 0, L2CAP_OPT_QOS_SIZE, &val);
switch (val.qos.service_type) {
case L2CAP_QOS_NO_TRAFFIC:
case L2CAP_QOS_BEST_EFFORT:
l2cap_qos_btoh(&chan->lc_oqos, &val.qos);
break;
case L2CAP_QOS_GUARANTEED:
default:
goto discon;
}
break;
default:
@ -1130,3 +1204,37 @@ l2cap_send_connect_rsp(struct hci_link *link, uint8_t ident, uint16_t dcid, uint
return l2cap_send_signal(link, L2CAP_CONNECT_RSP, ident, sizeof(cp), &cp);
}
/*
* copy in QoS buffer to host
*/
static void
l2cap_qos_btoh(l2cap_qos_t *qos, void *buf)
{
l2cap_qos_t *src = buf;
qos->flags = src->flags;
qos->service_type = src->service_type;
qos->token_rate = le32toh(src->token_rate);
qos->token_bucket_size = le32toh(src->token_bucket_size);
qos->peak_bandwidth = le32toh(src->peak_bandwidth);
qos->latency = le32toh(src->latency);
qos->delay_variation = le32toh(src->delay_variation);
}
/*
* copy out host QoS to buffer
*/
static void
l2cap_qos_htob(void *buf, l2cap_qos_t *qos)
{
l2cap_qos_t *dst = buf;
dst->flags = qos->flags;
dst->service_type = qos->service_type;
dst->token_rate = htole32(qos->token_rate);
dst->token_bucket_size = htole32(qos->token_bucket_size);
dst->peak_bandwidth = htole32(qos->peak_bandwidth);
dst->latency = htole32(qos->latency);
dst->delay_variation = htole32(qos->delay_variation);
}