diff --git a/include/net/sock.h b/include/net/sock.h
index 3784d61d0adc7863b7359d8319042797ab6bc53e..254e220fdb7ff627061edf03b57d6fc6da3d9f69 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1642,12 +1642,14 @@ struct sockcm_cookie {
 	u64 transmit_time;
 	u32 mark;
 	u16 tsflags;
+	struct skb_redundant_info redinfo;
 };
 
 static inline void sockcm_init(struct sockcm_cookie *sockc,
 			       const struct sock *sk)
 {
 	*sockc = (struct sockcm_cookie) { .tsflags = sk->sk_tsflags };
+	memset(&sockc->redinfo, 0, sizeof(sockc->redinfo));
 }
 
 int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg,
@@ -2457,6 +2459,18 @@ static inline void sock_recv_redundant_info(struct msghdr *msg, struct sock *sk,
 		put_cmsg(msg, SOL_SOCKET, SCM_REDUNDANT, sizeof(*sred), sred);
 }
 
+static inline void sock_tx_redundant_info(const struct sock *sk,
+					  struct skb_redundant_info *redinfo,
+					  struct sk_buff *skb)
+{
+	struct skb_redundant_info *sred;
+
+	if (redinfo->io_port) {
+		sred = skb_redinfo(skb);
+		memcpy(sred, redinfo, sizeof(*sred));
+	}
+}
+
 /**
  * sk_eat_skb - Release a skb if it is no longer needed
  * @sk: socket to eat this skb from
diff --git a/net/core/sock.c b/net/core/sock.c
index 371f30e353eaa7c21c61411053395930ffaa5590..6eb478f11381656d2a5114d841d972dedc5e38bb 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2270,6 +2270,7 @@ EXPORT_SYMBOL(sock_alloc_send_skb);
 int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg,
 		     struct sockcm_cookie *sockc)
 {
+	struct skb_redundant_info *cred;
 	u32 tsflags;
 
 	switch (cmsg->cmsg_type) {
@@ -2302,6 +2303,15 @@ int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg,
 	case SCM_RIGHTS:
 	case SCM_CREDENTIALS:
 		break;
+	case SCM_REDUNDANT:
+		if (cmsg->cmsg_len !=
+		    CMSG_LEN(sizeof(struct skb_redundant_info)))
+			return -EINVAL;
+
+		cred = (struct skb_redundant_info *)CMSG_DATA(cmsg);
+		memcpy(&sockc->redinfo, cred,
+		       sizeof(struct skb_redundant_info));
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 3d5c3ea4a4ec2e4dab0c53b094f03566bc6e878b..c74689da8ee7d440d9e87c41ef258a3c53e9b488 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2950,6 +2950,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
 
 	skb_setup_tx_timestamp(skb, sockc.tsflags);
 
+	sock_tx_redundant_info(sk, &sockc.redinfo, skb);
+
 	if (!vnet_hdr.gso_type && (len > dev->mtu + reserve + extra_len) &&
 	    !packet_extra_vlan_len_allowed(dev, skb)) {
 		err = -EMSGSIZE;