From patchwork Wed Oct 19 10:35:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Grzeschik X-Patchwork-Id: 13011577 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0C494C4332F for ; Wed, 19 Oct 2022 11:08:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230355AbiJSLIF (ORCPT ); Wed, 19 Oct 2022 07:08:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42362 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233870AbiJSLH2 (ORCPT ); Wed, 19 Oct 2022 07:07:28 -0400 Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de [IPv6:2001:67c:670:201:290:27ff:fe1d:cc33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 571C617653F for ; Wed, 19 Oct 2022 03:36:23 -0700 (PDT) Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1ol6Q2-0005oI-9s; Wed, 19 Oct 2022 12:35:26 +0200 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtp (Exim 4.94.2) (envelope-from ) id 1ol6Q1-0006FY-K0; Wed, 19 Oct 2022 12:35:25 +0200 Received: from mgr by dude04.red.stw.pengutronix.de with local (Exim 4.94.2) (envelope-from ) id 1ol6Q0-00COQ3-Jy; Wed, 19 Oct 2022 12:35:24 +0200 From: Michael Grzeschik To: linux-usb@vger.kernel.org Cc: linux-media@vger.kernel.org, balbi@kernel.org, laurent.pinchart@ideasonboard.com, kernel@pengutronix.de Subject: [PATCH v4 1/2] usb: gadget: uvc: default the ctrl request interface offsets Date: Wed, 19 Oct 2022 12:35:21 +0200 Message-Id: <20221019103522.2925375-2-m.grzeschik@pengutronix.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221019103522.2925375-1-m.grzeschik@pengutronix.de> References: <20221019103522.2925375-1-m.grzeschik@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: mgr@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org For the userspace it is needed to distinguish between requests for the control or streaming interface. The userspace would have to parse the configfs to know which interface index it has to compare the ctrl requests against. Since the interface numbers are not fixed, e.g. for composite gadgets, the interface offset depends on the setup. The kernel has this information when handing over the ctrl request to the userspace. This patch removes the offset from the interface numbers and expose the default interface defines in the uapi g_uvc.h. Signed-off-by: Michael Grzeschik --- v1 - v2: - removed the extra variable in struct uvc_event - replacing the ctrl request interface bits in place - included the move of the default interface defines to g_uvc.h v2 - v3: - improced coding style v3 - v4: - no changes drivers/usb/gadget/function/f_uvc.c | 15 ++++++++++++--- include/uapi/linux/usb/g_uvc.h | 3 +++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 6e196e06181ecf..6e131624011a5e 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -39,9 +39,6 @@ MODULE_PARM_DESC(trace, "Trace level bitmask"); /* string IDs are assigned dynamically */ -#define UVC_STRING_CONTROL_IDX 0 -#define UVC_STRING_STREAMING_IDX 1 - static struct usb_string uvc_en_us_strings[] = { /* [UVC_STRING_CONTROL_IDX].s = DYNAMIC, */ [UVC_STRING_STREAMING_IDX].s = "Video Streaming", @@ -228,6 +225,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) struct uvc_device *uvc = to_uvc(f); struct v4l2_event v4l2_event; struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; + unsigned int interface = le16_to_cpu(ctrl->wIndex) & 0xff; + struct usb_ctrlrequest *mctrl; if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) { uvcg_info(f, "invalid request type\n"); @@ -248,6 +247,16 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_SETUP; memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req)); + + /* check for the interface number, fixup the interface number in + * the ctrl request so the userspace doesn't have to bother with + * offset and configfs parsing + */ + mctrl = &uvc_event->req; + mctrl->wIndex &= ~cpu_to_le16(0xff); + if (interface == uvc->streaming_intf) + mctrl->wIndex = cpu_to_le16(UVC_STRING_STREAMING_IDX); + v4l2_event_queue(&uvc->vdev, &v4l2_event); return 0; diff --git a/include/uapi/linux/usb/g_uvc.h b/include/uapi/linux/usb/g_uvc.h index 652f169a019e7d..8d7824dde1b2f9 100644 --- a/include/uapi/linux/usb/g_uvc.h +++ b/include/uapi/linux/usb/g_uvc.h @@ -21,6 +21,9 @@ #define UVC_EVENT_DATA (V4L2_EVENT_PRIVATE_START + 5) #define UVC_EVENT_LAST (V4L2_EVENT_PRIVATE_START + 5) +#define UVC_STRING_CONTROL_IDX 0 +#define UVC_STRING_STREAMING_IDX 1 + struct uvc_request_data { __s32 length; __u8 data[60]; From patchwork Wed Oct 19 10:35:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Grzeschik X-Patchwork-Id: 13011578 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 169B1C433FE for ; Wed, 19 Oct 2022 11:08:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231615AbiJSLIJ (ORCPT ); Wed, 19 Oct 2022 07:08:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33258 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233795AbiJSLH2 (ORCPT ); Wed, 19 Oct 2022 07:07:28 -0400 Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de [IPv6:2001:67c:670:201:290:27ff:fe1d:cc33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B3E1A1781EE for ; Wed, 19 Oct 2022 03:36:21 -0700 (PDT) Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1ol6Q2-0005oG-9s; Wed, 19 Oct 2022 12:35:26 +0200 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtp (Exim 4.94.2) (envelope-from ) id 1ol6Q1-0006FV-Eo; Wed, 19 Oct 2022 12:35:25 +0200 Received: from mgr by dude04.red.stw.pengutronix.de with local (Exim 4.94.2) (envelope-from ) id 1ol6Q0-00COQ6-KL; Wed, 19 Oct 2022 12:35:24 +0200 From: Michael Grzeschik To: linux-usb@vger.kernel.org Cc: linux-media@vger.kernel.org, balbi@kernel.org, laurent.pinchart@ideasonboard.com, kernel@pengutronix.de Subject: [PATCH v4 2/2] usb: gadget: uvc: add validate and fix function for uvc response Date: Wed, 19 Oct 2022 12:35:22 +0200 Message-Id: <20221019103522.2925375-3-m.grzeschik@pengutronix.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221019103522.2925375-1-m.grzeschik@pengutronix.de> References: <20221019103522.2925375-1-m.grzeschik@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: mgr@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org When the userspace gets the setup requests for UVC_GET_CUR UVC_GET_MIN, UVC_GET_MAX, UVC_GET_DEF it will fill out the ctrl response. This data needs to be validated. Since the kernel also knows the limits for valid cases, it can fixup the values in case the userspace is setting invalid data. Signed-off-by: Michael Grzeschik --- v1 -> v4: - new patch drivers/usb/gadget/function/f_uvc.c | 4 +- drivers/usb/gadget/function/uvc.h | 1 + drivers/usb/gadget/function/uvc_v4l2.c | 76 ++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 6e131624011a5e..098bd3c4e3c0b3 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -254,8 +254,10 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) */ mctrl = &uvc_event->req; mctrl->wIndex &= ~cpu_to_le16(0xff); - if (interface == uvc->streaming_intf) + if (interface == uvc->streaming_intf) { + uvc->streaming_request = ctrl->bRequest; mctrl->wIndex = cpu_to_le16(UVC_STRING_STREAMING_IDX); + } v4l2_event_queue(&uvc->vdev, &v4l2_event); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 40226b1f7e148a..1be4d5f24b46bf 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -151,6 +151,7 @@ struct uvc_device { void *control_buf; unsigned int streaming_intf; + unsigned char streaming_request; /* Events */ unsigned int event_length; diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index c4ed48d6b8a407..d67aef71f8afc3 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -178,6 +178,67 @@ static struct uvcg_frame *find_closest_frame_by_size(struct uvc_device *uvc, * Requests handling */ +/* validate and fixup streaming ctrl request response data if possible */ +static void +uvc_validate_streaming_ctrl(struct uvc_device *uvc, + struct uvc_streaming_control *ctrl) +{ + struct f_uvc_opts *opts = fi_to_f_uvc_opts(uvc->func.fi); + unsigned int iformat, iframe; + struct uvcg_format *uformat; + struct uvcg_frame *uframe; + bool ival_found = false; + int i; + + iformat = ctrl->bFormatIndex; + iframe = ctrl->bFrameIndex; + + /* Restrict the iformat, iframe and dwFrameInterval to valid values. + * Negative values for iformat and iframe will result in the maximum + * valid value being selected + */ + iformat = clamp((unsigned int)iformat, 1U, + (unsigned int)uvc->header->num_fmt); + if (iformat != ctrl->bFormatIndex) { + uvcg_info(&uvc->func, + "Userspace set invalid Format Index - fixup\n"); + ctrl->bFormatIndex = iformat; + } + uformat = find_format_by_index(uvc, iformat); + + iframe = clamp((unsigned int)iframe, 1U, + (unsigned int)uformat->num_frames); + if (iframe != ctrl->bFrameIndex) { + uvcg_info(&uvc->func, + "Userspace set invalid Frame Index - fixup\n"); + ctrl->bFrameIndex = iframe; + } + uframe = find_frame_by_index(uvc, uformat, iframe); + + if (ctrl->dwFrameInterval) { + for (i = 0; i < uframe->frame.b_frame_interval_type; i++) { + if (ctrl->dwFrameInterval == + uframe->dw_frame_interval[i]) + ival_found = true; + } + } + if (!ival_found) { + uvcg_info(&uvc->func, + "Userspace set invalid Frame Inteval - fixup\n"); + ctrl->dwFrameInterval = uframe->frame.dw_default_frame_interval; + } + + if (!ctrl->dwMaxPayloadTransferSize || + ctrl->dwMaxPayloadTransferSize > + opts->streaming_maxpacket) + ctrl->dwMaxPayloadTransferSize = opts->streaming_maxpacket; + + if (!ctrl->dwMaxVideoFrameSize || + ctrl->dwMaxVideoFrameSize > + uframe->frame.dw_max_video_frame_buffer_size) + ctrl->dwMaxVideoFrameSize = uvc_get_frame_size(uformat, uframe); +} + static int uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data) { @@ -192,6 +253,21 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data) memcpy(req->buf, data->data, req->length); + /* validate the ctrl content and fixup */ + if (!uvc->event_setup_out) { + struct uvc_streaming_control *ctrl = req->buf; + + switch (uvc->streaming_request) { + case UVC_GET_CUR: + case UVC_GET_MIN: + case UVC_GET_MAX: + case UVC_GET_DEF: + uvc_validate_streaming_ctrl(uvc, ctrl); + default: + break; + } + } + return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL); }