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

Commit 370af734 authored by Jim Baxter's avatar Jim Baxter Committed by Felipe Balbi
Browse files

usb: gadget: NCM: RX function support multiple NDPs



The NDP was ignoring the wNextNdpIndex in the NDP which
means that NTBs containing multiple NDPs would have missed
frames.

Signed-off-by: default avatarJim Baxter <jim_baxter@mentor.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent d82aa8ae
Loading
Loading
Loading
Loading
+78 −68
Original line number Diff line number Diff line
@@ -963,6 +963,7 @@ static int ncm_unwrap_ntb(struct gether *port,
	struct f_ncm	*ncm = func_to_ncm(&port->func);
	__le16		*tmp = (void *) skb->data;
	unsigned	index, index2;
	int		ndp_index;
	unsigned	dg_len, dg_len2;
	unsigned	ndp_len;
	struct sk_buff	*skb2;
@@ -995,16 +996,20 @@ static int ncm_unwrap_ntb(struct gether *port,
		goto err;
	}

	index = get_ncm(&tmp, opts->fp_index);
	ndp_index = get_ncm(&tmp, opts->fp_index);

	/* Run through all the NDP's in the NTB */
	do {
		/* NCM 3.2 */
	if (((index % 4) != 0) && (index < opts->nth_size)) {
		INFO(port->func.config->cdev, "Bad index: %x\n",
			index);
		if (((ndp_index % 4) != 0) &&
				(ndp_index < opts->nth_size)) {
			INFO(port->func.config->cdev, "Bad index: %#X\n",
			     ndp_index);
			goto err;
		}

		/* walk through NDP */
	tmp = ((void *)skb->data) + index;
		tmp = (void *)(skb->data + ndp_index);
		if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
			INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
			goto err;
@@ -1017,14 +1022,18 @@ static int ncm_unwrap_ntb(struct gether *port,
		 * entry is 2 items
		 * item size is 16/32 bits, opts->dgram_item_len * 2 bytes
		 * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry
		 * Each entry is a dgram index and a dgram length.
		 */
	if ((ndp_len < opts->ndp_size + 2 * 2 * (opts->dgram_item_len * 2))
		if ((ndp_len < opts->ndp_size
				+ 2 * 2 * (opts->dgram_item_len * 2))
				|| (ndp_len % opts->ndplen_align != 0)) {
		INFO(port->func.config->cdev, "Bad NDP length: %x\n", ndp_len);
			INFO(port->func.config->cdev, "Bad NDP length: %#X\n",
			     ndp_len);
			goto err;
		}
		tmp += opts->reserved1;
	tmp += opts->next_fp_index; /* skip reserved (d)wNextFpIndex */
		/* Check for another NDP (d)wNextNdpIndex */
		ndp_index = get_ncm(&tmp, opts->next_fp_index);
		tmp += opts->reserved2;

		ndp_len -= opts->ndp_size;
@@ -1035,21 +1044,23 @@ static int ncm_unwrap_ntb(struct gether *port,
		do {
			index = index2;
			dg_len = dg_len2;
		if (dg_len < 14 + crc_len) { /* ethernet header + crc */
			INFO(port->func.config->cdev, "Bad dgram length: %x\n",
			     dg_len);
			if (dg_len < 14 + crc_len) { /* ethernet hdr + crc */
				INFO(port->func.config->cdev,
				     "Bad dgram length: %#X\n", dg_len);
				goto err;
			}
			if (ncm->is_crc) {
				uint32_t crc, crc2;

				crc = get_unaligned_le32(skb->data +
						 index + dg_len - crc_len);
							 index + dg_len -
							 crc_len);
				crc2 = ~crc32_le(~0,
						 skb->data + index,
						 dg_len - crc_len);
				if (crc != crc2) {
				INFO(port->func.config->cdev, "Bad CRC\n");
					INFO(port->func.config->cdev,
					     "Bad CRC\n");
					goto err;
				}
			}
@@ -1057,13 +1068,9 @@ static int ncm_unwrap_ntb(struct gether *port,
			index2 = get_ncm(&tmp, opts->dgram_item_len);
			dg_len2 = get_ncm(&tmp, opts->dgram_item_len);

		if (index2 == 0 || dg_len2 == 0) {
			skb2 = skb;
		} else {
			skb2 = skb_clone(skb, GFP_ATOMIC);
			if (skb2 == NULL)
				goto err;
		}

			if (!skb_pull(skb2, index)) {
				ret = -EOVERFLOW;
@@ -1079,7 +1086,10 @@ static int ncm_unwrap_ntb(struct gether *port,

			if (index2 == 0 || dg_len2 == 0)
				break;
	} while (ndp_len > 2 * (opts->dgram_item_len * 2)); /* zero entry */
		} while (ndp_len > 2 * (opts->dgram_item_len * 2));
	} while (ndp_index);

	dev_kfree_skb_any(skb);

	VDBG(port->func.config->cdev,
	     "Parsed NTB with %d frames\n", dgram_counter);