diff options
Diffstat (limited to 'drivers/net/usb/cdc_ncm.c')
-rw-r--r-- | drivers/net/usb/cdc_ncm.c | 236 |
1 files changed, 115 insertions, 121 deletions
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 3a539a9cac54..7adc9f6b0ea1 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * cdc_ncm.c | 2 | * cdc_ncm.c |
3 | * | 3 | * |
4 | * Copyright (C) ST-Ericsson 2010-2011 | 4 | * Copyright (C) ST-Ericsson 2010-2012 |
5 | * Contact: Alexey Orishko <alexey.orishko@stericsson.com> | 5 | * Contact: Alexey Orishko <alexey.orishko@stericsson.com> |
6 | * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com> | 6 | * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com> |
7 | * | 7 | * |
@@ -47,20 +47,19 @@ | |||
47 | #include <linux/mii.h> | 47 | #include <linux/mii.h> |
48 | #include <linux/crc32.h> | 48 | #include <linux/crc32.h> |
49 | #include <linux/usb.h> | 49 | #include <linux/usb.h> |
50 | #include <linux/timer.h> | 50 | #include <linux/hrtimer.h> |
51 | #include <linux/spinlock.h> | ||
52 | #include <linux/atomic.h> | 51 | #include <linux/atomic.h> |
53 | #include <linux/usb/usbnet.h> | 52 | #include <linux/usb/usbnet.h> |
54 | #include <linux/usb/cdc.h> | 53 | #include <linux/usb/cdc.h> |
55 | 54 | ||
56 | #define DRIVER_VERSION "04-Aug-2011" | 55 | #define DRIVER_VERSION "14-Mar-2012" |
57 | 56 | ||
58 | /* CDC NCM subclass 3.2.1 */ | 57 | /* CDC NCM subclass 3.2.1 */ |
59 | #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 | 58 | #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 |
60 | 59 | ||
61 | /* Maximum NTB length */ | 60 | /* Maximum NTB length */ |
62 | #define CDC_NCM_NTB_MAX_SIZE_TX 16384 /* bytes */ | 61 | #define CDC_NCM_NTB_MAX_SIZE_TX 32768 /* bytes */ |
63 | #define CDC_NCM_NTB_MAX_SIZE_RX 16384 /* bytes */ | 62 | #define CDC_NCM_NTB_MAX_SIZE_RX 32768 /* bytes */ |
64 | 63 | ||
65 | /* Minimum value for MaxDatagramSize, ch. 6.2.9 */ | 64 | /* Minimum value for MaxDatagramSize, ch. 6.2.9 */ |
66 | #define CDC_NCM_MIN_DATAGRAM_SIZE 1514 /* bytes */ | 65 | #define CDC_NCM_MIN_DATAGRAM_SIZE 1514 /* bytes */ |
@@ -68,19 +67,18 @@ | |||
68 | #define CDC_NCM_MIN_TX_PKT 512 /* bytes */ | 67 | #define CDC_NCM_MIN_TX_PKT 512 /* bytes */ |
69 | 68 | ||
70 | /* Default value for MaxDatagramSize */ | 69 | /* Default value for MaxDatagramSize */ |
71 | #define CDC_NCM_MAX_DATAGRAM_SIZE 2048 /* bytes */ | 70 | #define CDC_NCM_MAX_DATAGRAM_SIZE 8192 /* bytes */ |
72 | 71 | ||
73 | /* | 72 | /* |
74 | * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting | 73 | * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting |
75 | * the last NULL entry. Any additional datagrams in NTB would be discarded. | 74 | * the last NULL entry. |
76 | */ | 75 | */ |
77 | #define CDC_NCM_DPT_DATAGRAMS_MAX 32 | 76 | #define CDC_NCM_DPT_DATAGRAMS_MAX 40 |
78 | |||
79 | /* Maximum amount of IN datagrams in NTB */ | ||
80 | #define CDC_NCM_DPT_DATAGRAMS_IN_MAX 0 /* unlimited */ | ||
81 | 77 | ||
82 | /* 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 */ |
83 | #define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3 | 79 | #define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3 |
80 | #define CDC_NCM_TIMER_PENDING_CNT 2 | ||
81 | #define CDC_NCM_TIMER_INTERVAL (400UL * NSEC_PER_USEC) | ||
84 | 82 | ||
85 | /* The following macro defines the minimum header space */ | 83 | /* The following macro defines the minimum header space */ |
86 | #define CDC_NCM_MIN_HDR_SIZE \ | 84 | #define CDC_NCM_MIN_HDR_SIZE \ |
@@ -94,10 +92,10 @@ struct cdc_ncm_data { | |||
94 | }; | 92 | }; |
95 | 93 | ||
96 | struct cdc_ncm_ctx { | 94 | struct cdc_ncm_ctx { |
97 | struct cdc_ncm_data rx_ncm; | ||
98 | struct cdc_ncm_data tx_ncm; | 95 | struct cdc_ncm_data tx_ncm; |
99 | struct usb_cdc_ncm_ntb_parameters ncm_parm; | 96 | struct usb_cdc_ncm_ntb_parameters ncm_parm; |
100 | struct timer_list tx_timer; | 97 | struct hrtimer tx_timer; |
98 | struct tasklet_struct bh; | ||
101 | 99 | ||
102 | const struct usb_cdc_ncm_desc *func_desc; | 100 | const struct usb_cdc_ncm_desc *func_desc; |
103 | const struct usb_cdc_header_desc *header_desc; | 101 | const struct usb_cdc_header_desc *header_desc; |
@@ -117,6 +115,7 @@ struct cdc_ncm_ctx { | |||
117 | struct sk_buff *tx_rem_skb; | 115 | struct sk_buff *tx_rem_skb; |
118 | 116 | ||
119 | spinlock_t mtx; | 117 | spinlock_t mtx; |
118 | atomic_t stop; | ||
120 | 119 | ||
121 | u32 tx_timer_pending; | 120 | u32 tx_timer_pending; |
122 | u32 tx_curr_offset; | 121 | u32 tx_curr_offset; |
@@ -132,10 +131,13 @@ struct cdc_ncm_ctx { | |||
132 | u16 tx_modulus; | 131 | u16 tx_modulus; |
133 | u16 tx_ndp_modulus; | 132 | u16 tx_ndp_modulus; |
134 | u16 tx_seq; | 133 | u16 tx_seq; |
134 | u16 rx_seq; | ||
135 | u16 connected; | 135 | u16 connected; |
136 | }; | 136 | }; |
137 | 137 | ||
138 | static void cdc_ncm_tx_timeout(unsigned long arg); | 138 | static void cdc_ncm_txpath_bh(unsigned long param); |
139 | static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx); | ||
140 | static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer); | ||
139 | static const struct driver_info cdc_ncm_info; | 141 | static const struct driver_info cdc_ncm_info; |
140 | static struct usb_driver cdc_ncm_driver; | 142 | static struct usb_driver cdc_ncm_driver; |
141 | static const struct ethtool_ops cdc_ncm_ethtool_ops; | 143 | static const struct ethtool_ops cdc_ncm_ethtool_ops; |
@@ -361,27 +363,25 @@ size_err: | |||
361 | if (err < 0) { | 363 | if (err < 0) { |
362 | pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", | 364 | pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", |
363 | CDC_NCM_MIN_DATAGRAM_SIZE); | 365 | CDC_NCM_MIN_DATAGRAM_SIZE); |
364 | kfree(max_datagram_size); | ||
365 | } else { | 366 | } else { |
366 | ctx->max_datagram_size = | 367 | ctx->max_datagram_size = |
367 | le16_to_cpu(*max_datagram_size); | 368 | le16_to_cpu(*max_datagram_size); |
368 | /* Check Eth descriptor value */ | 369 | /* Check Eth descriptor value */ |
369 | if (eth_max_sz < CDC_NCM_MAX_DATAGRAM_SIZE) { | 370 | if (ctx->max_datagram_size > eth_max_sz) |
370 | if (ctx->max_datagram_size > eth_max_sz) | ||
371 | ctx->max_datagram_size = eth_max_sz; | 371 | ctx->max_datagram_size = eth_max_sz; |
372 | } else { | 372 | |
373 | if (ctx->max_datagram_size > | 373 | if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE) |
374 | CDC_NCM_MAX_DATAGRAM_SIZE) | 374 | ctx->max_datagram_size = |
375 | ctx->max_datagram_size = | ||
376 | CDC_NCM_MAX_DATAGRAM_SIZE; | 375 | CDC_NCM_MAX_DATAGRAM_SIZE; |
377 | } | ||
378 | 376 | ||
379 | if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE) | 377 | if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE) |
380 | ctx->max_datagram_size = | 378 | ctx->max_datagram_size = |
381 | CDC_NCM_MIN_DATAGRAM_SIZE; | 379 | CDC_NCM_MIN_DATAGRAM_SIZE; |
382 | 380 | ||
383 | /* if value changed, update device */ | 381 | /* if value changed, update device */ |
384 | err = usb_control_msg(ctx->udev, | 382 | if (ctx->max_datagram_size != |
383 | le16_to_cpu(*max_datagram_size)) { | ||
384 | err = usb_control_msg(ctx->udev, | ||
385 | usb_sndctrlpipe(ctx->udev, 0), | 385 | usb_sndctrlpipe(ctx->udev, 0), |
386 | USB_CDC_SET_MAX_DATAGRAM_SIZE, | 386 | USB_CDC_SET_MAX_DATAGRAM_SIZE, |
387 | USB_TYPE_CLASS | USB_DIR_OUT | 387 | USB_TYPE_CLASS | USB_DIR_OUT |
@@ -389,14 +389,14 @@ size_err: | |||
389 | 0, | 389 | 0, |
390 | iface_no, max_datagram_size, | 390 | iface_no, max_datagram_size, |
391 | 2, 1000); | 391 | 2, 1000); |
392 | kfree(max_datagram_size); | 392 | if (err < 0) |
393 | max_dgram_err: | 393 | pr_debug("SET_MAX_DGRAM_SIZE failed\n"); |
394 | if (err < 0) | 394 | } |
395 | pr_debug("SET_MAX_DATAGRAM_SIZE failed\n"); | ||
396 | } | 395 | } |
397 | 396 | kfree(max_datagram_size); | |
398 | } | 397 | } |
399 | 398 | ||
399 | max_dgram_err: | ||
400 | if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN)) | 400 | if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN)) |
401 | ctx->netdev->mtu = ctx->max_datagram_size - ETH_HLEN; | 401 | ctx->netdev->mtu = ctx->max_datagram_size - ETH_HLEN; |
402 | 402 | ||
@@ -441,8 +441,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) | |||
441 | if (ctx == NULL) | 441 | if (ctx == NULL) |
442 | return; | 442 | return; |
443 | 443 | ||
444 | del_timer_sync(&ctx->tx_timer); | ||
445 | |||
446 | if (ctx->tx_rem_skb != NULL) { | 444 | if (ctx->tx_rem_skb != NULL) { |
447 | dev_kfree_skb_any(ctx->tx_rem_skb); | 445 | dev_kfree_skb_any(ctx->tx_rem_skb); |
448 | ctx->tx_rem_skb = NULL; | 446 | ctx->tx_rem_skb = NULL; |
@@ -469,7 +467,11 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) | |||
469 | if (ctx == NULL) | 467 | if (ctx == NULL) |
470 | return -ENODEV; | 468 | return -ENODEV; |
471 | 469 | ||
472 | init_timer(&ctx->tx_timer); | 470 | hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
471 | ctx->tx_timer.function = &cdc_ncm_tx_timer_cb; | ||
472 | ctx->bh.data = (unsigned long)ctx; | ||
473 | ctx->bh.func = cdc_ncm_txpath_bh; | ||
474 | atomic_set(&ctx->stop, 0); | ||
473 | spin_lock_init(&ctx->mtx); | 475 | spin_lock_init(&ctx->mtx); |
474 | ctx->netdev = dev->net; | 476 | ctx->netdev = dev->net; |
475 | 477 | ||
@@ -579,11 +581,7 @@ advance: | |||
579 | if (temp) | 581 | if (temp) |
580 | goto error2; | 582 | goto error2; |
581 | 583 | ||
582 | dev_info(&dev->udev->dev, "MAC-Address: " | 584 | dev_info(&dev->udev->dev, "MAC-Address: %pM\n", dev->net->dev_addr); |
583 | "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", | ||
584 | dev->net->dev_addr[0], dev->net->dev_addr[1], | ||
585 | dev->net->dev_addr[2], dev->net->dev_addr[3], | ||
586 | dev->net->dev_addr[4], dev->net->dev_addr[5]); | ||
587 | 585 | ||
588 | dev->in = usb_rcvbulkpipe(dev->udev, | 586 | dev->in = usb_rcvbulkpipe(dev->udev, |
589 | ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | 587 | ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); |
@@ -621,6 +619,13 @@ static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) | |||
621 | if (ctx == NULL) | 619 | if (ctx == NULL) |
622 | return; /* no setup */ | 620 | return; /* no setup */ |
623 | 621 | ||
622 | atomic_set(&ctx->stop, 1); | ||
623 | |||
624 | if (hrtimer_active(&ctx->tx_timer)) | ||
625 | hrtimer_cancel(&ctx->tx_timer); | ||
626 | |||
627 | tasklet_kill(&ctx->bh); | ||
628 | |||
624 | /* disconnect master --> disconnect slave */ | 629 | /* disconnect master --> disconnect slave */ |
625 | if (intf == ctx->control && ctx->data) { | 630 | if (intf == ctx->control && ctx->data) { |
626 | usb_set_intfdata(ctx->data, NULL); | 631 | usb_set_intfdata(ctx->data, NULL); |
@@ -791,7 +796,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) | |||
791 | ctx->tx_curr_last_offset = last_offset; | 796 | ctx->tx_curr_last_offset = last_offset; |
792 | /* set the pending count */ | 797 | /* set the pending count */ |
793 | if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT) | 798 | if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT) |
794 | ctx->tx_timer_pending = 2; | 799 | ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT; |
795 | goto exit_no_skb; | 800 | goto exit_no_skb; |
796 | 801 | ||
797 | } else { | 802 | } else { |
@@ -871,44 +876,49 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) | |||
871 | 876 | ||
872 | /* return skb */ | 877 | /* return skb */ |
873 | ctx->tx_curr_skb = NULL; | 878 | ctx->tx_curr_skb = NULL; |
879 | ctx->netdev->stats.tx_packets += ctx->tx_curr_frame_num; | ||
874 | return skb_out; | 880 | return skb_out; |
875 | 881 | ||
876 | exit_no_skb: | 882 | exit_no_skb: |
883 | /* Start timer, if there is a remaining skb */ | ||
884 | if (ctx->tx_curr_skb != NULL) | ||
885 | cdc_ncm_tx_timeout_start(ctx); | ||
877 | return NULL; | 886 | return NULL; |
878 | } | 887 | } |
879 | 888 | ||
880 | static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx) | 889 | static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx) |
881 | { | 890 | { |
882 | /* start timer, if not already started */ | 891 | /* start timer, if not already started */ |
883 | if (timer_pending(&ctx->tx_timer) == 0) { | 892 | if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop))) |
884 | ctx->tx_timer.function = &cdc_ncm_tx_timeout; | 893 | hrtimer_start(&ctx->tx_timer, |
885 | ctx->tx_timer.data = (unsigned long)ctx; | 894 | ktime_set(0, CDC_NCM_TIMER_INTERVAL), |
886 | ctx->tx_timer.expires = jiffies + ((HZ + 999) / 1000); | 895 | HRTIMER_MODE_REL); |
887 | add_timer(&ctx->tx_timer); | ||
888 | } | ||
889 | } | 896 | } |
890 | 897 | ||
891 | static void cdc_ncm_tx_timeout(unsigned long arg) | 898 | static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *timer) |
892 | { | 899 | { |
893 | struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)arg; | 900 | struct cdc_ncm_ctx *ctx = |
894 | u8 restart; | 901 | container_of(timer, struct cdc_ncm_ctx, tx_timer); |
895 | 902 | ||
896 | spin_lock(&ctx->mtx); | 903 | if (!atomic_read(&ctx->stop)) |
897 | if (ctx->tx_timer_pending != 0) { | 904 | tasklet_schedule(&ctx->bh); |
898 | ctx->tx_timer_pending--; | 905 | return HRTIMER_NORESTART; |
899 | restart = 1; | 906 | } |
900 | } else { | ||
901 | restart = 0; | ||
902 | } | ||
903 | 907 | ||
904 | spin_unlock(&ctx->mtx); | 908 | static void cdc_ncm_txpath_bh(unsigned long param) |
909 | { | ||
910 | struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)param; | ||
905 | 911 | ||
906 | if (restart) { | 912 | spin_lock_bh(&ctx->mtx); |
907 | spin_lock(&ctx->mtx); | 913 | if (ctx->tx_timer_pending != 0) { |
914 | ctx->tx_timer_pending--; | ||
908 | cdc_ncm_tx_timeout_start(ctx); | 915 | cdc_ncm_tx_timeout_start(ctx); |
909 | spin_unlock(&ctx->mtx); | 916 | spin_unlock_bh(&ctx->mtx); |
910 | } else if (ctx->netdev != NULL) { | 917 | } else if (ctx->netdev != NULL) { |
918 | spin_unlock_bh(&ctx->mtx); | ||
919 | netif_tx_lock_bh(ctx->netdev); | ||
911 | usbnet_start_xmit(NULL, ctx->netdev); | 920 | usbnet_start_xmit(NULL, ctx->netdev); |
921 | netif_tx_unlock_bh(ctx->netdev); | ||
912 | } | 922 | } |
913 | } | 923 | } |
914 | 924 | ||
@@ -917,7 +927,6 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | |||
917 | { | 927 | { |
918 | struct sk_buff *skb_out; | 928 | struct sk_buff *skb_out; |
919 | struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; | 929 | struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; |
920 | u8 need_timer = 0; | ||
921 | 930 | ||
922 | /* | 931 | /* |
923 | * The Ethernet API we are using does not support transmitting | 932 | * The Ethernet API we are using does not support transmitting |
@@ -929,19 +938,9 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | |||
929 | if (ctx == NULL) | 938 | if (ctx == NULL) |
930 | goto error; | 939 | goto error; |
931 | 940 | ||
932 | spin_lock(&ctx->mtx); | 941 | spin_lock_bh(&ctx->mtx); |
933 | skb_out = cdc_ncm_fill_tx_frame(ctx, skb); | 942 | skb_out = cdc_ncm_fill_tx_frame(ctx, skb); |
934 | if (ctx->tx_curr_skb != NULL) | 943 | spin_unlock_bh(&ctx->mtx); |
935 | need_timer = 1; | ||
936 | |||
937 | /* Start timer, if there is a remaining skb */ | ||
938 | if (need_timer) | ||
939 | cdc_ncm_tx_timeout_start(ctx); | ||
940 | |||
941 | if (skb_out) | ||
942 | dev->net->stats.tx_packets += ctx->tx_curr_frame_num; | ||
943 | |||
944 | spin_unlock(&ctx->mtx); | ||
945 | return skb_out; | 944 | return skb_out; |
946 | 945 | ||
947 | error: | 946 | error: |
@@ -954,108 +953,103 @@ error: | |||
954 | 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) |
955 | { | 954 | { |
956 | struct sk_buff *skb; | 955 | struct sk_buff *skb; |
957 | struct cdc_ncm_ctx *ctx; | 956 | struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; |
958 | int sumlen; | 957 | int len; |
959 | int actlen; | ||
960 | int temp; | ||
961 | int nframes; | 958 | int nframes; |
962 | int x; | 959 | int x; |
963 | 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; | ||
964 | 964 | ||
965 | ctx = (struct cdc_ncm_ctx *)dev->data[0]; | ||
966 | if (ctx == NULL) | 965 | if (ctx == NULL) |
967 | goto error; | 966 | goto error; |
968 | 967 | ||
969 | actlen = skb_in->len; | 968 | if (skb_in->len < (sizeof(struct usb_cdc_ncm_nth16) + |
970 | sumlen = CDC_NCM_NTB_MAX_SIZE_RX; | 969 | sizeof(struct usb_cdc_ncm_ndp16))) { |
971 | |||
972 | if (actlen < (sizeof(ctx->rx_ncm.nth16) + sizeof(ctx->rx_ncm.ndp16))) { | ||
973 | pr_debug("frame too short\n"); | 970 | pr_debug("frame too short\n"); |
974 | goto error; | 971 | goto error; |
975 | } | 972 | } |
976 | 973 | ||
977 | memcpy(&(ctx->rx_ncm.nth16), ((u8 *)skb_in->data), | 974 | nth16 = (struct usb_cdc_ncm_nth16 *)skb_in->data; |
978 | sizeof(ctx->rx_ncm.nth16)); | ||
979 | 975 | ||
980 | if (le32_to_cpu(ctx->rx_ncm.nth16.dwSignature) != | 976 | if (le32_to_cpu(nth16->dwSignature) != USB_CDC_NCM_NTH16_SIGN) { |
981 | USB_CDC_NCM_NTH16_SIGN) { | ||
982 | pr_debug("invalid NTH16 signature <%u>\n", | 977 | pr_debug("invalid NTH16 signature <%u>\n", |
983 | le32_to_cpu(ctx->rx_ncm.nth16.dwSignature)); | 978 | le32_to_cpu(nth16->dwSignature)); |
984 | goto error; | 979 | goto error; |
985 | } | 980 | } |
986 | 981 | ||
987 | temp = le16_to_cpu(ctx->rx_ncm.nth16.wBlockLength); | 982 | len = le16_to_cpu(nth16->wBlockLength); |
988 | if (temp > sumlen) { | 983 | if (len > ctx->rx_max) { |
989 | 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); | ||
990 | goto error; | 986 | goto error; |
991 | } | 987 | } |
992 | 988 | ||
993 | temp = le16_to_cpu(ctx->rx_ncm.nth16.wNdpIndex); | 989 | if ((ctx->rx_seq + 1) != le16_to_cpu(nth16->wSequence) && |
994 | if ((temp + sizeof(ctx->rx_ncm.ndp16)) > actlen) { | 990 | (ctx->rx_seq || le16_to_cpu(nth16->wSequence)) && |
995 | 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)); | ||
996 | goto error; | 1001 | goto error; |
997 | } | 1002 | } |
998 | 1003 | ||
999 | memcpy(&(ctx->rx_ncm.ndp16), ((u8 *)skb_in->data) + temp, | 1004 | ndp16 = (struct usb_cdc_ncm_ndp16 *)(((u8 *)skb_in->data) + len); |
1000 | sizeof(ctx->rx_ncm.ndp16)); | ||
1001 | 1005 | ||
1002 | if (le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature) != | 1006 | if (le32_to_cpu(ndp16->dwSignature) != USB_CDC_NCM_NDP16_NOCRC_SIGN) { |
1003 | USB_CDC_NCM_NDP16_NOCRC_SIGN) { | ||
1004 | pr_debug("invalid DPT16 signature <%u>\n", | 1007 | pr_debug("invalid DPT16 signature <%u>\n", |
1005 | le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature)); | 1008 | le32_to_cpu(ndp16->dwSignature)); |
1006 | goto error; | 1009 | goto error; |
1007 | } | 1010 | } |
1008 | 1011 | ||
1009 | if (le16_to_cpu(ctx->rx_ncm.ndp16.wLength) < | 1012 | if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) { |
1010 | USB_CDC_NCM_NDP16_LENGTH_MIN) { | ||
1011 | pr_debug("invalid DPT16 length <%u>\n", | 1013 | pr_debug("invalid DPT16 length <%u>\n", |
1012 | le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature)); | 1014 | le32_to_cpu(ndp16->dwSignature)); |
1013 | goto error; | 1015 | goto error; |
1014 | } | 1016 | } |
1015 | 1017 | ||
1016 | nframes = ((le16_to_cpu(ctx->rx_ncm.ndp16.wLength) - | 1018 | nframes = ((le16_to_cpu(ndp16->wLength) - |
1017 | sizeof(struct usb_cdc_ncm_ndp16)) / | 1019 | sizeof(struct usb_cdc_ncm_ndp16)) / |
1018 | sizeof(struct usb_cdc_ncm_dpe16)); | 1020 | sizeof(struct usb_cdc_ncm_dpe16)); |
1019 | nframes--; /* we process NDP entries except for the last one */ | 1021 | nframes--; /* we process NDP entries except for the last one */ |
1020 | 1022 | ||
1021 | pr_debug("nframes = %u\n", nframes); | 1023 | len += sizeof(struct usb_cdc_ncm_ndp16); |
1022 | |||
1023 | temp += sizeof(ctx->rx_ncm.ndp16); | ||
1024 | 1024 | ||
1025 | if ((temp + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > actlen) { | 1025 | if ((len + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > |
1026 | skb_in->len) { | ||
1026 | pr_debug("Invalid nframes = %d\n", nframes); | 1027 | pr_debug("Invalid nframes = %d\n", nframes); |
1027 | goto error; | 1028 | goto error; |
1028 | } | 1029 | } |
1029 | 1030 | ||
1030 | if (nframes > CDC_NCM_DPT_DATAGRAMS_MAX) { | 1031 | dpe16 = (struct usb_cdc_ncm_dpe16 *)(((u8 *)skb_in->data) + len); |
1031 | pr_debug("Truncating number of frames from %u to %u\n", | ||
1032 | nframes, CDC_NCM_DPT_DATAGRAMS_MAX); | ||
1033 | nframes = CDC_NCM_DPT_DATAGRAMS_MAX; | ||
1034 | } | ||
1035 | |||
1036 | memcpy(&(ctx->rx_ncm.dpe16), ((u8 *)skb_in->data) + temp, | ||
1037 | nframes * (sizeof(struct usb_cdc_ncm_dpe16))); | ||
1038 | 1032 | ||
1039 | for (x = 0; x < nframes; x++) { | 1033 | for (x = 0; x < nframes; x++, dpe16++) { |
1040 | offset = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramIndex); | 1034 | offset = le16_to_cpu(dpe16->wDatagramIndex); |
1041 | temp = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramLength); | 1035 | len = le16_to_cpu(dpe16->wDatagramLength); |
1042 | 1036 | ||
1043 | /* | 1037 | /* |
1044 | * CDC NCM ch. 3.7 | 1038 | * CDC NCM ch. 3.7 |
1045 | * All entries after first NULL entry are to be ignored | 1039 | * All entries after first NULL entry are to be ignored |
1046 | */ | 1040 | */ |
1047 | if ((offset == 0) || (temp == 0)) { | 1041 | if ((offset == 0) || (len == 0)) { |
1048 | if (!x) | 1042 | if (!x) |
1049 | goto error; /* empty NTB */ | 1043 | goto error; /* empty NTB */ |
1050 | break; | 1044 | break; |
1051 | } | 1045 | } |
1052 | 1046 | ||
1053 | /* sanity checking */ | 1047 | /* sanity checking */ |
1054 | if (((offset + temp) > actlen) || | 1048 | if (((offset + len) > skb_in->len) || |
1055 | (temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) { | 1049 | (len > ctx->rx_max) || (len < ETH_HLEN)) { |
1056 | pr_debug("invalid frame detected (ignored)" | 1050 | pr_debug("invalid frame detected (ignored)" |
1057 | "offset[%u]=%u, length=%u, skb=%p\n", | 1051 | "offset[%u]=%u, length=%u, skb=%p\n", |
1058 | x, offset, temp, skb_in); | 1052 | x, offset, len, skb_in); |
1059 | if (!x) | 1053 | if (!x) |
1060 | goto error; | 1054 | goto error; |
1061 | break; | 1055 | break; |
@@ -1064,9 +1058,9 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) | |||
1064 | skb = skb_clone(skb_in, GFP_ATOMIC); | 1058 | skb = skb_clone(skb_in, GFP_ATOMIC); |
1065 | if (!skb) | 1059 | if (!skb) |
1066 | goto error; | 1060 | goto error; |
1067 | skb->len = temp; | 1061 | skb->len = len; |
1068 | skb->data = ((u8 *)skb_in->data) + offset; | 1062 | skb->data = ((u8 *)skb_in->data) + offset; |
1069 | skb_set_tail_pointer(skb, temp); | 1063 | skb_set_tail_pointer(skb, len); |
1070 | usbnet_skb_return(dev, skb); | 1064 | usbnet_skb_return(dev, skb); |
1071 | } | 1065 | } |
1072 | } | 1066 | } |