diff options
| author | Alexey Orishko <alexey.orishko@gmail.com> | 2012-03-14 07:26:12 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2012-03-16 05:08:36 -0400 |
| commit | d5ddb4a59ed43b4c569b4efa8b508d50ef140cc6 (patch) | |
| tree | c8fbd659c3bc62fe64f16408954e3fb66eac8a17 | |
| parent | 3f658cde9401bd45429ee720cf2c69f0bc5547b9 (diff) | |
cdc_ncm: avoid discarding datagrams in rx path
Changes:
- removed a limit for amount of datagrams for IN NTB
- using pointer to traverse NTB in rx_fixup()
- renamed "temp" to "len" in rx_fixup()
- do NTB sequence number check in rx path
Tested on Intel/ARM.
Reviewed-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
Tested-by: Dmitry Tarnyagin <Dmitry.Tarnyagin@stericsson.com>
Signed-off-by: Alexey Orishko <alexey.orishko@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/usb/cdc_ncm.c | 102 |
1 files changed, 47 insertions, 55 deletions
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index f8f194658412..7adc9f6b0ea1 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c | |||
| @@ -71,13 +71,10 @@ | |||
| 71 | 71 | ||
| 72 | /* | 72 | /* |
| 73 | * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting | 73 | * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting |
| 74 | * the last NULL entry. Any additional datagrams in NTB would be discarded. | 74 | * the last NULL entry. |
| 75 | */ | 75 | */ |
| 76 | #define CDC_NCM_DPT_DATAGRAMS_MAX 40 | 76 | #define CDC_NCM_DPT_DATAGRAMS_MAX 40 |
| 77 | 77 | ||
| 78 | /* Maximum amount of IN datagrams in NTB */ | ||
| 79 | #define CDC_NCM_DPT_DATAGRAMS_IN_MAX 0 /* unlimited */ | ||
| 80 | |||
| 81 | /* Restart the timer, if amount of datagrams is less than given value */ | 78 | /* Restart the timer, if amount of datagrams is less than given value */ |
| 82 | #define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3 | 79 | #define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3 |
| 83 | #define CDC_NCM_TIMER_PENDING_CNT 2 | 80 | #define CDC_NCM_TIMER_PENDING_CNT 2 |
| @@ -95,7 +92,6 @@ struct cdc_ncm_data { | |||
| 95 | }; | 92 | }; |
| 96 | 93 | ||
| 97 | struct cdc_ncm_ctx { | 94 | struct cdc_ncm_ctx { |
| 98 | struct cdc_ncm_data rx_ncm; | ||
| 99 | struct cdc_ncm_data tx_ncm; | 95 | struct cdc_ncm_data tx_ncm; |
| 100 | struct usb_cdc_ncm_ntb_parameters ncm_parm; | 96 | struct usb_cdc_ncm_ntb_parameters ncm_parm; |
| 101 | struct hrtimer tx_timer; | 97 | struct hrtimer tx_timer; |
| @@ -135,6 +131,7 @@ struct cdc_ncm_ctx { | |||
| 135 | u16 tx_modulus; | 131 | u16 tx_modulus; |
| 136 | u16 tx_ndp_modulus; | 132 | u16 tx_ndp_modulus; |
| 137 | u16 tx_seq; | 133 | u16 tx_seq; |
| 134 | u16 rx_seq; | ||
| 138 | u16 connected; | 135 | u16 connected; |
| 139 | }; | 136 | }; |
| 140 | 137 | ||
| @@ -956,108 +953,103 @@ error: | |||
| 956 | static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) | 953 | static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) |
| 957 | { | 954 | { |
| 958 | struct sk_buff *skb; | 955 | struct sk_buff *skb; |
| 959 | struct cdc_ncm_ctx *ctx; | 956 | struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; |
| 960 | int sumlen; | 957 | int len; |
| 961 | int actlen; | ||
| 962 | int temp; | ||
| 963 | int nframes; | 958 | int nframes; |
| 964 | int x; | 959 | int x; |
| 965 | int offset; | 960 | int offset; |
| 961 | struct usb_cdc_ncm_nth16 *nth16; | ||
| 962 | struct usb_cdc_ncm_ndp16 *ndp16; | ||
| 963 | struct usb_cdc_ncm_dpe16 *dpe16; | ||
| 966 | 964 | ||
| 967 | ctx = (struct cdc_ncm_ctx *)dev->data[0]; | ||
| 968 | if (ctx == NULL) | 965 | if (ctx == NULL) |
| 969 | goto error; | 966 | goto error; |
| 970 | 967 | ||
| 971 | actlen = skb_in->len; | 968 | if (skb_in->len < (sizeof(struct usb_cdc_ncm_nth16) + |
| 972 | sumlen = CDC_NCM_NTB_MAX_SIZE_RX; | 969 | sizeof(struct usb_cdc_ncm_ndp16))) { |
| 973 | |||
| 974 | if (actlen < (sizeof(ctx->rx_ncm.nth16) + sizeof(ctx->rx_ncm.ndp16))) { | ||
| 975 | pr_debug("frame too short\n"); | 970 | pr_debug("frame too short\n"); |
| 976 | goto error; | 971 | goto error; |
| 977 | } | 972 | } |
| 978 | 973 | ||
| 979 | memcpy(&(ctx->rx_ncm.nth16), ((u8 *)skb_in->data), | 974 | nth16 = (struct usb_cdc_ncm_nth16 *)skb_in->data; |
| 980 | sizeof(ctx->rx_ncm.nth16)); | ||
| 981 | 975 | ||
| 982 | if (le32_to_cpu(ctx->rx_ncm.nth16.dwSignature) != | 976 | if (le32_to_cpu(nth16->dwSignature) != USB_CDC_NCM_NTH16_SIGN) { |
| 983 | USB_CDC_NCM_NTH16_SIGN) { | ||
| 984 | pr_debug("invalid NTH16 signature <%u>\n", | 977 | pr_debug("invalid NTH16 signature <%u>\n", |
| 985 | le32_to_cpu(ctx->rx_ncm.nth16.dwSignature)); | 978 | le32_to_cpu(nth16->dwSignature)); |
| 986 | goto error; | 979 | goto error; |
| 987 | } | 980 | } |
| 988 | 981 | ||
| 989 | temp = le16_to_cpu(ctx->rx_ncm.nth16.wBlockLength); | 982 | len = le16_to_cpu(nth16->wBlockLength); |
| 990 | if (temp > sumlen) { | 983 | if (len > ctx->rx_max) { |
| 991 | pr_debug("unsupported NTB block length %u/%u\n", temp, sumlen); | 984 | pr_debug("unsupported NTB block length %u/%u\n", len, |
| 985 | ctx->rx_max); | ||
| 992 | goto error; | 986 | goto error; |
| 993 | } | 987 | } |
| 994 | 988 | ||
| 995 | temp = le16_to_cpu(ctx->rx_ncm.nth16.wNdpIndex); | 989 | if ((ctx->rx_seq + 1) != le16_to_cpu(nth16->wSequence) && |
| 996 | if ((temp + sizeof(ctx->rx_ncm.ndp16)) > actlen) { | 990 | (ctx->rx_seq || le16_to_cpu(nth16->wSequence)) && |
| 997 | pr_debug("invalid DPT16 index\n"); | 991 | !((ctx->rx_seq == 0xffff) && !le16_to_cpu(nth16->wSequence))) { |
| 992 | pr_debug("sequence number glitch prev=%d curr=%d\n", | ||
| 993 | ctx->rx_seq, le16_to_cpu(nth16->wSequence)); | ||
| 994 | } | ||
| 995 | ctx->rx_seq = le16_to_cpu(nth16->wSequence); | ||
| 996 | |||
| 997 | len = le16_to_cpu(nth16->wNdpIndex); | ||
| 998 | if ((len + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) { | ||
| 999 | pr_debug("invalid DPT16 index <%u>\n", | ||
| 1000 | le16_to_cpu(nth16->wNdpIndex)); | ||
| 998 | goto error; | 1001 | goto error; |
| 999 | } | 1002 | } |
| 1000 | 1003 | ||
| 1001 | memcpy(&(ctx->rx_ncm.ndp16), ((u8 *)skb_in->data) + temp, | 1004 | ndp16 = (struct usb_cdc_ncm_ndp16 *)(((u8 *)skb_in->data) + len); |
| 1002 | sizeof(ctx->rx_ncm.ndp16)); | ||
| 1003 | 1005 | ||
| 1004 | if (le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature) != | 1006 | if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) { |
| 1005 | USB_CDC_NCM_NDP16_NOCRC_SIGN) { | ||
| 1006 | pr_debug("invalid DPT16 signature <%u>\n", | 1007 | pr_debug("invalid DPT16 signature <%u>\n", |
| 1007 | le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature)); | 1008 | le32_to_cpu(ndp16->dwSignature)); |
| 1008 | goto error; | 1009 | goto error; |
| 1009 | } | 1010 | } |
| 1010 | 1011 | ||
| 1011 | if (le16_to_cpu(ctx->rx_ncm.ndp16.wLength) < | 1012 | if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) { |
| 1012 | USB_CDC_NCM_NDP16_LENGTH_MIN) { | ||
| 1013 | pr_debug("invalid DPT16 length <%u>\n", | 1013 | pr_debug("invalid DPT16 length <%u>\n", |
| 1014 | le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature)); | 1014 | le32_to_cpu(ndp16->dwSignature)); |
| 1015 | goto error; | 1015 | goto error; |
| 1016 | } | 1016 | } |
| 1017 | 1017 | ||
| 1018 | nframes = ((le16_to_cpu(ctx->rx_ncm.ndp16.wLength) - | 1018 | nframes = ((le16_to_cpu(ndp16->wLength) - |
| 1019 | sizeof(struct usb_cdc_ncm_ndp16)) / | 1019 | sizeof(struct usb_cdc_ncm_ndp16)) / |
| 1020 | sizeof(struct usb_cdc_ncm_dpe16)); | 1020 | sizeof(struct usb_cdc_ncm_dpe16)); |
| 1021 | nframes--; /* we process NDP entries except for the last one */ | 1021 | nframes--; /* we process NDP entries except for the last one */ |
| 1022 | 1022 | ||
| 1023 | pr_debug("nframes = %u\n", nframes); | 1023 | len += sizeof(struct usb_cdc_ncm_ndp16); |
| 1024 | 1024 | ||
| 1025 | temp += sizeof(ctx->rx_ncm.ndp16); | 1025 | if ((len + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > |
| 1026 | 1026 | skb_in->len) { | |
| 1027 | if ((temp + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > actlen) { | ||
| 1028 | pr_debug("Invalid nframes = %d\n", nframes); | 1027 | pr_debug("Invalid nframes = %d\n", nframes); |
| 1029 | goto error; | 1028 | goto error; |
| 1030 | } | 1029 | } |
| 1031 | 1030 | ||
| 1032 | if (nframes > CDC_NCM_DPT_DATAGRAMS_MAX) { | 1031 | dpe16 = (struct usb_cdc_ncm_dpe16 *)(((u8 *)skb_in->data) + len); |
| 1033 | pr_debug("Truncating number of frames from %u to %u\n", | ||
| 1034 | nframes, CDC_NCM_DPT_DATAGRAMS_MAX); | ||
| 1035 | nframes = CDC_NCM_DPT_DATAGRAMS_MAX; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | memcpy(&(ctx->rx_ncm.dpe16), ((u8 *)skb_in->data) + temp, | ||
| 1039 | nframes * (sizeof(struct usb_cdc_ncm_dpe16))); | ||
| 1040 | 1032 | ||
| 1041 | for (x = 0; x < nframes; x++) { | 1033 | for (x = 0; x < nframes; x++, dpe16++) { |
| 1042 | offset = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramIndex); | 1034 | offset = le16_to_cpu(dpe16->wDatagramIndex); |
| 1043 | temp = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramLength); | 1035 | len = le16_to_cpu(dpe16->wDatagramLength); |
| 1044 | 1036 | ||
| 1045 | /* | 1037 | /* |
| 1046 | * CDC NCM ch. 3.7 | 1038 | * CDC NCM ch. 3.7 |
| 1047 | * All entries after first NULL entry are to be ignored | 1039 | |
