162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "queueing.h" 762306a36Sopenharmony_ci#include "timers.h" 862306a36Sopenharmony_ci#include "device.h" 962306a36Sopenharmony_ci#include "peer.h" 1062306a36Sopenharmony_ci#include "socket.h" 1162306a36Sopenharmony_ci#include "messages.h" 1262306a36Sopenharmony_ci#include "cookie.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/uio.h> 1562306a36Sopenharmony_ci#include <linux/inetdevice.h> 1662306a36Sopenharmony_ci#include <linux/socket.h> 1762306a36Sopenharmony_ci#include <net/ip_tunnels.h> 1862306a36Sopenharmony_ci#include <net/udp.h> 1962306a36Sopenharmony_ci#include <net/sock.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void wg_packet_send_handshake_initiation(struct wg_peer *peer) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct message_handshake_initiation packet; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci if (!wg_birthdate_has_expired(atomic64_read(&peer->last_sent_handshake), 2662306a36Sopenharmony_ci REKEY_TIMEOUT)) 2762306a36Sopenharmony_ci return; /* This function is rate limited. */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci atomic64_set(&peer->last_sent_handshake, ktime_get_coarse_boottime_ns()); 3062306a36Sopenharmony_ci net_dbg_ratelimited("%s: Sending handshake initiation to peer %llu (%pISpfsc)\n", 3162306a36Sopenharmony_ci peer->device->dev->name, peer->internal_id, 3262306a36Sopenharmony_ci &peer->endpoint.addr); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (wg_noise_handshake_create_initiation(&packet, &peer->handshake)) { 3562306a36Sopenharmony_ci wg_cookie_add_mac_to_packet(&packet, sizeof(packet), peer); 3662306a36Sopenharmony_ci wg_timers_any_authenticated_packet_traversal(peer); 3762306a36Sopenharmony_ci wg_timers_any_authenticated_packet_sent(peer); 3862306a36Sopenharmony_ci atomic64_set(&peer->last_sent_handshake, 3962306a36Sopenharmony_ci ktime_get_coarse_boottime_ns()); 4062306a36Sopenharmony_ci wg_socket_send_buffer_to_peer(peer, &packet, sizeof(packet), 4162306a36Sopenharmony_ci HANDSHAKE_DSCP); 4262306a36Sopenharmony_ci wg_timers_handshake_initiated(peer); 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_civoid wg_packet_handshake_send_worker(struct work_struct *work) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct wg_peer *peer = container_of(work, struct wg_peer, 4962306a36Sopenharmony_ci transmit_handshake_work); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci wg_packet_send_handshake_initiation(peer); 5262306a36Sopenharmony_ci wg_peer_put(peer); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_civoid wg_packet_send_queued_handshake_initiation(struct wg_peer *peer, 5662306a36Sopenharmony_ci bool is_retry) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci if (!is_retry) 5962306a36Sopenharmony_ci peer->timer_handshake_attempts = 0; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci rcu_read_lock_bh(); 6262306a36Sopenharmony_ci /* We check last_sent_handshake here in addition to the actual function 6362306a36Sopenharmony_ci * we're queueing up, so that we don't queue things if not strictly 6462306a36Sopenharmony_ci * necessary: 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci if (!wg_birthdate_has_expired(atomic64_read(&peer->last_sent_handshake), 6762306a36Sopenharmony_ci REKEY_TIMEOUT) || 6862306a36Sopenharmony_ci unlikely(READ_ONCE(peer->is_dead))) 6962306a36Sopenharmony_ci goto out; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci wg_peer_get(peer); 7262306a36Sopenharmony_ci /* Queues up calling packet_send_queued_handshakes(peer), where we do a 7362306a36Sopenharmony_ci * peer_put(peer) after: 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci if (!queue_work(peer->device->handshake_send_wq, 7662306a36Sopenharmony_ci &peer->transmit_handshake_work)) 7762306a36Sopenharmony_ci /* If the work was already queued, we want to drop the 7862306a36Sopenharmony_ci * extra reference: 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci wg_peer_put(peer); 8162306a36Sopenharmony_ciout: 8262306a36Sopenharmony_ci rcu_read_unlock_bh(); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_civoid wg_packet_send_handshake_response(struct wg_peer *peer) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct message_handshake_response packet; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci atomic64_set(&peer->last_sent_handshake, ktime_get_coarse_boottime_ns()); 9062306a36Sopenharmony_ci net_dbg_ratelimited("%s: Sending handshake response to peer %llu (%pISpfsc)\n", 9162306a36Sopenharmony_ci peer->device->dev->name, peer->internal_id, 9262306a36Sopenharmony_ci &peer->endpoint.addr); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (wg_noise_handshake_create_response(&packet, &peer->handshake)) { 9562306a36Sopenharmony_ci wg_cookie_add_mac_to_packet(&packet, sizeof(packet), peer); 9662306a36Sopenharmony_ci if (wg_noise_handshake_begin_session(&peer->handshake, 9762306a36Sopenharmony_ci &peer->keypairs)) { 9862306a36Sopenharmony_ci wg_timers_session_derived(peer); 9962306a36Sopenharmony_ci wg_timers_any_authenticated_packet_traversal(peer); 10062306a36Sopenharmony_ci wg_timers_any_authenticated_packet_sent(peer); 10162306a36Sopenharmony_ci atomic64_set(&peer->last_sent_handshake, 10262306a36Sopenharmony_ci ktime_get_coarse_boottime_ns()); 10362306a36Sopenharmony_ci wg_socket_send_buffer_to_peer(peer, &packet, 10462306a36Sopenharmony_ci sizeof(packet), 10562306a36Sopenharmony_ci HANDSHAKE_DSCP); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_civoid wg_packet_send_handshake_cookie(struct wg_device *wg, 11162306a36Sopenharmony_ci struct sk_buff *initiating_skb, 11262306a36Sopenharmony_ci __le32 sender_index) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct message_handshake_cookie packet; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci net_dbg_skb_ratelimited("%s: Sending cookie response for denied handshake message for %pISpfsc\n", 11762306a36Sopenharmony_ci wg->dev->name, initiating_skb); 11862306a36Sopenharmony_ci wg_cookie_message_create(&packet, initiating_skb, sender_index, 11962306a36Sopenharmony_ci &wg->cookie_checker); 12062306a36Sopenharmony_ci wg_socket_send_buffer_as_reply_to_skb(wg, initiating_skb, &packet, 12162306a36Sopenharmony_ci sizeof(packet)); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void keep_key_fresh(struct wg_peer *peer) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct noise_keypair *keypair; 12762306a36Sopenharmony_ci bool send; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci rcu_read_lock_bh(); 13062306a36Sopenharmony_ci keypair = rcu_dereference_bh(peer->keypairs.current_keypair); 13162306a36Sopenharmony_ci send = keypair && READ_ONCE(keypair->sending.is_valid) && 13262306a36Sopenharmony_ci (atomic64_read(&keypair->sending_counter) > REKEY_AFTER_MESSAGES || 13362306a36Sopenharmony_ci (keypair->i_am_the_initiator && 13462306a36Sopenharmony_ci wg_birthdate_has_expired(keypair->sending.birthdate, REKEY_AFTER_TIME))); 13562306a36Sopenharmony_ci rcu_read_unlock_bh(); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (unlikely(send)) 13862306a36Sopenharmony_ci wg_packet_send_queued_handshake_initiation(peer, false); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic unsigned int calculate_skb_padding(struct sk_buff *skb) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci unsigned int padded_size, last_unit = skb->len; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (unlikely(!PACKET_CB(skb)->mtu)) 14662306a36Sopenharmony_ci return ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE) - last_unit; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* We do this modulo business with the MTU, just in case the networking 14962306a36Sopenharmony_ci * layer gives us a packet that's bigger than the MTU. In that case, we 15062306a36Sopenharmony_ci * wouldn't want the final subtraction to overflow in the case of the 15162306a36Sopenharmony_ci * padded_size being clamped. Fortunately, that's very rarely the case, 15262306a36Sopenharmony_ci * so we optimize for that not happening. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci if (unlikely(last_unit > PACKET_CB(skb)->mtu)) 15562306a36Sopenharmony_ci last_unit %= PACKET_CB(skb)->mtu; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci padded_size = min(PACKET_CB(skb)->mtu, 15862306a36Sopenharmony_ci ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE)); 15962306a36Sopenharmony_ci return padded_size - last_unit; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci unsigned int padding_len, plaintext_len, trailer_len; 16562306a36Sopenharmony_ci struct scatterlist sg[MAX_SKB_FRAGS + 8]; 16662306a36Sopenharmony_ci struct message_data *header; 16762306a36Sopenharmony_ci struct sk_buff *trailer; 16862306a36Sopenharmony_ci int num_frags; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Force hash calculation before encryption so that flow analysis is 17162306a36Sopenharmony_ci * consistent over the inner packet. 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_ci skb_get_hash(skb); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Calculate lengths. */ 17662306a36Sopenharmony_ci padding_len = calculate_skb_padding(skb); 17762306a36Sopenharmony_ci trailer_len = padding_len + noise_encrypted_len(0); 17862306a36Sopenharmony_ci plaintext_len = skb->len + padding_len; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Expand data section to have room for padding and auth tag. */ 18162306a36Sopenharmony_ci num_frags = skb_cow_data(skb, trailer_len, &trailer); 18262306a36Sopenharmony_ci if (unlikely(num_frags < 0 || num_frags > ARRAY_SIZE(sg))) 18362306a36Sopenharmony_ci return false; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Set the padding to zeros, and make sure it and the auth tag are part 18662306a36Sopenharmony_ci * of the skb. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci memset(skb_tail_pointer(trailer), 0, padding_len); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* Expand head section to have room for our header and the network 19162306a36Sopenharmony_ci * stack's headers. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci if (unlikely(skb_cow_head(skb, DATA_PACKET_HEAD_ROOM) < 0)) 19462306a36Sopenharmony_ci return false; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* Finalize checksum calculation for the inner packet, if required. */ 19762306a36Sopenharmony_ci if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL && 19862306a36Sopenharmony_ci skb_checksum_help(skb))) 19962306a36Sopenharmony_ci return false; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* Only after checksumming can we safely add on the padding at the end 20262306a36Sopenharmony_ci * and the header. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci skb_set_inner_network_header(skb, 0); 20562306a36Sopenharmony_ci header = (struct message_data *)skb_push(skb, sizeof(*header)); 20662306a36Sopenharmony_ci header->header.type = cpu_to_le32(MESSAGE_DATA); 20762306a36Sopenharmony_ci header->key_idx = keypair->remote_index; 20862306a36Sopenharmony_ci header->counter = cpu_to_le64(PACKET_CB(skb)->nonce); 20962306a36Sopenharmony_ci pskb_put(skb, trailer, trailer_len); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Now we can encrypt the scattergather segments */ 21262306a36Sopenharmony_ci sg_init_table(sg, num_frags); 21362306a36Sopenharmony_ci if (skb_to_sgvec(skb, sg, sizeof(struct message_data), 21462306a36Sopenharmony_ci noise_encrypted_len(plaintext_len)) <= 0) 21562306a36Sopenharmony_ci return false; 21662306a36Sopenharmony_ci return chacha20poly1305_encrypt_sg_inplace(sg, plaintext_len, NULL, 0, 21762306a36Sopenharmony_ci PACKET_CB(skb)->nonce, 21862306a36Sopenharmony_ci keypair->sending.key); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_civoid wg_packet_send_keepalive(struct wg_peer *peer) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct sk_buff *skb; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (skb_queue_empty(&peer->staged_packet_queue)) { 22662306a36Sopenharmony_ci skb = alloc_skb(DATA_PACKET_HEAD_ROOM + MESSAGE_MINIMUM_LENGTH, 22762306a36Sopenharmony_ci GFP_ATOMIC); 22862306a36Sopenharmony_ci if (unlikely(!skb)) 22962306a36Sopenharmony_ci return; 23062306a36Sopenharmony_ci skb_reserve(skb, DATA_PACKET_HEAD_ROOM); 23162306a36Sopenharmony_ci skb->dev = peer->device->dev; 23262306a36Sopenharmony_ci PACKET_CB(skb)->mtu = skb->dev->mtu; 23362306a36Sopenharmony_ci skb_queue_tail(&peer->staged_packet_queue, skb); 23462306a36Sopenharmony_ci net_dbg_ratelimited("%s: Sending keepalive packet to peer %llu (%pISpfsc)\n", 23562306a36Sopenharmony_ci peer->device->dev->name, peer->internal_id, 23662306a36Sopenharmony_ci &peer->endpoint.addr); 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci wg_packet_send_staged_packets(peer); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void wg_packet_create_data_done(struct wg_peer *peer, struct sk_buff *first) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct sk_buff *skb, *next; 24562306a36Sopenharmony_ci bool is_keepalive, data_sent = false; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci wg_timers_any_authenticated_packet_traversal(peer); 24862306a36Sopenharmony_ci wg_timers_any_authenticated_packet_sent(peer); 24962306a36Sopenharmony_ci skb_list_walk_safe(first, skb, next) { 25062306a36Sopenharmony_ci is_keepalive = skb->len == message_data_len(0); 25162306a36Sopenharmony_ci if (likely(!wg_socket_send_skb_to_peer(peer, skb, 25262306a36Sopenharmony_ci PACKET_CB(skb)->ds) && !is_keepalive)) 25362306a36Sopenharmony_ci data_sent = true; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (likely(data_sent)) 25762306a36Sopenharmony_ci wg_timers_data_sent(peer); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci keep_key_fresh(peer); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_civoid wg_packet_tx_worker(struct work_struct *work) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct wg_peer *peer = container_of(work, struct wg_peer, transmit_packet_work); 26562306a36Sopenharmony_ci struct noise_keypair *keypair; 26662306a36Sopenharmony_ci enum packet_state state; 26762306a36Sopenharmony_ci struct sk_buff *first; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci while ((first = wg_prev_queue_peek(&peer->tx_queue)) != NULL && 27062306a36Sopenharmony_ci (state = atomic_read_acquire(&PACKET_CB(first)->state)) != 27162306a36Sopenharmony_ci PACKET_STATE_UNCRYPTED) { 27262306a36Sopenharmony_ci wg_prev_queue_drop_peeked(&peer->tx_queue); 27362306a36Sopenharmony_ci keypair = PACKET_CB(first)->keypair; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (likely(state == PACKET_STATE_CRYPTED)) 27662306a36Sopenharmony_ci wg_packet_create_data_done(peer, first); 27762306a36Sopenharmony_ci else 27862306a36Sopenharmony_ci kfree_skb_list(first); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci wg_noise_keypair_put(keypair, false); 28162306a36Sopenharmony_ci wg_peer_put(peer); 28262306a36Sopenharmony_ci if (need_resched()) 28362306a36Sopenharmony_ci cond_resched(); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_civoid wg_packet_encrypt_worker(struct work_struct *work) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct crypt_queue *queue = container_of(work, struct multicore_worker, 29062306a36Sopenharmony_ci work)->ptr; 29162306a36Sopenharmony_ci struct sk_buff *first, *skb, *next; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci while ((first = ptr_ring_consume_bh(&queue->ring)) != NULL) { 29462306a36Sopenharmony_ci enum packet_state state = PACKET_STATE_CRYPTED; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci skb_list_walk_safe(first, skb, next) { 29762306a36Sopenharmony_ci if (likely(encrypt_packet(skb, 29862306a36Sopenharmony_ci PACKET_CB(first)->keypair))) { 29962306a36Sopenharmony_ci wg_reset_packet(skb, true); 30062306a36Sopenharmony_ci } else { 30162306a36Sopenharmony_ci state = PACKET_STATE_DEAD; 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci wg_queue_enqueue_per_peer_tx(first, state); 30662306a36Sopenharmony_ci if (need_resched()) 30762306a36Sopenharmony_ci cond_resched(); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void wg_packet_create_data(struct wg_peer *peer, struct sk_buff *first) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct wg_device *wg = peer->device; 31462306a36Sopenharmony_ci int ret = -EINVAL; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci rcu_read_lock_bh(); 31762306a36Sopenharmony_ci if (unlikely(READ_ONCE(peer->is_dead))) 31862306a36Sopenharmony_ci goto err; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci ret = wg_queue_enqueue_per_device_and_peer(&wg->encrypt_queue, &peer->tx_queue, first, 32162306a36Sopenharmony_ci wg->packet_crypt_wq); 32262306a36Sopenharmony_ci if (unlikely(ret == -EPIPE)) 32362306a36Sopenharmony_ci wg_queue_enqueue_per_peer_tx(first, PACKET_STATE_DEAD); 32462306a36Sopenharmony_cierr: 32562306a36Sopenharmony_ci rcu_read_unlock_bh(); 32662306a36Sopenharmony_ci if (likely(!ret || ret == -EPIPE)) 32762306a36Sopenharmony_ci return; 32862306a36Sopenharmony_ci wg_noise_keypair_put(PACKET_CB(first)->keypair, false); 32962306a36Sopenharmony_ci wg_peer_put(peer); 33062306a36Sopenharmony_ci kfree_skb_list(first); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_civoid wg_packet_purge_staged_packets(struct wg_peer *peer) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci spin_lock_bh(&peer->staged_packet_queue.lock); 33662306a36Sopenharmony_ci DEV_STATS_ADD(peer->device->dev, tx_dropped, 33762306a36Sopenharmony_ci peer->staged_packet_queue.qlen); 33862306a36Sopenharmony_ci __skb_queue_purge(&peer->staged_packet_queue); 33962306a36Sopenharmony_ci spin_unlock_bh(&peer->staged_packet_queue.lock); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_civoid wg_packet_send_staged_packets(struct wg_peer *peer) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct noise_keypair *keypair; 34562306a36Sopenharmony_ci struct sk_buff_head packets; 34662306a36Sopenharmony_ci struct sk_buff *skb; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* Steal the current queue into our local one. */ 34962306a36Sopenharmony_ci __skb_queue_head_init(&packets); 35062306a36Sopenharmony_ci spin_lock_bh(&peer->staged_packet_queue.lock); 35162306a36Sopenharmony_ci skb_queue_splice_init(&peer->staged_packet_queue, &packets); 35262306a36Sopenharmony_ci spin_unlock_bh(&peer->staged_packet_queue.lock); 35362306a36Sopenharmony_ci if (unlikely(skb_queue_empty(&packets))) 35462306a36Sopenharmony_ci return; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* First we make sure we have a valid reference to a valid key. */ 35762306a36Sopenharmony_ci rcu_read_lock_bh(); 35862306a36Sopenharmony_ci keypair = wg_noise_keypair_get( 35962306a36Sopenharmony_ci rcu_dereference_bh(peer->keypairs.current_keypair)); 36062306a36Sopenharmony_ci rcu_read_unlock_bh(); 36162306a36Sopenharmony_ci if (unlikely(!keypair)) 36262306a36Sopenharmony_ci goto out_nokey; 36362306a36Sopenharmony_ci if (unlikely(!READ_ONCE(keypair->sending.is_valid))) 36462306a36Sopenharmony_ci goto out_nokey; 36562306a36Sopenharmony_ci if (unlikely(wg_birthdate_has_expired(keypair->sending.birthdate, 36662306a36Sopenharmony_ci REJECT_AFTER_TIME))) 36762306a36Sopenharmony_ci goto out_invalid; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* After we know we have a somewhat valid key, we now try to assign 37062306a36Sopenharmony_ci * nonces to all of the packets in the queue. If we can't assign nonces 37162306a36Sopenharmony_ci * for all of them, we just consider it a failure and wait for the next 37262306a36Sopenharmony_ci * handshake. 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci skb_queue_walk(&packets, skb) { 37562306a36Sopenharmony_ci /* 0 for no outer TOS: no leak. TODO: at some later point, we 37662306a36Sopenharmony_ci * might consider using flowi->tos as outer instead. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci PACKET_CB(skb)->ds = ip_tunnel_ecn_encap(0, ip_hdr(skb), skb); 37962306a36Sopenharmony_ci PACKET_CB(skb)->nonce = 38062306a36Sopenharmony_ci atomic64_inc_return(&keypair->sending_counter) - 1; 38162306a36Sopenharmony_ci if (unlikely(PACKET_CB(skb)->nonce >= REJECT_AFTER_MESSAGES)) 38262306a36Sopenharmony_ci goto out_invalid; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci packets.prev->next = NULL; 38662306a36Sopenharmony_ci wg_peer_get(keypair->entry.peer); 38762306a36Sopenharmony_ci PACKET_CB(packets.next)->keypair = keypair; 38862306a36Sopenharmony_ci wg_packet_create_data(peer, packets.next); 38962306a36Sopenharmony_ci return; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ciout_invalid: 39262306a36Sopenharmony_ci WRITE_ONCE(keypair->sending.is_valid, false); 39362306a36Sopenharmony_ciout_nokey: 39462306a36Sopenharmony_ci wg_noise_keypair_put(keypair, false); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* We orphan the packets if we're waiting on a handshake, so that they 39762306a36Sopenharmony_ci * don't block a socket's pool. 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_ci skb_queue_walk(&packets, skb) 40062306a36Sopenharmony_ci skb_orphan(skb); 40162306a36Sopenharmony_ci /* Then we put them back on the top of the queue. We're not too 40262306a36Sopenharmony_ci * concerned about accidentally getting things a little out of order if 40362306a36Sopenharmony_ci * packets are being added really fast, because this queue is for before 40462306a36Sopenharmony_ci * packets can even be sent and it's small anyway. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci spin_lock_bh(&peer->staged_packet_queue.lock); 40762306a36Sopenharmony_ci skb_queue_splice(&packets, &peer->staged_packet_queue); 40862306a36Sopenharmony_ci spin_unlock_bh(&peer->staged_packet_queue.lock); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* If we're exiting because there's something wrong with the key, it 41162306a36Sopenharmony_ci * means we should initiate a new handshake. 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ci wg_packet_send_queued_handshake_initiation(peer, false); 41462306a36Sopenharmony_ci} 415