88
88
(sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \
89
89
(CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
90
90
91
- struct cdc_ncm_data {
92
- struct usb_cdc_ncm_nth16 nth16 ;
93
- struct usb_cdc_ncm_ndp16 ndp16 ;
94
- struct usb_cdc_ncm_dpe16 dpe16 [CDC_NCM_DPT_DATAGRAMS_MAX + 1 ];
95
- };
91
+ #define CDC_NCM_NDP_SIZE \
92
+ (sizeof(struct usb_cdc_ncm_ndp16) + \
93
+ (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
96
94
97
95
struct cdc_ncm_ctx {
98
- struct cdc_ncm_data tx_ncm ;
99
96
struct usb_cdc_ncm_ntb_parameters ncm_parm ;
100
97
struct hrtimer tx_timer ;
101
98
struct tasklet_struct bh ;
@@ -117,13 +114,12 @@ struct cdc_ncm_ctx {
117
114
118
115
struct sk_buff * tx_curr_skb ;
119
116
struct sk_buff * tx_rem_skb ;
117
+ __le32 tx_rem_sign ;
120
118
121
119
spinlock_t mtx ;
122
120
atomic_t stop ;
123
121
124
122
u32 tx_timer_pending ;
125
- u32 tx_curr_offset ;
126
- u32 tx_curr_last_offset ;
127
123
u32 tx_curr_frame_num ;
128
124
u32 rx_speed ;
129
125
u32 tx_speed ;
@@ -658,51 +654,75 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
658
654
return ret ;
659
655
}
660
656
661
- static void cdc_ncm_zero_fill ( u8 * ptr , u32 first , u32 end , u32 max )
657
+ static void cdc_ncm_align_tail ( struct sk_buff * skb , size_t modulus , size_t remainder , size_t max )
662
658
{
663
- if (first >= max )
664
- return ;
665
- if (first >= end )
666
- return ;
667
- if (end > max )
668
- end = max ;
669
- memset (ptr + first , 0 , end - first );
659
+ size_t align = ALIGN (skb -> len , modulus ) - skb -> len + remainder ;
660
+
661
+ if (skb -> len + align > max )
662
+ align = max - skb -> len ;
663
+ if (align && skb_tailroom (skb ) >= align )
664
+ memset (skb_put (skb , align ), 0 , align );
665
+ }
666
+
667
+ /* return a pointer to a valid struct usb_cdc_ncm_ndp16 of type sign, possibly
668
+ * allocating a new one within skb
669
+ */
670
+ static struct usb_cdc_ncm_ndp16 * cdc_ncm_ndp (struct cdc_ncm_ctx * ctx , struct sk_buff * skb , __le32 sign , size_t reserve )
671
+ {
672
+ struct usb_cdc_ncm_ndp16 * ndp16 = NULL ;
673
+ struct usb_cdc_ncm_nth16 * nth16 = (void * )skb -> data ;
674
+ size_t ndpoffset = le16_to_cpu (nth16 -> wNdpIndex );
675
+
676
+ /* follow the chain of NDPs, looking for a match */
677
+ while (ndpoffset ) {
678
+ ndp16 = (struct usb_cdc_ncm_ndp16 * )(skb -> data + ndpoffset );
679
+ if (ndp16 -> dwSignature == sign )
680
+ return ndp16 ;
681
+ ndpoffset = le16_to_cpu (ndp16 -> wNextNdpIndex );
682
+ }
683
+
684
+ /* align new NDP */
685
+ cdc_ncm_align_tail (skb , ctx -> tx_ndp_modulus , 0 , ctx -> tx_max );
686
+
687
+ /* verify that there is room for the NDP and the datagram (reserve) */
688
+ if ((ctx -> tx_max - skb -> len - reserve ) < CDC_NCM_NDP_SIZE )
689
+ return NULL ;
690
+
691
+ /* link to it */
692
+ if (ndp16 )
693
+ ndp16 -> wNextNdpIndex = cpu_to_le16 (skb -> len );
694
+ else
695
+ nth16 -> wNdpIndex = cpu_to_le16 (skb -> len );
696
+
697
+ /* push a new empty NDP */
698
+ ndp16 = (struct usb_cdc_ncm_ndp16 * )memset (skb_put (skb , CDC_NCM_NDP_SIZE ), 0 , CDC_NCM_NDP_SIZE );
699
+ ndp16 -> dwSignature = sign ;
700
+ ndp16 -> wLength = cpu_to_le16 (sizeof (struct usb_cdc_ncm_ndp16 ) + sizeof (struct usb_cdc_ncm_dpe16 ));
701
+ return ndp16 ;
670
702
}
671
703
672
704
static struct sk_buff *
673
- cdc_ncm_fill_tx_frame (struct cdc_ncm_ctx * ctx , struct sk_buff * skb )
705
+ cdc_ncm_fill_tx_frame (struct cdc_ncm_ctx * ctx , struct sk_buff * skb , __le32 sign )
674
706
{
707
+ struct usb_cdc_ncm_nth16 * nth16 ;
708
+ struct usb_cdc_ncm_ndp16 * ndp16 ;
675
709
struct sk_buff * skb_out ;
676
- u32 rem ;
677
- u32 offset ;
678
- u32 last_offset ;
679
- u16 n = 0 , index ;
710
+ u16 n = 0 , index , ndplen ;
680
711
u8 ready2send = 0 ;
681
712
682
713
/* if there is a remaining skb, it gets priority */
683
- if (skb != NULL )
714
+ if (skb != NULL ) {
684
715
swap (skb , ctx -> tx_rem_skb );
685
- else
716
+ swap (sign , ctx -> tx_rem_sign );
717
+ } else {
686
718
ready2send = 1 ;
687
-
688
- /*
689
- * +----------------+
690
- * | skb_out |
691
- * +----------------+
692
- * ^ offset
693
- * ^ last_offset
694
- */
719
+ }
695
720
696
721
/* check if we are resuming an OUT skb */
697
- if (ctx -> tx_curr_skb != NULL ) {
698
- /* pop variables */
699
- skb_out = ctx -> tx_curr_skb ;
700
- offset = ctx -> tx_curr_offset ;
701
- last_offset = ctx -> tx_curr_last_offset ;
702
- n = ctx -> tx_curr_frame_num ;
722
+ skb_out = ctx -> tx_curr_skb ;
703
723
704
- } else {
705
- /* reset variables */
724
+ /* allocate a new OUT skb */
725
+ if (! skb_out ) {
706
726
skb_out = alloc_skb ((ctx -> tx_max + 1 ), GFP_ATOMIC );
707
727
if (skb_out == NULL ) {
708
728
if (skb != NULL ) {
@@ -711,43 +731,36 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
711
731
}
712
732
goto exit_no_skb ;
713
733
}
734
+ /* fill out the initial 16-bit NTB header */
735
+ nth16 = (struct usb_cdc_ncm_nth16 * )memset (skb_put (skb_out , sizeof (struct usb_cdc_ncm_nth16 )), 0 , sizeof (struct usb_cdc_ncm_nth16 ));
736
+ nth16 -> dwSignature = cpu_to_le32 (USB_CDC_NCM_NTH16_SIGN );
737
+ nth16 -> wHeaderLength = cpu_to_le16 (sizeof (struct usb_cdc_ncm_nth16 ));
738
+ nth16 -> wSequence = cpu_to_le16 (ctx -> tx_seq ++ );
714
739
715
- /* make room for NTH and NDP */
716
- offset = ALIGN (sizeof (struct usb_cdc_ncm_nth16 ),
717
- ctx -> tx_ndp_modulus ) +
718
- sizeof (struct usb_cdc_ncm_ndp16 ) +
719
- (ctx -> tx_max_datagrams + 1 ) *
720
- sizeof (struct usb_cdc_ncm_dpe16 );
721
-
722
- /* store last valid offset before alignment */
723
- last_offset = offset ;
724
- /* align first Datagram offset correctly */
725
- offset = ALIGN (offset , ctx -> tx_modulus ) + ctx -> tx_remainder ;
726
- /* zero buffer till the first IP datagram */
727
- cdc_ncm_zero_fill (skb_out -> data , 0 , offset , offset );
728
- n = 0 ;
740
+ /* count total number of frames in this NTB */
729
741
ctx -> tx_curr_frame_num = 0 ;
730
742
}
731
743
732
- for (; n < ctx -> tx_max_datagrams ; n ++ ) {
733
- /* check if end of transmit buffer is reached */
734
- if (offset >= ctx -> tx_max ) {
735
- ready2send = 1 ;
736
- break ;
737
- }
738
- /* compute maximum buffer size */
739
- rem = ctx -> tx_max - offset ;
740
-
744
+ for (n = ctx -> tx_curr_frame_num ; n < ctx -> tx_max_datagrams ; n ++ ) {
745
+ /* send any remaining skb first */
741
746
if (skb == NULL ) {
742
747
skb = ctx -> tx_rem_skb ;
748
+ sign = ctx -> tx_rem_sign ;
743
749
ctx -> tx_rem_skb = NULL ;
744
750
745
751
/* check for end of skb */
746
752
if (skb == NULL )
747
753
break ;
748
754
}
749
755
750
- if (skb -> len > rem ) {
756
+ /* get the appropriate NDP for this skb */
757
+ ndp16 = cdc_ncm_ndp (ctx , skb_out , sign , skb -> len + ctx -> tx_modulus + ctx -> tx_remainder );
758
+
759
+ /* align beginning of next frame */
760
+ cdc_ncm_align_tail (skb_out , ctx -> tx_modulus , ctx -> tx_remainder , ctx -> tx_max );
761
+
762
+ /* check if we had enough room left for both NDP and frame */
763
+ if (!ndp16 || skb_out -> len + skb -> len > ctx -> tx_max ) {
751
764
if (n == 0 ) {
752
765
/* won't fit, MTU problem? */
753
766
dev_kfree_skb_any (skb );
@@ -760,31 +773,30 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
760
773
ctx -> netdev -> stats .tx_dropped ++ ;
761
774
}
762
775
ctx -> tx_rem_skb = skb ;
776
+ ctx -> tx_rem_sign = sign ;
763
777
skb = NULL ;
764
778
ready2send = 1 ;
765
779
}
766
780
break ;
767
781
}
768
782
769
- memcpy (((u8 * )skb_out -> data ) + offset , skb -> data , skb -> len );
770
-
771
- ctx -> tx_ncm .dpe16 [n ].wDatagramLength = cpu_to_le16 (skb -> len );
772
- ctx -> tx_ncm .dpe16 [n ].wDatagramIndex = cpu_to_le16 (offset );
773
-
774
- /* update offset */
775
- offset += skb -> len ;
783
+ /* calculate frame number withing this NDP */
784
+ ndplen = le16_to_cpu (ndp16 -> wLength );
785
+ index = (ndplen - sizeof (struct usb_cdc_ncm_ndp16 )) / sizeof (struct usb_cdc_ncm_dpe16 ) - 1 ;
776
786
777
- /* store last valid offset before alignment */
778
- last_offset = offset ;
779
-
780
- /* align offset correctly */
781
- offset = ALIGN (offset , ctx -> tx_modulus ) + ctx -> tx_remainder ;
782
-
783
- /* zero padding */
784
- cdc_ncm_zero_fill (skb_out -> data , last_offset , offset ,
785
- ctx -> tx_max );
787
+ /* OK, add this skb */
788
+ ndp16 -> dpe16 [index ].wDatagramLength = cpu_to_le16 (skb -> len );
789
+ ndp16 -> dpe16 [index ].wDatagramIndex = cpu_to_le16 (skb_out -> len );
790
+ ndp16 -> wLength = cpu_to_le16 (ndplen + sizeof (struct usb_cdc_ncm_dpe16 ));
791
+ memcpy (skb_put (skb_out , skb -> len ), skb -> data , skb -> len );
786
792
dev_kfree_skb_any (skb );
787
793
skb = NULL ;
794
+
795
+ /* send now if this NDP is full */
796
+ if (index >= CDC_NCM_DPT_DATAGRAMS_MAX ) {
797
+ ready2send = 1 ;
798
+ break ;
799
+ }
788
800
}
789
801
790
802
/* free up any dangling skb */
@@ -800,16 +812,12 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
800
812
/* wait for more frames */
801
813
/* push variables */
802
814
ctx -> tx_curr_skb = skb_out ;
803
- ctx -> tx_curr_offset = offset ;
804
- ctx -> tx_curr_last_offset = last_offset ;
805
815
goto exit_no_skb ;
806
816
807
817
} else if ((n < ctx -> tx_max_datagrams ) && (ready2send == 0 )) {
808
818
/* wait for more frames */
809
819
/* push variables */
810
820
ctx -> tx_curr_skb = skb_out ;
811
- ctx -> tx_curr_offset = offset ;
812
- ctx -> tx_curr_last_offset = last_offset ;
813
821
/* set the pending count */
814
822
if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT )
815
823
ctx -> tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT ;
@@ -820,75 +828,24 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
820
828
/* variables will be reset at next call */
821
829
}
822
830
823
- /* check for overflow */
824
- if (last_offset > ctx -> tx_max )
825
- last_offset = ctx -> tx_max ;
826
-
827
- /* revert offset */
828
- offset = last_offset ;
829
-
830
831
/*
831
832
* If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes,
832
833
* we send buffers as it is. If we get more data, it would be more
833
834
* efficient for USB HS mobile device with DMA engine to receive a full
834
835
* size NTB, than canceling DMA transfer and receiving a short packet.
835
836
*/
836
- if (offset > CDC_NCM_MIN_TX_PKT )
837
- offset = ctx -> tx_max ;
838
-
839
- /* final zero padding */
840
- cdc_ncm_zero_fill (skb_out -> data , last_offset , offset , ctx -> tx_max );
841
-
842
- /* store last offset */
843
- last_offset = offset ;
844
-
845
- if (((last_offset < ctx -> tx_max ) && ((last_offset %
846
- le16_to_cpu (ctx -> out_ep -> desc .wMaxPacketSize )) == 0 )) ||
847
- (((last_offset == ctx -> tx_max ) && ((ctx -> tx_max %
848
- le16_to_cpu (ctx -> out_ep -> desc .wMaxPacketSize )) == 0 )) &&
849
- (ctx -> tx_max < le32_to_cpu (ctx -> ncm_parm .dwNtbOutMaxSize )))) {
850
- /* force short packet */
851
- * (((u8 * )skb_out -> data ) + last_offset ) = 0 ;
852
- last_offset ++ ;
853
- }
837
+ if (skb_out -> len > CDC_NCM_MIN_TX_PKT )
838
+ /* final zero padding */
839
+ memset (skb_put (skb_out , ctx -> tx_max - skb_out -> len ), 0 , ctx -> tx_max - skb_out -> len );
854
840
855
- /* zero the rest of the DPEs plus the last NULL entry */
856
- for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX ; n ++ ) {
857
- ctx -> tx_ncm .dpe16 [n ].wDatagramLength = 0 ;
858
- ctx -> tx_ncm .dpe16 [n ].wDatagramIndex = 0 ;
859
- }
860
-
861
- /* fill out 16-bit NTB header */
862
- ctx -> tx_ncm .nth16 .dwSignature = cpu_to_le32 (USB_CDC_NCM_NTH16_SIGN );
863
- ctx -> tx_ncm .nth16 .wHeaderLength =
864
- cpu_to_le16 (sizeof (ctx -> tx_ncm .nth16 ));
865
- ctx -> tx_ncm .nth16 .wSequence = cpu_to_le16 (ctx -> tx_seq );
866
- ctx -> tx_ncm .nth16 .wBlockLength = cpu_to_le16 (last_offset );
867
- index = ALIGN (sizeof (struct usb_cdc_ncm_nth16 ), ctx -> tx_ndp_modulus );
868
- ctx -> tx_ncm .nth16 .wNdpIndex = cpu_to_le16 (index );
869
-
870
- memcpy (skb_out -> data , & (ctx -> tx_ncm .nth16 ), sizeof (ctx -> tx_ncm .nth16 ));
871
- ctx -> tx_seq ++ ;
872
-
873
- /* fill out 16-bit NDP table */
874
- ctx -> tx_ncm .ndp16 .dwSignature =
875
- cpu_to_le32 (USB_CDC_NCM_NDP16_NOCRC_SIGN );
876
- rem = sizeof (ctx -> tx_ncm .ndp16 ) + ((ctx -> tx_curr_frame_num + 1 ) *
877
- sizeof (struct usb_cdc_ncm_dpe16 ));
878
- ctx -> tx_ncm .ndp16 .wLength = cpu_to_le16 (rem );
879
- ctx -> tx_ncm .ndp16 .wNextNdpIndex = 0 ; /* reserved */
880
-
881
- memcpy (((u8 * )skb_out -> data ) + index ,
882
- & (ctx -> tx_ncm .ndp16 ),
883
- sizeof (ctx -> tx_ncm .ndp16 ));
884
-
885
- memcpy (((u8 * )skb_out -> data ) + index + sizeof (ctx -> tx_ncm .ndp16 ),
886
- & (ctx -> tx_ncm .dpe16 ),
887
- (ctx -> tx_curr_frame_num + 1 ) *
888
- sizeof (struct usb_cdc_ncm_dpe16 ));
841
+ /* do we need to prevent a ZLP? */
842
+ if (((skb_out -> len % le16_to_cpu (ctx -> out_ep -> desc .wMaxPacketSize )) == 0 ) &&
843
+ (skb_out -> len < le32_to_cpu (ctx -> ncm_parm .dwNtbOutMaxSize )) && skb_tailroom (skb_out ))
844
+ * skb_put (skb_out , 1 ) = 0 ; /* force short packet */
889
845
890
- /* set frame length */
891
- skb_put (skb_out , last_offset );
846
+ /* set final frame length */
847
+ nth16 = (struct usb_cdc_ncm_nth16 * )skb_out -> data ;
848
+ nth16 -> wBlockLength = cpu_to_le16 (skb_out -> len );
892
849
893
850
/* return skb */
894
851
ctx -> tx_curr_skb = NULL ;
@@ -955,7 +912,7 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
955
912
goto error ;
956
913
957
914
spin_lock_bh (& ctx -> mtx );
958
- skb_out = cdc_ncm_fill_tx_frame (ctx , skb );
915
+ skb_out = cdc_ncm_fill_tx_frame (ctx , skb , cpu_to_le32 ( USB_CDC_NCM_NDP16_NOCRC_SIGN ) );
959
916
spin_unlock_bh (& ctx -> mtx );
960
917
return skb_out ;
961
918
0 commit comments