Blame SOURCES/0001-sdpd-Fix-leaking-buffers-stored-in-cstates-cache.patch

f3f10d
From 4e6a2402ed4f46ea026ad0929fbc14faecf3a475 Mon Sep 17 00:00:00 2001
f3f10d
From: Gopal Tiwari <gtiwari@redhat.com>
f3f10d
Date: Wed, 1 Dec 2021 12:18:24 +0530
f3f10d
Subject: [PATCH BlueZ] sdpd: Fix leaking buffers stored in cstates cache
f3f10d
f3f10d
commit e79417ed7185b150a056d4eb3a1ab528b91d2fc0
f3f10d
Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
f3f10d
Date:   Thu Jul 15 11:01:20 2021 -0700
f3f10d
f3f10d
    sdpd: Fix leaking buffers stored in cstates cache
f3f10d
f3f10d
    These buffer shall only be keep in cache for as long as they are
f3f10d
    needed so this would cleanup any client cstates in the following
f3f10d
    conditions:
f3f10d
f3f10d
     - There is no cstate on the response
f3f10d
     - No continuation can be found for cstate
f3f10d
     - Different request opcode
f3f10d
     - Respond with an error
f3f10d
     - Client disconnect
f3f10d
f3f10d
    Fixes: https://github.com/bluez/bluez/security/advisories/GHSA-3fqg-r8j5-f5xq
f3f10d
---
f3f10d
 src/sdpd-request.c | 170 ++++++++++++++++++++++++++++++++-------------
f3f10d
 src/sdpd-server.c  |  20 +++---
f3f10d
 src/sdpd.h         |   3 +
f3f10d
 unit/test-sdp.c    |   2 +-
f3f10d
 4 files changed, 135 insertions(+), 60 deletions(-)
f3f10d
f3f10d
diff --git a/src/sdpd-request.c b/src/sdpd-request.c
f3f10d
index 033d1e5bf..c8f5a2c72 100644
f3f10d
--- a/src/sdpd-request.c
f3f10d
+++ b/src/sdpd-request.c
f3f10d
@@ -42,48 +42,78 @@ typedef struct {
f3f10d
 
f3f10d
 #define MIN(x, y) ((x) < (y)) ? (x): (y)
f3f10d
 
f3f10d
-typedef struct _sdp_cstate_list sdp_cstate_list_t;
f3f10d
+typedef struct sdp_cont_info sdp_cont_info_t;
f3f10d
 
f3f10d
-struct _sdp_cstate_list {
f3f10d
-	sdp_cstate_list_t *next;
f3f10d
+struct sdp_cont_info {
f3f10d
+	int sock;
f3f10d
+	uint8_t opcode;
f3f10d
 	uint32_t timestamp;
f3f10d
 	sdp_buf_t buf;
f3f10d
 };
f3f10d
 
f3f10d
-static sdp_cstate_list_t *cstates;
f3f10d
+static sdp_list_t *cstates;
f3f10d
 
f3f10d
-/* FIXME: should probably remove it when it's found */
f3f10d
-static sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate)
f3f10d
+static int cstate_match(const void *data, const void *user_data)
f3f10d
 {
f3f10d
-	sdp_cstate_list_t *p;
f3f10d
+	const sdp_cont_info_t *cinfo = data;
f3f10d
+	const sdp_cont_state_t *cstate = user_data;
f3f10d
 
f3f10d
-	for (p = cstates; p; p = p->next) {
f3f10d
-		/* Check timestamp */
f3f10d
-		if (p->timestamp != cstate->timestamp)
f3f10d
-			continue;
f3f10d
+	/* Check timestamp */
f3f10d
+	return cinfo->timestamp - cstate->timestamp;
f3f10d
+}
f3f10d
+
f3f10d
+static void sdp_cont_info_free(sdp_cont_info_t *cinfo)
f3f10d
+{
f3f10d
+	if (!cinfo)
f3f10d
+		return;
f3f10d
+
f3f10d
+	cstates = sdp_list_remove(cstates, cinfo);
f3f10d
+	free(cinfo->buf.data);
f3f10d
+	free(cinfo);
f3f10d
+}
f3f10d
+
f3f10d
+static sdp_cont_info_t *sdp_get_cont_info(sdp_req_t *req,
f3f10d
+						sdp_cont_state_t *cstate)
f3f10d
+{
f3f10d
+	sdp_list_t *list;
f3f10d
+
f3f10d
+	list = sdp_list_find(cstates, cstate, cstate_match);
f3f10d
+	if (list) {
f3f10d
+		sdp_cont_info_t *cinfo = list->data;
f3f10d
 
f3f10d
-		/* Check if requesting more than available */
f3f10d
-		if (cstate->cStateValue.maxBytesSent < p->buf.data_size)
f3f10d
-			return &p->buf;
f3f10d
+		if (cinfo->opcode == req->opcode)
f3f10d
+			return cinfo;
f3f10d
+
f3f10d
+		/* Cleanup continuation if the opcode doesn't match since its
f3f10d
+		 * response buffer shall only be valid for the original requests
f3f10d
+		 */
f3f10d
+		sdp_cont_info_free(cinfo);
f3f10d
+		return NULL;
f3f10d
 	}
f3f10d
 
f3f10d
-	return 0;
f3f10d
+	/* Cleanup cstates if no continuation info could be found */
f3f10d
+	sdp_cstate_cleanup(req->sock);
f3f10d
+
f3f10d
+	return NULL;
f3f10d
 }
f3f10d
 
f3f10d
-static uint32_t sdp_cstate_alloc_buf(sdp_buf_t *buf)
f3f10d
+static uint32_t sdp_cstate_alloc_buf(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 {
f3f10d
-	sdp_cstate_list_t *cstate = malloc(sizeof(sdp_cstate_list_t));
f3f10d
+	sdp_cont_info_t *cinfo = malloc(sizeof(sdp_cont_info_t));
f3f10d
 	uint8_t *data = malloc(buf->data_size);
f3f10d
 
f3f10d
 	memcpy(data, buf->data, buf->data_size);
f3f10d
-	memset((char *)cstate, 0, sizeof(sdp_cstate_list_t));
f3f10d
-	cstate->buf.data = data;
f3f10d
-	cstate->buf.data_size = buf->data_size;
f3f10d
-	cstate->buf.buf_size = buf->data_size;
f3f10d
-	cstate->timestamp = sdp_get_time();
f3f10d
-	cstate->next = cstates;
f3f10d
-	cstates = cstate;
f3f10d
-	return cstate->timestamp;
f3f10d
+	memset(cinfo, 0, sizeof(sdp_cont_info_t));
f3f10d
+	cinfo->buf.data = data;
f3f10d
+	cinfo->buf.data_size = buf->data_size;
f3f10d
+	cinfo->buf.buf_size = buf->data_size;
f3f10d
+	cinfo->timestamp = sdp_get_time();
f3f10d
+	cinfo->sock = req->sock;
f3f10d
+	cinfo->opcode = req->opcode;
f3f10d
+
f3f10d
+	cstates = sdp_list_append(cstates, cinfo);
f3f10d
+
f3f10d
+	return cinfo->timestamp;
f3f10d
 }
f3f10d
 
f3f10d
 /* Additional values for checking datatype (not in spec) */
f3f10d
@@ -274,14 +304,16 @@ static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate)
f3f10d
 	return length;
f3f10d
 }
f3f10d
 
f3f10d
-static int sdp_cstate_get(uint8_t *buffer, size_t len,
f3f10d
-						sdp_cont_state_t **cstate)
f3f10d
+static int sdp_cstate_get(sdp_req_t *req, uint8_t *buffer, size_t len,
f3f10d
+			sdp_cont_state_t **cstate, sdp_cont_info_t **cinfo)
f3f10d
 {
f3f10d
 	uint8_t cStateSize = *buffer;
f3f10d
 
f3f10d
 	SDPDBG("Continuation State size : %d", cStateSize);
f3f10d
 
f3f10d
 	if (cStateSize == 0) {
f3f10d
+		/* Cleanup cstates if request doesn't contain a cstate */
f3f10d
+		sdp_cstate_cleanup(req->sock);
f3f10d
 		*cstate = NULL;
f3f10d
 		return 0;
f3f10d
 	}
f3f10d
@@ -306,6 +338,8 @@ static int sdp_cstate_get(uint8_t *buffer, size_t len,
f3f10d
 	SDPDBG("Cstate TS : 0x%x", (*cstate)->timestamp);
f3f10d
 	SDPDBG("Bytes sent : %d", (*cstate)->cStateValue.maxBytesSent);
f3f10d
 
f3f10d
+	*cinfo = sdp_get_cont_info(req, *cstate);
f3f10d
+
f3f10d
 	return 0;
f3f10d
 }
f3f10d
 
f3f10d
@@ -360,6 +394,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 	uint16_t expected, actual, rsp_count = 0;
f3f10d
 	uint8_t dtd;
f3f10d
 	sdp_cont_state_t *cstate = NULL;
f3f10d
+	sdp_cont_info_t *cinfo = NULL;
f3f10d
 	uint8_t *pCacheBuffer = NULL;
f3f10d
 	int handleSize = 0;
f3f10d
 	uint32_t cStateId = 0;
f3f10d
@@ -399,9 +434,9 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 
f3f10d
 	/*
f3f10d
 	 * Check if continuation state exists, if yes attempt
f3f10d
-	 * to get rsp remainder from cache, else send error
f3f10d
+	 * to get rsp remainder from continuation info, else send error
f3f10d
 	 */
f3f10d
-	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
f3f10d
+	if (sdp_cstate_get(req, pdata, data_left, &cstate, &cinfo) < 0) {
f3f10d
 		status = SDP_INVALID_SYNTAX;
f3f10d
 		goto done;
f3f10d
 	}
f3f10d
@@ -451,7 +486,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 
f3f10d
 		if (rsp_count > actual) {
f3f10d
 			/* cache the rsp and generate a continuation state */
f3f10d
-			cStateId = sdp_cstate_alloc_buf(buf);
f3f10d
+			cStateId = sdp_cstate_alloc_buf(req, buf);
f3f10d
 			/*
f3f10d
 			 * subtract handleSize since we now send only
f3f10d
 			 * a subset of handles
f3f10d
@@ -459,6 +494,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 			buf->data_size -= handleSize;
f3f10d
 		} else {
f3f10d
 			/* NULL continuation state */
f3f10d
+			sdp_cont_info_free(cinfo);
f3f10d
 			sdp_set_cstate_pdu(buf, NULL);
f3f10d
 		}
f3f10d
 	}
f3f10d
@@ -468,13 +504,15 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 		short lastIndex = 0;
f3f10d
 
f3f10d
 		if (cstate) {
f3f10d
-			/*
f3f10d
-			 * Get the previous sdp_cont_state_t and obtain
f3f10d
-			 * the cached rsp
f3f10d
-			 */
f3f10d
-			sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
f3f10d
-			if (pCache) {
f3f10d
-				pCacheBuffer = pCache->data;
f3f10d
+			if (cinfo) {
f3f10d
+				/* Check if requesting more than available */
f3f10d
+				if (cstate->cStateValue.maxBytesSent >=
f3f10d
+						cinfo->buf.data_size) {
f3f10d
+					status = SDP_INVALID_CSTATE;
f3f10d
+					goto done;
f3f10d
+				}
f3f10d
+
f3f10d
+				pCacheBuffer = cinfo->buf.data;
f3f10d
 				/* get the rsp_count from the cached buffer */
f3f10d
 				rsp_count = get_be16(pCacheBuffer);
f3f10d
 
f3f10d
@@ -518,6 +556,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 		if (i == rsp_count) {
f3f10d
 			/* set "null" continuationState */
f3f10d
 			sdp_set_cstate_pdu(buf, NULL);
f3f10d
+			sdp_cont_info_free(cinfo);
f3f10d
 		} else {
f3f10d
 			/*
f3f10d
 			 * there's more: set lastIndexSent to
f3f10d
@@ -540,6 +579,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 
f3f10d
 done:
f3f10d
 	free(cstate);
f3f10d
+
f3f10d
 	if (pattern)
f3f10d
 		sdp_list_free(pattern, free);
f3f10d
 
f3f10d
@@ -619,15 +659,21 @@ static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, sdp_buf_t *buf)
f3f10d
 }
f3f10d
 
f3f10d
 /* Build cstate response */
f3f10d
-static int sdp_cstate_rsp(sdp_cont_state_t *cstate, sdp_buf_t *buf,
f3f10d
-							uint16_t max)
f3f10d
+static int sdp_cstate_rsp(sdp_cont_info_t *cinfo, sdp_cont_state_t *cstate,
f3f10d
+					sdp_buf_t *buf, uint16_t max)
f3f10d
 {
f3f10d
-	/* continuation State exists -> get from cache */
f3f10d
-	sdp_buf_t *cache = sdp_get_cached_rsp(cstate);
f3f10d
+	sdp_buf_t *cache;
f3f10d
 	uint16_t sent;
f3f10d
 
f3f10d
-	if (!cache)
f3f10d
+	if (!cinfo)
f3f10d
+		return 0;
f3f10d
+
f3f10d
+	if (cstate->cStateValue.maxBytesSent >= cinfo->buf.data_size) {
f3f10d
+		sdp_cont_info_free(cinfo);
f3f10d
 		return 0;
f3f10d
+	}
f3f10d
+
f3f10d
+	cache = &cinfo->buf;
f3f10d
 
f3f10d
 	sent = MIN(max, cache->data_size - cstate->cStateValue.maxBytesSent);
f3f10d
 	memcpy(buf->data, cache->data + cstate->cStateValue.maxBytesSent, sent);
f3f10d
@@ -637,8 +683,10 @@ static int sdp_cstate_rsp(sdp_cont_state_t *cstate, sdp_buf_t *buf,
f3f10d
 	SDPDBG("Response size : %d sending now : %d bytes sent so far : %d",
f3f10d
 		cache->data_size, sent, cstate->cStateValue.maxBytesSent);
f3f10d
 
f3f10d
-	if (cstate->cStateValue.maxBytesSent == cache->data_size)
f3f10d
+	if (cstate->cStateValue.maxBytesSent == cache->data_size) {
f3f10d
+		sdp_cont_info_free(cinfo);
f3f10d
 		return sdp_set_cstate_pdu(buf, NULL);
f3f10d
+	}
f3f10d
 
f3f10d
 	return sdp_set_cstate_pdu(buf, cstate);
f3f10d
 }
f3f10d
@@ -652,6 +700,7 @@ static int sdp_cstate_rsp(sdp_cont_state_t *cstate, sdp_buf_t *buf,
f3f10d
 static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 {
f3f10d
 	sdp_cont_state_t *cstate = NULL;
f3f10d
+	sdp_cont_info_t *cinfo = NULL;
f3f10d
 	short cstate_size = 0;
f3f10d
 	sdp_list_t *seq = NULL;
f3f10d
 	uint8_t dtd = 0;
f3f10d
@@ -708,7 +757,7 @@ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 	 * if continuation state exists, attempt
f3f10d
 	 * to get rsp remainder from cache, else send error
f3f10d
 	 */
f3f10d
-	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
f3f10d
+	if (sdp_cstate_get(req, pdata, data_left, &cstate, &cinfo) < 0) {
f3f10d
 		status = SDP_INVALID_SYNTAX;
f3f10d
 		goto done;
f3f10d
 	}
f3f10d
@@ -737,7 +786,7 @@ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 	buf->buf_size -= sizeof(uint16_t);
f3f10d
 
f3f10d
 	if (cstate) {
f3f10d
-		cstate_size = sdp_cstate_rsp(cstate, buf, max_rsp_size);
f3f10d
+		cstate_size = sdp_cstate_rsp(cinfo, cstate, buf, max_rsp_size);
f3f10d
 		if (!cstate_size) {
f3f10d
 			status = SDP_INVALID_CSTATE;
f3f10d
 			error("NULL cache buffer and non-NULL continuation state");
f3f10d
@@ -749,7 +798,7 @@ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 			sdp_cont_state_t newState;
f3f10d
 
f3f10d
 			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
f3f10d
-			newState.timestamp = sdp_cstate_alloc_buf(buf);
f3f10d
+			newState.timestamp = sdp_cstate_alloc_buf(req, buf);
f3f10d
 			/*
f3f10d
 			 * Reset the buffer size to the maximum expected and
f3f10d
 			 * set the sdp_cont_state_t
f3f10d
@@ -793,6 +842,7 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 	int scanned, rsp_count = 0;
f3f10d
 	sdp_list_t *pattern = NULL, *seq = NULL, *svcList;
f3f10d
 	sdp_cont_state_t *cstate = NULL;
f3f10d
+	sdp_cont_info_t *cinfo = NULL;
f3f10d
 	short cstate_size = 0;
f3f10d
 	uint8_t dtd = 0;
f3f10d
 	sdp_buf_t tmpbuf;
f3f10d
@@ -852,7 +902,7 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 	 * if continuation state exists attempt
f3f10d
 	 * to get rsp remainder from cache, else send error
f3f10d
 	 */
f3f10d
-	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
f3f10d
+	if (sdp_cstate_get(req, pdata, data_left, &cstate, &cinfo) < 0) {
f3f10d
 		status = SDP_INVALID_SYNTAX;
f3f10d
 		goto done;
f3f10d
 	}
f3f10d
@@ -906,7 +956,7 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 			sdp_cont_state_t newState;
f3f10d
 
f3f10d
 			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
f3f10d
-			newState.timestamp = sdp_cstate_alloc_buf(buf);
f3f10d
+			newState.timestamp = sdp_cstate_alloc_buf(req, buf);
f3f10d
 			/*
f3f10d
 			 * Reset the buffer size to the maximum expected and
f3f10d
 			 * set the sdp_cont_state_t
f3f10d
@@ -917,7 +967,7 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
f3f10d
 		} else
f3f10d
 			cstate_size = sdp_set_cstate_pdu(buf, NULL);
f3f10d
 	} else {
f3f10d
-		cstate_size = sdp_cstate_rsp(cstate, buf, max);
f3f10d
+		cstate_size = sdp_cstate_rsp(cinfo, cstate, buf, max);
f3f10d
 		if (!cstate_size) {
f3f10d
 			status = SDP_INVALID_CSTATE;
f3f10d
 			SDPDBG("Non-null continuation state, but null cache buffer");
f3f10d
@@ -974,6 +1024,9 @@ static void process_request(sdp_req_t *req)
f3f10d
 		status = SDP_INVALID_PDU_SIZE;
f3f10d
 		goto send_rsp;
f3f10d
 	}
f3f10d
+
f3f10d
+	req->opcode = reqhdr->pdu_id;
f3f10d
+
f3f10d
 	switch (reqhdr->pdu_id) {
f3f10d
 	case SDP_SVC_SEARCH_REQ:
f3f10d
 		SDPDBG("Got a svc srch req");
f3f10d
@@ -1020,6 +1073,8 @@ static void process_request(sdp_req_t *req)
f3f10d
 
f3f10d
 send_rsp:
f3f10d
 	if (status) {
f3f10d
+		/* Cleanup cstates on error */
f3f10d
+		sdp_cstate_cleanup(req->sock);
f3f10d
 		rsphdr->pdu_id = SDP_ERROR_RSP;
f3f10d
 		put_be16(status, rsp.data);
f3f10d
 		rsp.data_size = sizeof(uint16_t);
f3f10d
@@ -1108,3 +1163,20 @@ void handle_request(int sk, uint8_t *data, int len)
f3f10d
 
f3f10d
 	process_request(&req;;
f3f10d
 }
f3f10d
+
f3f10d
+void sdp_cstate_cleanup(int sock)
f3f10d
+{
f3f10d
+	sdp_list_t *list;
f3f10d
+
f3f10d
+	/* Remove any cinfo for the client */
f3f10d
+	for (list = cstates; list;) {
f3f10d
+		sdp_cont_info_t *cinfo = list->data;
f3f10d
+
f3f10d
+		list = list->next;
f3f10d
+
f3f10d
+		if (cinfo->sock != sock)
f3f10d
+			continue;
f3f10d
+
f3f10d
+		sdp_cont_info_free(cinfo);
f3f10d
+	}
f3f10d
+}
f3f10d
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
f3f10d
index dfd8b1f00..66ee7ba14 100644
f3f10d
--- a/src/sdpd-server.c
f3f10d
+++ b/src/sdpd-server.c
f3f10d
@@ -146,16 +146,12 @@ static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, gpointer d
f3f10d
 
f3f10d
 	sk = g_io_channel_unix_get_fd(chan);
f3f10d
 
f3f10d
-	if (cond & (G_IO_HUP | G_IO_ERR)) {
f3f10d
-		sdp_svcdb_collect_all(sk);
f3f10d
-		return FALSE;
f3f10d
-	}
f3f10d
+	if (cond & (G_IO_HUP | G_IO_ERR))
f3f10d
+		goto cleanup;
f3f10d
 
f3f10d
 	len = recv(sk, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK);
f3f10d
-	if (len < 0 || (unsigned int) len < sizeof(sdp_pdu_hdr_t)) {
f3f10d
-		sdp_svcdb_collect_all(sk);
f3f10d
-		return FALSE;
f3f10d
-	}
f3f10d
+	if (len < 0 || (unsigned int) len < sizeof(sdp_pdu_hdr_t))
f3f10d
+		goto cleanup;
f3f10d
 
f3f10d
 	size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen);
f3f10d
 	buf = malloc(size);
f3f10d
@@ -168,14 +164,18 @@ static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, gpointer d
f3f10d
 	 * inside handle_request() in order to produce ErrorResponse.
f3f10d
 	 */
f3f10d
 	if (len <= 0) {
f3f10d
-		sdp_svcdb_collect_all(sk);
f3f10d
 		free(buf);
f3f10d
-		return FALSE;
f3f10d
+		goto cleanup;
f3f10d
 	}
f3f10d
 
f3f10d
 	handle_request(sk, buf, len);
f3f10d
 
f3f10d
 	return TRUE;
f3f10d
+
f3f10d
+cleanup:
f3f10d
+	sdp_svcdb_collect_all(sk);
f3f10d
+	sdp_cstate_cleanup(sk);
f3f10d
+	return FALSE;
f3f10d
 }
f3f10d
 
f3f10d
 static gboolean io_accept_event(GIOChannel *chan, GIOCondition cond, gpointer data)
f3f10d
diff --git a/src/sdpd.h b/src/sdpd.h
f3f10d
index 257411f03..4316aff67 100644
f3f10d
--- a/src/sdpd.h
f3f10d
+++ b/src/sdpd.h
f3f10d
@@ -27,8 +27,11 @@ typedef struct request {
f3f10d
 	int      flags;
f3f10d
 	uint8_t  *buf;
f3f10d
 	int      len;
f3f10d
+	uint8_t  opcode;
f3f10d
 } sdp_req_t;
f3f10d
 
f3f10d
+void sdp_cstate_cleanup(int sock);
f3f10d
+
f3f10d
 void handle_internal_request(int sk, int mtu, void *data, int len);
f3f10d
 void handle_request(int sk, uint8_t *data, int len);
f3f10d
 
f3f10d
diff --git a/unit/test-sdp.c b/unit/test-sdp.c
f3f10d
index d3a885f19..8f95fcb71 100644
f3f10d
--- a/unit/test-sdp.c
f3f10d
+++ b/unit/test-sdp.c
f3f10d
@@ -235,7 +235,7 @@ static gboolean client_handler(GIOChannel *channel, GIOCondition cond,
f3f10d
 	tester_monitor('>', 0x0000, 0x0001, buf, len);
f3f10d
 
f3f10d
 	g_assert(len > 0);
f3f10d
-	g_assert((size_t) len == rsp_pdu->raw_size + rsp_pdu->cont_len);
f3f10d
+	g_assert_cmpuint(len, ==, rsp_pdu->raw_size + rsp_pdu->cont_len);
f3f10d
 
f3f10d
 	g_assert(memcmp(buf, rsp_pdu->raw_data,	rsp_pdu->raw_size) == 0);
f3f10d
 
f3f10d
-- 
f3f10d
2.26.2
f3f10d