summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/receive.c15
-rw-r--r--src/send.c27
-rw-r--r--src/socket.c8
-rw-r--r--src/socket.h4
4 files changed, 38 insertions, 16 deletions
diff --git a/src/receive.c b/src/receive.c
index 5dc9c5b..fee2f21 100644
--- a/src/receive.c
+++ b/src/receive.c
@@ -6,6 +6,7 @@
#include "timers.h"
#include "messages.h"
#include "cookie.h"
+#include <net/ip_tunnels.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
@@ -175,6 +176,11 @@ void packet_process_queued_handshake_packets(struct work_struct *work)
}
}
+struct packet_cb {
+ u8 ds;
+};
+#define PACKET_CB(skb) ((struct packet_cb *)skb->cb)
+
static void receive_data_packet(struct sk_buff *skb, struct wireguard_peer *peer, struct sockaddr_storage *addr, bool used_new_key, int err)
{
struct net_device *dev;
@@ -214,9 +220,11 @@ static void receive_data_packet(struct sk_buff *skb, struct wireguard_peer *peer
skb->dev = dev;
skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (ip_hdr(skb)->version == 4)
+ if (ip_hdr(skb)->version == 4) {
skb->protocol = htons(ETH_P_IP);
- else if (ip_hdr(skb)->version == 6) {
+ if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
+ IP_ECN_set_ce(ip_hdr(skb));
+ } else if (ip_hdr(skb)->version == 6) {
if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
++dev->stats.rx_errors;
++dev->stats.rx_length_errors;
@@ -224,6 +232,8 @@ static void receive_data_packet(struct sk_buff *skb, struct wireguard_peer *peer
goto packet_processed;
}
skb->protocol = htons(ETH_P_IPV6);
+ if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
+ IP6_ECN_set_ce(skb, ipv6_hdr(skb));
} else {
++dev->stats.rx_errors;
++dev->stats.rx_length_errors;
@@ -294,6 +304,7 @@ void packet_receive(struct wireguard_device *wg, struct sk_buff *skb)
queue_work(wg->workqueue, &wg->incoming_handshakes_work);
break;
case MESSAGE_DATA:
+ PACKET_CB(skb)->ds = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
packet_consume_data(skb, offset, wg, receive_data_packet);
break;
default:
diff --git a/src/send.c b/src/send.c
index 84eb6da..29a8f67 100644
--- a/src/send.c
+++ b/src/send.c
@@ -9,6 +9,7 @@
#include "cookie.h"
#include <net/udp.h>
#include <net/sock.h>
+#include <net/ip_tunnels.h>
#include <linux/uio.h>
#include <linux/inetdevice.h>
#include <linux/socket.h>
@@ -128,6 +129,13 @@ struct packet_bundle {
struct sk_buff *first;
};
+struct packet_cb {
+ struct packet_bundle *bundle;
+ struct packet_bundle data;
+ u8 ds;
+};
+#define PACKET_CB(skb) ((struct packet_cb *)skb->cb)
+
static inline void send_off_bundle(struct packet_bundle *bundle, struct wireguard_peer *peer)
{
struct sk_buff *skb, *next;
@@ -139,7 +147,7 @@ static inline void send_off_bundle(struct packet_bundle *bundle, struct wireguar
* consumes the packet before the top of the loop comes again. */
next = skb->next;
is_keepalive = skb->len == message_data_len(0);
- if (likely(!socket_send_skb_to_peer(peer, skb, 0 /* TODO: Should we copy the DSCP value from the enclosed packet? */) && !is_keepalive))
+ if (likely(!socket_send_skb_to_peer(peer, skb, PACKET_CB(skb)->ds) && !is_keepalive))
data_sent = true;
}
if (likely(data_sent))
@@ -148,11 +156,10 @@ static inline void send_off_bundle(struct packet_bundle *bundle, struct wireguar
static void message_create_data_done(struct sk_buff *skb, struct wireguard_peer *peer)
{
- struct packet_bundle *bundle = *((struct packet_bundle **)skb->cb);
/* A packet completed successfully, so we deincrement the counter of packets
* remaining, and if we hit zero we can send it off. */
- if (atomic_dec_and_test(&bundle->count))
- send_off_bundle(bundle, peer);
+ if (atomic_dec_and_test(&PACKET_CB(skb)->bundle->count))
+ send_off_bundle(PACKET_CB(skb)->bundle, peer);
keep_key_fresh(peer);
}
@@ -181,7 +188,8 @@ int packet_send_queue(struct wireguard_peer *peer)
/* The first pointer of the control block is a pointer to the bundle
* and after that, in the first packet only, is where we actually store
* the bundle data. This saves us a call to kmalloc. */
- bundle = (struct packet_bundle *)(first->cb + sizeof(void *));
+ BUILD_BUG_ON(sizeof(struct packet_cb) > sizeof(skb->cb));
+ bundle = &PACKET_CB(first)->data;
atomic_set(&bundle->count, skb_queue_len(&local_queue));
bundle->first = first;
@@ -195,7 +203,10 @@ int packet_send_queue(struct wireguard_peer *peer)
next = skb->next;
/* We set the first pointer in cb to point to the bundle data. */
- *(struct packet_bundle **)skb->cb = bundle;
+ PACKET_CB(skb)->bundle = bundle;
+
+ /* Extract the TOS value before encryption, for ECN encapsulation. */
+ PACKET_CB(skb)->ds = ip_tunnel_ecn_encap(0 /* No outer TOS: no leak. TODO: should we use flowi->tos as outer? */, ip_hdr(skb), skb);
/* We submit it for encryption and sending. */
switch (packet_create_data(skb, peer, message_create_data_done, parallel)) {
@@ -248,8 +259,8 @@ int packet_send_queue(struct wireguard_peer *peer)
/* If it's the first one that failed, we need to move the bundle data
* to the next packet. Then, all subsequent assignments of the bundle
* pointer will be to the moved data. */
- *(struct packet_bundle *)(next->cb + sizeof(void *)) = *bundle;
- bundle = (struct packet_bundle *)(next->cb + sizeof(void *));
+ PACKET_CB(next)->data = *bundle;
+ bundle = &PACKET_CB(next)->data;
bundle->first = next;
}
/* We remove the skb from the list and free it. */
diff --git a/src/socket.c b/src/socket.c
index 4720d4a..1299404 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -234,7 +234,7 @@ out:
}
-int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 dscp)
+int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 ds)
{
struct net_device *dev = netdev_pub(peer->device);
struct dst_entry *dst;
@@ -255,7 +255,7 @@ int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8
rcu_read_lock();
read_lock_bh(&peer->endpoint_lock);
- ret = send(dev, skb, dst, &peer->endpoint_flow.fl4, &peer->endpoint_flow.fl6, &peer->endpoint_addr, rcu_dereference(peer->device->sock4), rcu_dereference(peer->device->sock6), dscp);
+ ret = send(dev, skb, dst, &peer->endpoint_flow.fl4, &peer->endpoint_flow.fl6, &peer->endpoint_addr, rcu_dereference(peer->device->sock4), rcu_dereference(peer->device->sock6), ds);
if (!ret)
peer->tx_bytes += skb_len;
@@ -265,14 +265,14 @@ int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8
return ret;
}
-int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *buffer, size_t len, u8 dscp)
+int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *buffer, size_t len, u8 ds)
{
struct sk_buff *skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
skb_reserve(skb, SKB_HEADER_LEN);
memcpy(skb_put(skb, len), buffer, len);
- return socket_send_skb_to_peer(peer, skb, dscp);
+ return socket_send_skb_to_peer(peer, skb, ds);
}
static int send_to_sockaddr(struct sk_buff *skb, struct wireguard_device *wg, struct sockaddr_storage *addr, struct sock *sock4, struct sock *sock6)
diff --git a/src/socket.h b/src/socket.h
index 327246f..2fe1bbf 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -14,8 +14,8 @@ struct wireguard_device;
int socket_init(struct wireguard_device *wg);
void socket_uninit(struct wireguard_device *wg);
-int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *data, size_t len, u8 dscp);
-int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 dscp);
+int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *data, size_t len, u8 ds);
+int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 ds);
int socket_send_buffer_as_reply_to_skb(struct sk_buff *in_skb, void *out_buffer, size_t len, struct wireguard_device *wg);
int socket_addr_from_skb(struct sockaddr_storage *sockaddr, struct sk_buff *skb);