Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c551cf8f authored by Jack Pham's avatar Jack Pham
Browse files

usb: pd: Add stricter checking for handling VDM responses



The PD 2.0 compliance tests TD.PD.VDMD.E2 (tVDMSenderResponse
Timeout) and TD.PD.VDMD.E3 (Incorrect Identity Fields) check
that a DFP should drop untimely or invalid responses to SVDM
Discovery messages.

Add a timing marker from the time an SVDM is initiated in
order to track if a response is later than SENDER_RESPONSE_TIME,
and if so, drop it. Also add additional fields checking in
handle_vdm_rx() to determine if the response is well-formed,
otherwise drop it.

Change-Id: I341fcd79abae1b35c0f3105dbb7d30d350ea56be
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent 51c5d1f0
Loading
Loading
Loading
Loading
+32 −2
Original line number Diff line number Diff line
@@ -327,6 +327,7 @@ static void *usbpd_ipc_log;
/* VDM header is the first 32-bit object following the 16-bit PD header */
#define VDM_HDR_SVID(hdr)	((hdr) >> 16)
#define VDM_IS_SVDM(hdr)	((hdr) & 0x8000)
#define SVDM_HDR_VER(hdr)	(((hdr) >> 13) & 0x3)
#define SVDM_HDR_OBJ_POS(hdr)	(((hdr) >> 8) & 0x7)
#define SVDM_HDR_CMD_TYPE(hdr)	(((hdr) >> 6) & 0x3)
#define SVDM_HDR_CMD(hdr)	((hdr) & 0x1f)
@@ -451,6 +452,7 @@ struct usbpd {
	struct vdm_tx		*vdm_tx_retry;
	struct mutex		svid_handler_lock;
	struct list_head	svid_handlers;
	ktime_t			svdm_start_time;

	struct list_head	instance;

@@ -1336,9 +1338,12 @@ static void handle_vdm_resp_ack(struct usbpd *pd, u32 *vdos, u8 num_vdos,
		kfree(pd->vdm_tx_retry);
		pd->vdm_tx_retry = NULL;

		if (num_vdos && ID_HDR_PRODUCT_TYPE(vdos[0]) ==
				ID_HDR_PRODUCT_VPD) {
		if (!num_vdos) {
			usbpd_dbg(&pd->dev, "Discarding Discover ID response with no VDOs\n");
			break;
		}

		if (ID_HDR_PRODUCT_TYPE(vdos[0]) == ID_HDR_PRODUCT_VPD) {
			usbpd_dbg(&pd->dev, "VPD detected turn off vbus\n");

			if (pd->vbus_enabled) {
@@ -1354,6 +1359,12 @@ static void handle_vdm_resp_ack(struct usbpd *pd, u32 *vdos, u8 num_vdos,
		if (!pd->in_explicit_contract)
			break;

		if (SVDM_HDR_OBJ_POS(vdm_hdr) != 0) {
			usbpd_dbg(&pd->dev, "Discarding Discover ID response with incorrect object position:%d\n",
					SVDM_HDR_OBJ_POS(vdm_hdr));
			break;
		}

		pd->vdm_state = DISCOVERED_ID;
		usbpd_send_svdm(pd, USBPD_SID,
				USBPD_SVDM_DISCOVER_SVIDS,
@@ -1460,6 +1471,7 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg)
	u8 cmd = SVDM_HDR_CMD(vdm_hdr);
	u8 cmd_type = SVDM_HDR_CMD_TYPE(vdm_hdr);
	struct usbpd_svid_handler *handler;
	ktime_t recvd_time = ktime_get();

	usbpd_dbg(&pd->dev,
			"VDM rx: svid:%x cmd:%x cmd_type:%x vdm_hdr:%x has_dp: %s\n",
@@ -1489,6 +1501,12 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg)
		return;
	}

	if (SVDM_HDR_VER(vdm_hdr) > 1) {
		usbpd_dbg(&pd->dev, "Discarding SVDM with incorrect version:%d\n",
				SVDM_HDR_VER(vdm_hdr));
		return;
	}

	/* if this interrupts a previous exchange, abort queued response */
	if (cmd_type == SVDM_CMD_TYPE_INITIATOR && pd->vdm_tx) {
		usbpd_dbg(&pd->dev, "Discarding previously queued SVDM tx (SVID:0x%04x)\n",
@@ -1528,6 +1546,12 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg)
			break;
		}

		if (ktime_ms_delta(recvd_time, pd->svdm_start_time) >
				SENDER_RESPONSE_TIME) {
			usbpd_dbg(&pd->dev, "Discarding delayed SVDM response due to timeout\n");
			break;
		}

		handle_vdm_resp_ack(pd, vdos, num_vdos, cmd);
		break;

@@ -1594,6 +1618,12 @@ static void handle_vdm_tx(struct usbpd *pd, enum pd_sop_type sop_type)
		return;
	}

	/* start tVDMSenderResponse timer */
	if (VDM_IS_SVDM(vdm_hdr) &&
		SVDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR) {
		pd->svdm_start_time = ktime_get();
	}

	/*
	 * special case: keep initiated Discover ID/SVIDs
	 * around in case we need to re-try when receiving BUSY