@@ -68,6 +68,7 @@
#define SCM_TIMESTAMPING SO_TIMESTAMPING
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
@@ -61,5 +61,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_SOCKET_H */
@@ -61,5 +61,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* __ASM_AVR32_SOCKET_H */
@@ -63,6 +63,7 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_SOCKET_H */
@@ -61,6 +61,7 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_SOCKET_H */
@@ -61,5 +61,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_SOCKET_H */
@@ -70,5 +70,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_IA64_SOCKET_H */
@@ -61,5 +61,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_M32R_SOCKET_H */
@@ -61,5 +61,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_SOCKET_H */
@@ -81,6 +81,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
#define SCM_TIMESTAMPING SO_TIMESTAMPING
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#ifdef __KERNEL__
@@ -61,5 +61,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_SOCKET_H */
@@ -60,6 +60,7 @@
#define SCM_TIMESTAMPING SO_TIMESTAMPING
#define SO_RXQ_OVFL 0x4021
+#define SO_NOFCS 0x4022
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
@@ -68,5 +68,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_POWERPC_SOCKET_H */
@@ -69,5 +69,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _ASM_SOCKET_H */
@@ -57,6 +57,7 @@
#define SCM_TIMESTAMPING SO_TIMESTAMPING
#define SO_RXQ_OVFL 0x0024
+#define SO_NOFCS 0x0025
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
@@ -72,5 +72,6 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+#define SO_NOFCS 41
#endif /* _XTENSA_SOCKET_H */
@@ -64,4 +64,11 @@
#define SO_DOMAIN 39
#define SO_RXQ_OVFL 40
+
+/* Instruct lower device to not calculate the frame
+ * checksum. Useful for generating Ethernet frames
+ * with custom checksums.
+ */
+#define SO_NOFCS 41
+
#endif /* __ASM_GENERIC_SOCKET_H */
@@ -307,6 +307,8 @@ typedef unsigned char *sk_buff_data_t;
* @peeked: this packet has been seen already, so stats have been
* done for it, don't do them again
* @nf_trace: netfilter packet trace flag
+ * @use_specified_ether_crc: skb is Ethernet frame with FCS already
+ * appended. Use that FCS. Requires special support in NIC.
* @nfctinfo: Relationship of this skb to the connection
* @nfct_reasm: netfilter conntrack re-assembly pointer
* @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
@@ -396,7 +398,8 @@ struct sk_buff {
#ifdef CONFIG_IPV6_NDISC_NODETYPE
__u8 ndisc_nodetype:2;
#endif
- __u8 ooo_okay:1;
+ __u8 ooo_okay:1,
+ use_specified_ether_crc:1;
kmemcheck_bitfield_end(flags2);
/* 0/13 bit hole */
@@ -563,6 +563,12 @@ enum sock_flags {
SOCK_TIMESTAMPING_SYS_HARDWARE, /* %SOF_TIMESTAMPING_SYS_HARDWARE */
SOCK_FASYNC, /* fasync() active */
SOCK_RXQ_OVFL,
+ SOCK_DONT_DO_LL_FCS, /* Tell NIC not to do the Ethernet FCS.
+ * Will use last 4 bytes of packet sent from
+ * user-space instead. Requires special
+ * support in NIC.
+ */
+
};
static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -541,6 +541,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->tc_verd = old->tc_verd;
#endif
#endif
+ new->use_specified_ether_crc = old->use_specified_ether_crc;
new->vlan_tci = old->vlan_tci;
skb_copy_secmark(new, old);
@@ -641,6 +641,13 @@ set_rcvbuf:
sock_warn_obsolete_bsdism("setsockopt");
break;
+ case SO_NOFCS:
+ if (valbool)
+ sk->sk_flags |= SOCK_DONT_DO_LL_FCS;
+ else
+ sk->sk_flags &= ~(SOCK_DONT_DO_LL_FCS);
+ break;
+
case SO_PASSCRED:
if (valbool)
set_bit(SOCK_PASSCRED, &sock->flags);
@@ -430,6 +430,10 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
struct net_device *dev;
__be16 proto = 0;
int err;
+ int fcs_len = 0;
+
+ if (unlikely(sk->sk_flags & SOCK_DONT_DO_LL_FCS))
+ fcs_len = 4; /* We're doing our own FCS */
/*
* Get and verify the address.
@@ -465,7 +469,7 @@ retry:
*/
err = -EMSGSIZE;
- if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN)
+ if (len > dev->mtu + dev->hard_header_len + VLAN_HLEN + fcs_len)
goto out_unlock;
if (!skb) {
@@ -518,6 +522,9 @@ retry:
if (err < 0)
goto out_unlock;
+ if (unlikely(sk->sk_flags & SOCK_DONT_DO_LL_FCS))
+ skb->use_specified_ether_crc = 1;
+
dev_queue_xmit(skb);
rcu_read_unlock();
return len;
@@ -1134,6 +1141,10 @@ static int packet_snd(struct socket *sock,
int vnet_hdr_len;
struct packet_sock *po = pkt_sk(sk);
unsigned short gso_type = 0;
+ int fcs_len = 0;
+
+ if (unlikely(sk->sk_flags & SOCK_DONT_DO_LL_FCS))
+ fcs_len = 4; /* We're doing our own Ethernet FCS */
/*
* Get and verify the address.
@@ -1215,7 +1226,7 @@ static int packet_snd(struct socket *sock,
}
err = -EMSGSIZE;
- if (!gso_type && (len > dev->mtu + reserve + VLAN_HLEN))
+ if (!gso_type && (len > dev->mtu + reserve + VLAN_HLEN + fcs_len))
goto out_unlock;
err = -ENOBUFS;
@@ -1278,6 +1289,9 @@ static int packet_snd(struct socket *sock,
len += vnet_hdr_len;
}
+ if (unlikely(sk->sk_flags & SOCK_DONT_DO_LL_FCS))
+ skb->use_specified_ether_crc = 1;
+
/*
* Now send it
*/