Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/usb/usbip/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 5 kB image not shown  

Quelle  vudc_rx.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
 * Copyright (C) 2015-2016 Samsung Electronics
 *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
 */


#include <net/sock.h>
#include <linux/list.h>
#include <linux/kthread.h>

#include "usbip_common.h"
#include "vudc.h"

static int alloc_urb_from_cmd(struct urb **urbp,
         struct usbip_header *pdu, u8 type)
{
 struct urb *urb;

 if (type == USB_ENDPOINT_XFER_ISOC)
  urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets,
       GFP_KERNEL);
 else
  urb = usb_alloc_urb(0, GFP_KERNEL);

 if (!urb)
  goto err;

 usbip_pack_pdu(pdu, urb, USBIP_CMD_SUBMIT, 0);

 if (urb->transfer_buffer_length > 0) {
  urb->transfer_buffer = kzalloc(urb->transfer_buffer_length,
   GFP_KERNEL);
  if (!urb->transfer_buffer)
   goto free_urb;
 }

 urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8,
       GFP_KERNEL);
 if (!urb->setup_packet)
  goto free_buffer;

 /*
 * FIXME - we only setup pipe enough for usbip functions
 * to behave nicely
 */

 urb->pipe |= pdu->base.direction == USBIP_DIR_IN ?
   USB_DIR_IN : USB_DIR_OUT;

 *urbp = urb;
 return 0;

free_buffer:
 kfree(urb->transfer_buffer);
 urb->transfer_buffer = NULL;
free_urb:
 usb_free_urb(urb);
err:
 return -ENOMEM;
}

static int v_recv_cmd_unlink(struct vudc *udc,
    struct usbip_header *pdu)
{
 unsigned long flags;
 struct urbp *urb_p;

 spin_lock_irqsave(&udc->lock, flags);
 list_for_each_entry(urb_p, &udc->urb_queue, urb_entry) {
  if (urb_p->seqnum != pdu->u.cmd_unlink.seqnum)
   continue;
  urb_p->urb->unlinked = -ECONNRESET;
  urb_p->seqnum = pdu->base.seqnum;
  v_kick_timer(udc, jiffies);
  spin_unlock_irqrestore(&udc->lock, flags);
  return 0;
 }
 /* Not found, completed / not queued */
 spin_lock(&udc->lock_tx);
 v_enqueue_ret_unlink(udc, pdu->base.seqnum, 0);
 wake_up(&udc->tx_waitq);
 spin_unlock(&udc->lock_tx);
 spin_unlock_irqrestore(&udc->lock, flags);

 return 0;
}

static int v_recv_cmd_submit(struct vudc *udc,
     struct usbip_header *pdu)
{
 int ret = 0;
 struct urbp *urb_p;
 u8 address;
 unsigned long flags;

