Commit 3bdc0eba authored by Ben Greear's avatar Ben Greear Committed by Jeff Kirsher

net: Add framework to allow sending packets with customized CRC.

This is useful for testing RX handling of frames with bad
CRCs.

Requires driver support to actually put the packet on the
wire properly.
Signed-off-by: default avatarBen Greear <greearb@candelatech.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 0184039a
...@@ -73,6 +73,9 @@ ...@@ -73,6 +73,9 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we /* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here. * have to define SOCK_NONBLOCK to a different value here.
*/ */
......
...@@ -66,4 +66,7 @@ ...@@ -66,4 +66,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -66,4 +66,7 @@ ...@@ -66,4 +66,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* __ASM_AVR32_SOCKET_H */ #endif /* __ASM_AVR32_SOCKET_H */
...@@ -68,6 +68,9 @@ ...@@ -68,6 +68,9 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -66,5 +66,8 @@ ...@@ -66,5 +66,8 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -66,4 +66,7 @@ ...@@ -66,4 +66,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -75,4 +75,7 @@ ...@@ -75,4 +75,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_IA64_SOCKET_H */ #endif /* _ASM_IA64_SOCKET_H */
...@@ -66,4 +66,7 @@ ...@@ -66,4 +66,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_M32R_SOCKET_H */ #endif /* _ASM_M32R_SOCKET_H */
...@@ -66,4 +66,7 @@ ...@@ -66,4 +66,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -86,6 +86,9 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ ...@@ -86,6 +86,9 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#ifdef __KERNEL__ #ifdef __KERNEL__
/** sock_type - Socket types /** sock_type - Socket types
......
...@@ -66,4 +66,7 @@ ...@@ -66,4 +66,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -65,6 +65,10 @@ ...@@ -65,6 +65,10 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 0x4023 #define SO_PEEK_OFF 0x4023
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 0x4024
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we /* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here. * have to define SOCK_NONBLOCK to a different value here.
*/ */
......
...@@ -73,4 +73,7 @@ ...@@ -73,4 +73,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_POWERPC_SOCKET_H */ #endif /* _ASM_POWERPC_SOCKET_H */
...@@ -74,4 +74,7 @@ ...@@ -74,4 +74,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -62,6 +62,10 @@ ...@@ -62,6 +62,10 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 0x0026 #define SO_PEEK_OFF 0x0026
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 0x0027
/* Security levels - as per NRL IPv6 - don't actually do anything */ /* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
......
...@@ -77,4 +77,7 @@ ...@@ -77,4 +77,7 @@
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* _XTENSA_SOCKET_H */ #endif /* _XTENSA_SOCKET_H */
...@@ -68,4 +68,8 @@ ...@@ -68,4 +68,8 @@
#define SO_WIFI_STATUS 41 #define SO_WIFI_STATUS 41
#define SCM_WIFI_STATUS SO_WIFI_STATUS #define SCM_WIFI_STATUS SO_WIFI_STATUS
#define SO_PEEK_OFF 42 #define SO_PEEK_OFF 42
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#endif /* __ASM_GENERIC_SOCKET_H */ #endif /* __ASM_GENERIC_SOCKET_H */
...@@ -80,6 +80,8 @@ ...@@ -80,6 +80,8 @@
* skbs on transmit */ * skbs on transmit */
#define IFF_UNICAST_FLT 0x20000 /* Supports unicast filtering */ #define IFF_UNICAST_FLT 0x20000 /* Supports unicast filtering */
#define IFF_TEAM_PORT 0x40000 /* device used as team port */ #define IFF_TEAM_PORT 0x40000 /* device used as team port */
#define IFF_SUPP_NOFCS 0x80000 /* device supports sending custom FCS */
#define IF_GET_IFACE 0x0001 /* for querying only */ #define IF_GET_IFACE 0x0001 /* for querying only */
#define IF_GET_PROTO 0x0002 #define IF_GET_PROTO 0x0002
......
...@@ -1082,7 +1082,8 @@ struct net_device { ...@@ -1082,7 +1082,8 @@ struct net_device {
const struct header_ops *header_ops; const struct header_ops *header_ops;
unsigned int flags; /* interface flags (a la BSD) */ unsigned int flags; /* interface flags (a la BSD) */
unsigned int priv_flags; /* Like 'flags' but invisible to userspace. */ unsigned int priv_flags; /* Like 'flags' but invisible to userspace.
* See if.h for definitions. */
unsigned short gflags; unsigned short gflags;
unsigned short padded; /* How much padding added by alloc_netdev() */ unsigned short padded; /* How much padding added by alloc_netdev() */
...@@ -2650,6 +2651,11 @@ static inline int netif_is_bond_slave(struct net_device *dev) ...@@ -2650,6 +2651,11 @@ static inline int netif_is_bond_slave(struct net_device *dev)
return dev->flags & IFF_SLAVE && dev->priv_flags & IFF_BONDING; return dev->flags & IFF_SLAVE && dev->priv_flags & IFF_BONDING;
} }
static inline bool netif_supports_nofcs(struct net_device *dev)
{
return dev->priv_flags & IFF_SUPP_NOFCS;
}
extern struct pernet_operations __net_initdata loopback_net_ops; extern struct pernet_operations __net_initdata loopback_net_ops;
/* Logging, debugging and troubleshooting/diagnostic helpers. */ /* Logging, debugging and troubleshooting/diagnostic helpers. */
......
...@@ -361,6 +361,7 @@ typedef unsigned char *sk_buff_data_t; ...@@ -361,6 +361,7 @@ typedef unsigned char *sk_buff_data_t;
* ports. * ports.
* @wifi_acked_valid: wifi_acked was set * @wifi_acked_valid: wifi_acked was set
* @wifi_acked: whether frame was acked on wifi or not * @wifi_acked: whether frame was acked on wifi or not
* @no_fcs: Request NIC to treat last 4 bytes as Ethernet FCS
* @dma_cookie: a cookie to one of several possible DMA operations * @dma_cookie: a cookie to one of several possible DMA operations
* done by skb DMA functions * done by skb DMA functions
* @secmark: security marking * @secmark: security marking
...@@ -459,7 +460,8 @@ struct sk_buff { ...@@ -459,7 +460,8 @@ struct sk_buff {
__u8 l4_rxhash:1; __u8 l4_rxhash:1;
__u8 wifi_acked_valid:1; __u8 wifi_acked_valid:1;
__u8 wifi_acked:1; __u8 wifi_acked:1;
/* 10/12 bit hole (depending on ndisc_nodetype presence) */ __u8 no_fcs:1;
/* 9/11 bit hole (depending on ndisc_nodetype presence) */
kmemcheck_bitfield_end(flags2); kmemcheck_bitfield_end(flags2);
#ifdef CONFIG_NET_DMA #ifdef CONFIG_NET_DMA
......
...@@ -615,6 +615,10 @@ enum sock_flags { ...@@ -615,6 +615,10 @@ enum sock_flags {
SOCK_RXQ_OVFL, SOCK_RXQ_OVFL,
SOCK_ZEROCOPY, /* buffers from userspace */ SOCK_ZEROCOPY, /* buffers from userspace */
SOCK_WIFI_STATUS, /* push wifi status to userspace */ SOCK_WIFI_STATUS, /* push wifi status to userspace */
SOCK_NOFCS, /* Tell NIC not to do the Ethernet FCS.
* Will use last 4 bytes of packet sent from
* user-space instead.
*/
}; };
static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
......
...@@ -592,6 +592,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) ...@@ -592,6 +592,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->rxhash = old->rxhash; new->rxhash = old->rxhash;
new->ooo_okay = old->ooo_okay; new->ooo_okay = old->ooo_okay;
new->l4_rxhash = old->l4_rxhash; new->l4_rxhash = old->l4_rxhash;
new->no_fcs = old->no_fcs;
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
new->sp = secpath_get(old->sp); new->sp = secpath_get(old->sp);
#endif #endif
......
...@@ -799,6 +799,11 @@ int sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -799,6 +799,11 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
else else
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break; break;
case SO_NOFCS:
sock_valbool_flag(sk, SOCK_NOFCS, valbool);
break;
default: default:
ret = -ENOPROTOOPT; ret = -ENOPROTOOPT;
break; break;
......
...@@ -1459,6 +1459,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, ...@@ -1459,6 +1459,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
struct net_device *dev; struct net_device *dev;
__be16 proto = 0; __be16 proto = 0;
int err; int err;
int extra_len = 0;
/* /*
* Get and verify the address. * Get and verify the address.
...@@ -1493,8 +1494,16 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, ...@@ -1493,8 +1494,16 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
* raw protocol and you must do your own fragmentation at this level. * raw protocol and you must do your own fragmentation at this level.
*/ */
if (unlikely(sock_flag(sk, SOCK_NOFCS))) {
if (!netif_supports_nofcs(dev)) {
err = -EPROTONOSUPPORT;
goto out_unlock;
}
extra_len = 4; /* We're doing our own CRC */
}
err = -EMSGSIZE; err = -EMSGSIZE;
if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN) if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN + extra_len)
goto out_unlock; goto out_unlock;
if (!skb) { if (!skb) {
...@@ -1526,7 +1535,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, ...@@ -1526,7 +1535,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
goto retry; goto retry;
} }
if (len > (dev->mtu + dev->hard_header_len)) { if (len > (dev->mtu + dev->hard_header_len + extra_len)) {
/* Earlier code assumed this would be a VLAN pkt, /* Earlier code assumed this would be a VLAN pkt,
* double-check this now that we have the actual * double-check this now that we have the actual
* packet in hand. * packet in hand.
...@@ -1548,6 +1557,9 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, ...@@ -1548,6 +1557,9 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
if (err < 0) if (err < 0)
goto out_unlock; goto out_unlock;
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
dev_queue_xmit(skb); dev_queue_xmit(skb);
rcu_read_unlock(); rcu_read_unlock();
return len; return len;
...@@ -2209,6 +2221,7 @@ static int packet_snd(struct socket *sock, ...@@ -2209,6 +2221,7 @@ static int packet_snd(struct socket *sock,
struct packet_sock *po = pkt_sk(sk); struct packet_sock *po = pkt_sk(sk);
unsigned short gso_type = 0; unsigned short gso_type = 0;
int hlen, tlen; int hlen, tlen;
int extra_len = 0;
/* /*
* Get and verify the address. * Get and verify the address.
...@@ -2288,8 +2301,16 @@ static int packet_snd(struct socket *sock, ...@@ -2288,8 +2301,16 @@ static int packet_snd(struct socket *sock,
} }
} }
if (unlikely(sock_flag(sk, SOCK_NOFCS))) {
if (!netif_supports_nofcs(dev)) {
err = -EPROTONOSUPPORT;
goto out_unlock;
}
extra_len = 4; /* We're doing our own CRC */
}
err = -EMSGSIZE; err = -EMSGSIZE;
if (!gso_type && (len > dev->mtu + reserve + VLAN_HLEN)) if (!gso_type && (len > dev->mtu + reserve + VLAN_HLEN + extra_len))
goto out_unlock; goto out_unlock;
err = -ENOBUFS; err = -ENOBUFS;
...@@ -2315,7 +2336,7 @@ static int packet_snd(struct socket *sock, ...@@ -2315,7 +2336,7 @@ static int packet_snd(struct socket *sock,
if (err < 0) if (err < 0)
goto out_free; goto out_free;
if (!gso_type && (len > dev->mtu + reserve)) { if (!gso_type && (len > dev->mtu + reserve + extra_len)) {
/* Earlier code assumed this would be a VLAN pkt, /* Earlier code assumed this would be a VLAN pkt,
* double-check this now that we have the actual * double-check this now that we have the actual
* packet in hand. * packet in hand.
...@@ -2353,6 +2374,9 @@ static int packet_snd(struct socket *sock, ...@@ -2353,6 +2374,9 @@ static int packet_snd(struct socket *sock,
len += vnet_hdr_len; len += vnet_hdr_len;
} }
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
/* /*
* Now send it * Now send it
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment