Module Name:    src
Committed By:   plunky
Date:           Tue Nov 29 13:16:27 UTC 2011

Modified Files:
        src/sys/netbt: l2cap_signal.c

Log Message:
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


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/sys/netbt/l2cap_signal.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netbt/l2cap_signal.c
diff -u src/sys/netbt/l2cap_signal.c:1.14 src/sys/netbt/l2cap_signal.c:1.15
--- src/sys/netbt/l2cap_signal.c:1.14	Wed Jul 27 10:25:09 2011
+++ src/sys/netbt/l2cap_signal.c	Tue Nov 29 13:16:27 2011
@@ -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(st
 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, st
 			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, st
 				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 *
 
 	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);
+}

Reply via email to