 urb_p = alloc_urbp();
 if (!urb_p) {
  usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC);
  return -ENOMEM;
 }

 /* base.ep is pipeendpoint(pipe) */
 address = pdu->base.ep;
 if (pdu->base.direction == USBIP_DIR_IN)
  address |= USB_DIR_IN;

 spin_lock_irqsave(&udc->lock, flags);
 urb_p->ep = vudc_find_endpoint(udc, address);
 if (!urb_p->ep) {
  /* we don't know the type, there may be isoc data! */
  dev_err(&udc->pdev->dev, "request to nonexistent endpoint");
  spin_unlock_irqrestore(&udc->lock, flags);
  usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP);
  ret = -EPIPE;
  goto free_urbp;
 }
 urb_p->type = urb_p->ep->type;
 spin_unlock_irqrestore(&udc->lock, flags);

 urb_p->new = 1;
 urb_p->seqnum = pdu->base.seqnum;

 if (urb_p->ep->type == USB_ENDPOINT_XFER_ISOC) {
  /* validate packet size and number of packets */
  unsigned int maxp, packets, bytes;

  maxp = usb_endpoint_maxp(urb_p->ep->desc);
  maxp *= usb_endpoint_maxp_mult(urb_p->ep->desc);
  bytes = pdu->u.cmd_submit.transfer_buffer_length;
  packets = DIV_ROUND_UP(bytes, maxp);

  if (pdu->u.cmd_submit.number_of_packets < 0 ||
      pdu->u.cmd_submit.number_of_packets > packets) {
   dev_err(&udc->gadget.dev,
    "CMD_SUBMIT: isoc invalid num packets %d\n",
    pdu->u.cmd_submit.number_of_packets);
   ret = -EMSGSIZE;
   goto free_urbp;
  }
 }

 ret = alloc_urb_from_cmd(&urb_p->urb, pdu, urb_p->ep->type);
 if (ret) {
  usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC);
  ret = -ENOMEM;
  goto free_urbp;
 }

 urb_p->urb->status = -EINPROGRESS;

 /* FIXME: more pipe setup to please usbip_common */
 BUILD_BUG_ON_MSG(PIPE_BULK != 3, "PIPE_* doesn't range from 0 to 3");

 urb_p->urb->pipe &= ~(PIPE_BULK << 30);
 switch (urb_p->ep->type) {
 case USB_ENDPOINT_XFER_BULK:
  urb_p->urb->pipe |= (PIPE_BULK << 30);
  break;
 case USB_ENDPOINT_XFER_INT:
  urb_p->urb->pipe |= (PIPE_INTERRUPT << 30);
  break;
 case USB_ENDPOINT_XFER_CONTROL:
  urb_p->urb->pipe |= (PIPE_CONTROL << 30);
  break;
 case USB_ENDPOINT_XFER_ISOC:
  urb_p->urb->pipe |= (PIPE_ISOCHRONOUS << 30);
  break;
 }
 ret = usbip_recv_xbuff(&udc->ud, urb_p->urb);
 if (ret < 0)
  goto free_urbp;

 ret = usbip_recv_iso(&udc->ud, urb_p->urb);
 if (ret < 0)
  goto free_urbp;

 spin_lock_irqsave(&udc->lock, flags);
 v_kick_timer(udc, jiffies);
 list_add_tail(&urb_p->urb_entry, &udc->urb_queue);
 spin_unlock_irqrestore(&udc->lock, flags);

 return 0;

free_urbp:
 free_urbp_and_urb(urb_p);
 return ret;
}

static int v_rx_pdu(struct usbip_device *ud)
{
 int ret;
 struct usbip_header pdu;
 struct vudc *udc = container_of(ud, struct vudc, ud);

 memset(&pdu, 0, sizeof(pdu));
 ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
 if (ret != sizeof(pdu)) {
  usbip_event_add(ud, VUDC_EVENT_ERROR_TCP);
  if (ret >= 0)
   return -EPIPE;
  return ret;
 }
 usbip_header_correct_endian(&pdu, 0);

 spin_lock_irq(&ud->lock);
 ret = (ud->status == SDEV_ST_USED);
 spin_unlock_irq(&ud->lock);
 if (!ret) {
  usbip_event_add(ud, VUDC_EVENT_ERROR_TCP);
  return -EBUSY;
 }

 switch (pdu.base.command) {
 case USBIP_CMD_UNLINK:
  ret = v_recv_cmd_unlink(udc, &pdu);
  break;
 case USBIP_CMD_SUBMIT:
  ret = v_recv_cmd_submit(udc, &pdu);
  break;
 default:
  ret = -EPIPE;
  pr_err("rx: unknown command");
  break;
 }
 return ret;
}

int v_rx_loop(void *data)
{
 struct usbip_device *ud = data;
 int ret = 0;

 while (!kthread_should_stop()) {
  if (usbip_event_happened(ud))
   break;
  ret = v_rx_pdu(ud);
  if (ret < 0) {
   pr_warn("v_rx exit with error %d", ret);
   break;
  }
 }
 return ret;
}

Messung V0.5
C=97 H=92 G=94

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.