Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gianfar: Fix invalid TX frames returned on error queue when time stamping

When TX time stamping for PTP messages is enabled on a socket, a time
stamp is returned on the socket error queue to the user space application
after the frame was transmitted. The transmitted frame is also returned on
the error queue so that an application knows to which frame the time stamp
belongs.

In the current implementation the TxFCB is immediately followed by the
frame. Since the eTSEC inserts the TX time stamp 8 bytes after the TxFCB,
parts of the frame have been overwritten and an invalid frame was returned
on the socket error queue.

This patch fixes the described problem by adding additional 16 padding
bytes between the TxFCB and the frame for all messages sent from a time
stamping enabled socket (other sockets are not affected).

Signed-off-by: Manfred Rudigier <manfred.rudigier@omicron.at>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Manfred Rudigier and committed by
David S. Miller
9c4886e5 db83d136

+23 -10
+20 -10
drivers/net/ethernet/freescale/gianfar.c
··· 1984 1984 return fcb; 1985 1985 } 1986 1986 1987 - static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb) 1987 + static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb, 1988 + int fcb_length) 1988 1989 { 1989 1990 u8 flags = 0; 1990 1991 ··· 2007 2006 * frame (skb->data) and the start of the IP hdr. 2008 2007 * l4os is the distance between the start of the 2009 2008 * l3 hdr and the l4 hdr */ 2010 - fcb->l3os = (u16)(skb_network_offset(skb) - GMAC_FCB_LEN); 2009 + fcb->l3os = (u16)(skb_network_offset(skb) - fcb_length); 2011 2010 fcb->l4os = skb_network_header_len(skb); 2012 2011 2013 2012 fcb->flags = flags; ··· 2047 2046 int i, rq = 0, do_tstamp = 0; 2048 2047 u32 bufaddr; 2049 2048 unsigned long flags; 2050 - unsigned int nr_frags, nr_txbds, length; 2049 + unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN; 2051 2050 2052 2051 /* 2053 2052 * TOE=1 frames larger than 2500 bytes may see excess delays ··· 2071 2070 2072 2071 /* check if time stamp should be generated */ 2073 2072 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && 2074 - priv->hwts_tx_en)) 2073 + priv->hwts_tx_en)) { 2075 2074 do_tstamp = 1; 2075 + fcb_length = GMAC_FCB_LEN + GMAC_TXPAL_LEN; 2076 + } 2076 2077 2077 2078 /* make space for additional header when fcb is needed */ 2078 2079 if (((skb->ip_summed == CHECKSUM_PARTIAL) || 2079 2080 vlan_tx_tag_present(skb) || 2080 2081 unlikely(do_tstamp)) && 2081 - (skb_headroom(skb) < GMAC_FCB_LEN)) { 2082 + (skb_headroom(skb) < fcb_length)) { 2082 2083 struct sk_buff *skb_new; 2083 2084 2084 - skb_new = skb_realloc_headroom(skb, GMAC_FCB_LEN); 2085 + skb_new = skb_realloc_headroom(skb, fcb_length); 2085 2086 if (!skb_new) { 2086 2087 dev->stats.tx_errors++; 2087 2088 kfree_skb(skb); ··· 2161 2158 lstatus = txbdp_start->lstatus; 2162 2159 } 2163 2160 2161 + /* Add TxPAL between FCB and frame if required */ 2162 + if (unlikely(do_tstamp)) { 2163 + skb_push(skb, GMAC_TXPAL_LEN); 2164 + memset(skb->data, 0, GMAC_TXPAL_LEN); 2165 + } 2166 + 2164 2167 /* Set up checksumming */ 2165 2168 if (CHECKSUM_PARTIAL == skb->ip_summed) { 2166 2169 fcb = gfar_add_fcb(skb); ··· 2177 2168 skb_checksum_help(skb); 2178 2169 } else { 2179 2170 lstatus |= BD_LFLAG(TXBD_TOE); 2180 - gfar_tx_checksum(skb, fcb); 2171 + gfar_tx_checksum(skb, fcb, fcb_length); 2181 2172 } 2182 2173 } 2183 2174 ··· 2209 2200 * the full frame length. 2210 2201 */ 2211 2202 if (unlikely(do_tstamp)) { 2212 - txbdp_tstamp->bufPtr = txbdp_start->bufPtr + GMAC_FCB_LEN; 2203 + txbdp_tstamp->bufPtr = txbdp_start->bufPtr + fcb_length; 2213 2204 txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_READY) | 2214 - (skb_headlen(skb) - GMAC_FCB_LEN); 2205 + (skb_headlen(skb) - fcb_length); 2215 2206 lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN; 2216 2207 } else { 2217 2208 lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); ··· 2503 2494 2504 2495 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { 2505 2496 next = next_txbd(bdp, base, tx_ring_size); 2506 - buflen = next->length + GMAC_FCB_LEN; 2497 + buflen = next->length + GMAC_FCB_LEN + GMAC_TXPAL_LEN; 2507 2498 } else 2508 2499 buflen = bdp->length; 2509 2500 ··· 2515 2506 u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7); 2516 2507 memset(&shhwtstamps, 0, sizeof(shhwtstamps)); 2517 2508 shhwtstamps.hwtstamp = ns_to_ktime(*ns); 2509 + skb_pull(skb, GMAC_FCB_LEN + GMAC_TXPAL_LEN); 2518 2510 skb_tstamp_tx(skb, &shhwtstamps); 2519 2511 bdp->lstatus &= BD_LFLAG(TXBD_WRAP); 2520 2512 bdp = next;
+3
drivers/net/ethernet/freescale/gianfar.h
··· 63 63 /* Length for FCB */ 64 64 #define GMAC_FCB_LEN 8 65 65 66 + /* Length for TxPAL */ 67 + #define GMAC_TXPAL_LEN 16 68 + 66 69 /* Default padding amount */ 67 70 #define DEFAULT_PADDING 2 68 71