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

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
......@@ -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,91 +996,100 @@ static int ncm_unwrap_ntb(struct gether *port,
goto err;
}
index = get_ncm(&tmp, opts->fp_index);
/* NCM 3.2 */
if (((index % 4) != 0) && (index < opts->nth_size)) {
INFO(port->func.config->cdev, "Bad index: %x\n",
index);
goto err;
}
/* walk through NDP */
tmp = ((void *)skb->data) + index;
if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
goto err;
}
tmp += 2;
ndp_len = get_unaligned_le16(tmp++);
/*
* NCM 3.3.1
* 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
*/
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);
goto err;
}
tmp += opts->reserved1;
tmp += opts->next_fp_index; /* skip reserved (d)wNextFpIndex */
tmp += opts->reserved2;
ndp_len -= opts->ndp_size;
index2 = get_ncm(&tmp, opts->dgram_item_len);
dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
dgram_counter = 0;
ndp_index = get_ncm(&tmp, opts->fp_index);
/* Run through all the NDP's in the NTB */
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);
/* NCM 3.2 */
if (((ndp_index % 4) != 0) &&
(ndp_index < opts->nth_size)) {
INFO(port->func.config->cdev, "Bad index: %#X\n",
ndp_index);
goto err;
}
if (ncm->is_crc) {
uint32_t crc, crc2;
crc = get_unaligned_le32(skb->data +
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");
goto err;
}
/* walk through NDP */
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;
}
tmp += 2;
ndp_len = get_unaligned_le16(tmp++);
/*
* NCM 3.3.1
* 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))
|| (ndp_len % opts->ndplen_align != 0)) {
INFO(port->func.config->cdev, "Bad NDP length: %#X\n",
ndp_len);
goto err;
}
tmp += opts->reserved1;
/* Check for another NDP (d)wNextNdpIndex */
ndp_index = get_ncm(&tmp, opts->next_fp_index);
tmp += opts->reserved2;
ndp_len -= opts->ndp_size;
index2 = get_ncm(&tmp, opts->dgram_item_len);
dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
dgram_counter = 0;
do {
index = index2;
dg_len = dg_len2;
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);
crc2 = ~crc32_le(~0,
skb->data + index,
dg_len - crc_len);
if (crc != crc2) {
INFO(port->func.config->cdev,
"Bad CRC\n");
goto err;
}
}
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;
goto err;
}
if (!skb_pull(skb2, index)) {
ret = -EOVERFLOW;
goto err;
}
skb_trim(skb2, dg_len - crc_len);
skb_queue_tail(list, skb2);
skb_trim(skb2, dg_len - crc_len);
skb_queue_tail(list, skb2);
ndp_len -= 2 * (opts->dgram_item_len * 2);
ndp_len -= 2 * (opts->dgram_item_len * 2);
dgram_counter++;
dgram_counter++;
if (index2 == 0 || dg_len2 == 0)
break;
} while (ndp_len > 2 * (opts->dgram_item_len * 2)); /* zero entry */
if (index2 == 0 || dg_len2 == 0)
break;
} 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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment