aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Baxter <jim_baxter@mentor.com>2014-07-07 13:33:17 -0400
committerFelipe Balbi <balbi@ti.com>2014-07-10 09:49:35 -0400
commit370af734dfaf8336b496b386e194648e097e248a (patch)
treeac8ec25e4fae41ddc9c06ce33bd4afde35c74ed0
parentd82aa8aeb0eaa06bad80860a95ca5fdff84e8775 (diff)
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: Jim Baxter <jim_baxter@mentor.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/gadget/f_ncm.c146
1 files changed, 78 insertions, 68 deletions
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index a9499fd30792..d0ebbac8845f 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -963,6 +963,7 @@ static int ncm_unwrap_ntb(struct gether *port,
963 struct f_ncm *ncm = func_to_ncm(&port->func); 963 struct f_ncm *ncm = func_to_ncm(&port->func);
964 __le16 *tmp = (void *) skb->data; 964 __le16 *tmp = (void *) skb->data;
965 unsigned index, index2; 965 unsigned index, index2;
966 int ndp_index;
966 unsigned dg_len, dg_len2; 967 unsigned dg_len, dg_len2;
967 unsigned ndp_len; 968 unsigned ndp_len;
968 struct sk_buff *skb2; 969 struct sk_buff *skb2;
@@ -995,91 +996,100 @@ static int ncm_unwrap_ntb(struct gether *port,
995 goto err; 996 goto err;
996 } 997 }
997 998
998 index = get_ncm(&tmp, opts->fp_index); 999 ndp_index = get_ncm(&tmp, opts->fp_index);
999 /* NCM 3.2 */
1000 if (((index % 4) != 0) && (index < opts->nth_size)) {
1001 INFO(port->func.config->cdev, "Bad index: %x\n",
1002 index);
1003 goto err;
1004 }
1005
1006 /* walk through NDP */
1007 tmp = ((void *)skb->data) + index;
1008 if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
1009 INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
1010 goto err;
1011 }
1012 tmp += 2;
1013
1014 ndp_len = get_unaligned_le16(tmp++);
1015 /*
1016 * NCM 3.3.1
1017 * entry is 2 items
1018 * item size is 16/32 bits, opts->dgram_item_len * 2 bytes
1019 * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry
1020 */
1021 if ((ndp_len < opts->ndp_size + 2 * 2 * (opts->dgram_item_len * 2))
1022 || (ndp_len % opts->ndplen_align != 0)) {
1023 INFO(port->func.config->cdev, "Bad NDP length: %x\n", ndp_len);
1024 goto err;
1025 }
1026 tmp += opts->reserved1;
1027 tmp += opts->next_fp_index; /* skip reserved (d)wNextFpIndex */
1028 tmp += opts->reserved2;
1029
1030 ndp_len -= opts->ndp_size;
1031 index2 = get_ncm(&tmp, opts->dgram_item_len);
1032 dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
1033 dgram_counter = 0;
1034 1000
1001 /* Run through all the NDP's in the NTB */
1035 do { 1002 do {
1036 index = index2; 1003 /* NCM 3.2 */
1037 dg_len = dg_len2; 1004 if (((ndp_index % 4) != 0) &&
1038 if (dg_len < 14 + crc_len) { /* ethernet header + crc */ 1005 (ndp_index < opts->nth_size)) {
1039 INFO(port->func.config->cdev, "Bad dgram length: %x\n", 1006 INFO(port->func.config->cdev, "Bad index: %#X\n",
1040 dg_len); 1007 ndp_index);
1041 goto err; 1008 goto err;
1042 } 1009 }
1043 if (ncm->is_crc) { 1010
1044 uint32_t crc, crc2; 1011 /* walk through NDP */
1045 1012 tmp = (void *)(skb->data + ndp_index);
1046 crc = get_unaligned_le32(skb->data + 1013 if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
1047 index + dg_len - crc_len); 1014 INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
1048 crc2 = ~crc32_le(~0, 1015 goto err;
1049 skb->data + index,
1050 dg_len - crc_len);
1051 if (crc != crc2) {
1052 INFO(port->func.config->cdev, "Bad CRC\n");
1053 goto err;
1054 }
1055 } 1016 }
1017 tmp += 2;
1056 1018
1019 ndp_len = get_unaligned_le16(tmp++);
1020 /*
1021 * NCM 3.3.1
1022 * entry is 2 items
1023 * item size is 16/32 bits, opts->dgram_item_len * 2 bytes
1024 * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry
1025 * Each entry is a dgram index and a dgram length.
1026 */
1027 if ((ndp_len < opts->ndp_size
1028 + 2 * 2 * (opts->dgram_item_len * 2))
1029 || (ndp_len % opts->ndplen_align != 0)) {
1030 INFO(port->func.config->cdev, "Bad NDP length: %#X\n",
1031 ndp_len);
1032 goto err;
1033 }
1034 tmp += opts->reserved1;
1035 /* Check for another NDP (d)wNextNdpIndex */
1036 ndp_index = get_ncm(&tmp, opts->next_fp_index);
1037 tmp += opts->reserved2;
1038
1039 ndp_len -= opts->ndp_size;
1057 index2 = get_ncm(&tmp, opts->dgram_item_len); 1040 index2 = get_ncm(&tmp, opts->dgram_item_len);
1058 dg_len2 = get_ncm(&tmp, opts->dgram_item_len); 1041 dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
1042 dgram_counter = 0;
1043
1044 do {
1045 index = index2;
1046 dg_len = dg_len2;
1047 if (dg_len < 14 + crc_len) { /* ethernet hdr + crc */
1048 INFO(port->func.config->cdev,
1049 "Bad dgram length: %#X\n", dg_len);
1050 goto err;
1051 }
1052 if (ncm->is_crc) {
1053 uint32_t crc, crc2;
1054
1055 crc = get_unaligned_le32(skb->data +
1056 index + dg_len -
1057 crc_len);
1058 crc2 = ~crc32_le(~0,
1059 skb->data + index,
1060 dg_len - crc_len);
1061 if (crc != crc2) {
1062 INFO(port->func.config->cdev,
1063 "Bad CRC\n");
1064 goto err;
1065 }
1066 }
1067
1068 index2 = get_ncm(&tmp, opts->dgram_item_len);
1069 dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
1059 1070
1060 if (index2 == 0 || dg_len2 == 0) {
1061 skb2 = skb;
1062 } else {
1063 skb2 = skb_clone(skb, GFP_ATOMIC); 1071 skb2 = skb_clone(skb, GFP_ATOMIC);
1064 if (skb2 == NULL) 1072 if (skb2 == NULL)
1065 goto err; 1073 goto err;
1066 }
1067 1074
1068 if (!skb_pull(skb2, index)) { 1075 if (!skb_pull(skb2, index)) {
1069 ret = -EOVERFLOW; 1076 ret = -EOVERFLOW;
1070 goto err; 1077 goto err;
1071 } 1078 }
1072 1079
1073 skb_trim(skb2, dg_len - crc_len); 1080 skb_trim(skb2, dg_len - crc_len);
1074 skb_queue_tail(list, skb2); 1081 skb_queue_tail(list, skb2);
1075 1082
1076 ndp_len -= 2 * (opts->dgram_item_len * 2); 1083 ndp_len -= 2 * (opts->dgram_item_len * 2);
1077 1084
1078 dgram_counter++; 1085 dgram_counter++;
1079 1086
1080 if (index2 == 0 || dg_len2 == 0) 1087 if (index2 == 0 || dg_len2 == 0)
1081 break; 1088 break;
1082 } while (ndp_len > 2 * (opts->dgram_item_len * 2)); /* zero entry */ 1089 } while (ndp_len > 2 * (opts->dgram_item_len * 2));
1090 } while (ndp_index);
1091
1092 dev_kfree_skb_any(skb);
1083 1093
1084 VDBG(port->func.config->cdev, 1094 VDBG(port->func.config->cdev,
1085 "Parsed NTB with %d frames\n", dgram_counter); 1095 "Parsed NTB with %d frames\n", dgram_counter);