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

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