diff options
-rw-r--r-- | src/receive.c | 15 | ||||
-rw-r--r-- | src/send.c | 27 | ||||
-rw-r--r-- | src/socket.c | 8 | ||||
-rw-r--r-- | src/socket.h | 4 |
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: @@ -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); |