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

Commit ff06ab13 authored by Bjørn Mork's avatar Bjørn Mork Committed by David S. Miller
Browse files

net: cdc_ncm: splitting rx_fixup for code reuse



Verifying and handling received MBIM and NCM frames will need
to be different in three areas:
 - verifying the NDP signature
 - checking valid datagram length
 - datagram header manipulation

This makes it inconvenient to share rx_fixup in whole.  But
some verification parts are common.  Split these out in separate
functions.

Signed-off-by: default avatarBjørn Mork <bjorn@mork.no>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 75d67d35
Loading
Loading
Loading
Loading
+55 −28
Original line number Diff line number Diff line
@@ -966,19 +966,12 @@ error:
	return NULL;
}

static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
/* verify NTB header and return offset of first NDP, or negative error */
static int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in)
{
	struct sk_buff *skb;
	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
	int len;
	int nframes;
	int x;
	int offset;
	struct usb_cdc_ncm_nth16 *nth16;
	struct usb_cdc_ncm_ndp16 *ndp16;
	struct usb_cdc_ncm_dpe16 *dpe16;
	int ndpoffset;
	int loopcount = 50; /* arbitrary max preventing infinite loop */
	int len;
	int ret = -EINVAL;

	if (ctx == NULL)
		goto error;
@@ -1012,40 +1005,74 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
	}
	ctx->rx_seq = le16_to_cpu(nth16->wSequence);

	ndpoffset = le16_to_cpu(nth16->wNdpIndex);
next_ndp:
	ret = le16_to_cpu(nth16->wNdpIndex);
error:
	return ret;
}

/* verify NDP header and return number of datagrams, or negative error */
static int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
{
	struct usb_cdc_ncm_ndp16 *ndp16;
	int ret = -EINVAL;

	if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
		pr_debug("invalid NDP offset  <%u>\n", ndpoffset);
		goto error;
	}
	ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);

	if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) {
		pr_debug("invalid DPT16 signature <%u>\n",
					le32_to_cpu(ndp16->dwSignature));
		goto err_ndp;
	}

	if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) {
		pr_debug("invalid DPT16 length <%u>\n",
					le32_to_cpu(ndp16->dwSignature));
		goto err_ndp;
		goto error;
	}

	nframes = ((le16_to_cpu(ndp16->wLength) -
	ret = ((le16_to_cpu(ndp16->wLength) -
					sizeof(struct usb_cdc_ncm_ndp16)) /
					sizeof(struct usb_cdc_ncm_dpe16));
	nframes--; /* we process NDP entries except for the last one */

	ndpoffset += sizeof(struct usb_cdc_ncm_ndp16);
	ret--; /* we process NDP entries except for the last one */

	if ((ndpoffset + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) >
	if ((sizeof(struct usb_cdc_ncm_ndp16) + ret * (sizeof(struct usb_cdc_ncm_dpe16))) >
								skb_in->len) {
		pr_debug("Invalid nframes = %d\n", nframes);
		goto err_ndp;
		pr_debug("Invalid nframes = %d\n", ret);
		ret = -EINVAL;
	}

	dpe16 = (struct usb_cdc_ncm_dpe16 *)(skb_in->data + ndpoffset);
error:
	return ret;
}

static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
{
	struct sk_buff *skb;
	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
	int len;
	int nframes;
	int x;
	int offset;
	struct usb_cdc_ncm_ndp16 *ndp16;
	struct usb_cdc_ncm_dpe16 *dpe16;
	int ndpoffset;
	int loopcount = 50; /* arbitrary max preventing infinite loop */

	ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
	if (ndpoffset < 0)
		goto error;

next_ndp:
	nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset);
	if (nframes < 0)
		goto error;

	ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);

	if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) {
		pr_debug("invalid DPT16 signature <%u>\n",
			 le32_to_cpu(ndp16->dwSignature));
		goto err_ndp;
	}
	dpe16 = ndp16->dpe16;

	for (x = 0; x < nframes; x++, dpe16++) {
		offset = le16_to_cpu(dpe16->wDatagramIndex);