Skip to content

Commit fa75ac3

Browse files
author
Sarah Sharp
committed
xhci: Reject double add of active endpoints.
While trying to switch a UAS device from the BOT configuration to the UAS configuration via the bConfigurationValue file, Tanya ran into an issue in the USB core. usb_disable_device() sets entries in udev->ep_out and udev->ep_out to NULL, but doesn't call into the xHCI bandwidth management functions to remove the BOT configuration endpoints from the xHCI host's internal structures. The USB core would then attempt to add endpoints for the UAS configuration, and some of the endpoints had the same address as endpoints in the BOT configuration. The xHCI driver blindly added the endpoints again, but the xHCI host controller rejected the Configure Endpoint command because active endpoints were added without being dropped. Make the xHCI driver reject calls to xhci_add_endpoint() that attempt to add active endpoints without first calling xhci_drop_endpoint(). This should be backported to kernels as old as 2.6.31. Signed-off-by: Sarah Sharp <[email protected]> Reported-by: Tanya Brokhman <[email protected]> Cc: [email protected]
1 parent 357f45d commit fa75ac3

File tree

1 file changed

+18
-4
lines changed

1 file changed

+18
-4
lines changed

drivers/usb/host/xhci.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
14011401
u32 added_ctxs;
14021402
unsigned int last_ctx;
14031403
u32 new_add_flags, new_drop_flags, new_slot_info;
1404+
struct xhci_virt_device *virt_dev;
14041405
int ret = 0;
14051406

14061407
ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
@@ -1425,11 +1426,25 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
14251426
return 0;
14261427
}
14271428

1428-
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
1429-
out_ctx = xhci->devs[udev->slot_id]->out_ctx;
1429+
virt_dev = xhci->devs[udev->slot_id];
1430+
in_ctx = virt_dev->in_ctx;
1431+
out_ctx = virt_dev->out_ctx;
14301432
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
14311433
ep_index = xhci_get_endpoint_index(&ep->desc);
14321434
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
1435+
1436+
/* If this endpoint is already in use, and the upper layers are trying
1437+
* to add it again without dropping it, reject the addition.
1438+
*/
1439+
if (virt_dev->eps[ep_index].ring &&
1440+
!(le32_to_cpu(ctrl_ctx->drop_flags) &
1441+
xhci_get_endpoint_flag(&ep->desc))) {
1442+
xhci_warn(xhci, "Trying to add endpoint 0x%x "
1443+
"without dropping it.\n",
1444+
(unsigned int) ep->desc.bEndpointAddress);
1445+
return -EINVAL;
1446+
}
1447+
14331448
/* If the HCD has already noted the endpoint is enabled,
14341449
* ignore this request.
14351450
*/
@@ -1445,8 +1460,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
14451460
* process context, not interrupt context (or so documenation
14461461
* for usb_set_interface() and usb_set_configuration() claim).
14471462
*/
1448-
if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id],
1449-
udev, ep, GFP_NOIO) < 0) {
1463+
if (xhci_endpoint_init(xhci, virt_dev, udev, ep, GFP_NOIO) < 0) {
14501464
dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
14511465
__func__, ep->desc.bEndpointAddress);
14521466
return -ENOMEM;

0 commit comments

Comments
 (0)