Skip to content

Commit 75d67d3

Browse files
bmorkdavem330
authored andcommitted
net: cdc_ncm: process chained NDPs
The NCM 1.0 spefication makes provisions for linking more than one NDP into a single NTB. This is important for MBIM support, where these NDPs might be of different types. Following the chain of NDPs is also correct for NCM, and will not change anything in the common case where there is only one NDP Signed-off-by: Bjørn Mork <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 38396e4 commit 75d67d3

File tree

1 file changed

+21
-14
lines changed

1 file changed

+21
-14
lines changed

drivers/net/usb/cdc_ncm.c

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,8 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
977977
struct usb_cdc_ncm_nth16 *nth16;
978978
struct usb_cdc_ncm_ndp16 *ndp16;
979979
struct usb_cdc_ncm_dpe16 *dpe16;
980+
int ndpoffset;
981+
int loopcount = 50; /* arbitrary max preventing infinite loop */
980982

981983
if (ctx == NULL)
982984
goto error;
@@ -1010,41 +1012,40 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
10101012
}
10111013
ctx->rx_seq = le16_to_cpu(nth16->wSequence);
10121014

1013-
len = le16_to_cpu(nth16->wNdpIndex);
1014-
if ((len + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
1015-
pr_debug("invalid DPT16 index <%u>\n",
1016-
le16_to_cpu(nth16->wNdpIndex));
1015+
ndpoffset = le16_to_cpu(nth16->wNdpIndex);
1016+
next_ndp:
1017+
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
1018+
pr_debug("invalid NDP offset <%u>\n", ndpoffset);
10171019
goto error;
10181020
}
1019-
1020-
ndp16 = (struct usb_cdc_ncm_ndp16 *)(((u8 *)skb_in->data) + len);
1021+
ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
10211022

10221023
if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) {
10231024
pr_debug("invalid DPT16 signature <%u>\n",
10241025
le32_to_cpu(ndp16->dwSignature));
1025-
goto error;
1026+
goto err_ndp;
10261027
}
10271028

10281029
if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) {
10291030
pr_debug("invalid DPT16 length <%u>\n",
10301031
le32_to_cpu(ndp16->dwSignature));
1031-
goto error;
1032+
goto err_ndp;
10321033
}
10331034

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

1039-
len += sizeof(struct usb_cdc_ncm_ndp16);
1040+
ndpoffset += sizeof(struct usb_cdc_ncm_ndp16);
10401041

1041-
if ((len + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) >
1042+
if ((ndpoffset + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) >
10421043
skb_in->len) {
10431044
pr_debug("Invalid nframes = %d\n", nframes);
1044-
goto error;
1045+
goto err_ndp;
10451046
}
10461047

1047-
dpe16 = (struct usb_cdc_ncm_dpe16 *)(((u8 *)skb_in->data) + len);
1048+
dpe16 = (struct usb_cdc_ncm_dpe16 *)(skb_in->data + ndpoffset);
10481049

10491050
for (x = 0; x < nframes; x++, dpe16++) {
10501051
offset = le16_to_cpu(dpe16->wDatagramIndex);
@@ -1056,7 +1057,7 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
10561057
*/
10571058
if ((offset == 0) || (len == 0)) {
10581059
if (!x)
1059-
goto error; /* empty NTB */
1060+
goto err_ndp; /* empty NTB */
10601061
break;
10611062
}
10621063

@@ -1067,7 +1068,7 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
10671068
"offset[%u]=%u, length=%u, skb=%p\n",
10681069
x, offset, len, skb_in);
10691070
if (!x)
1070-
goto error;
1071+
goto err_ndp;
10711072
break;
10721073

10731074
} else {
@@ -1080,6 +1081,12 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
10801081
usbnet_skb_return(dev, skb);
10811082
}
10821083
}
1084+
err_ndp:
1085+
/* are there more NDPs to process? */
1086+
ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex);
1087+
if (ndpoffset && loopcount--)
1088+
goto next_ndp;
1089+
10831090
return 1;
10841091
error:
10851092
return 0;

0 commit comments

Comments
 (0)