Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /* QUIC kernel implementation
3 : * (C) Copyright Red Hat Corp. 2023
4 : *
5 : * This file is part of the QUIC kernel implementation
6 : *
7 : * Initialization/cleanup for QUIC protocol support.
8 : *
9 : * Written or modified by:
10 : * Xin Long <lucien.xin@gmail.com>
11 : */
12 :
13 : #include <linux/quic.h>
14 : #include <net/sock.h>
15 :
16 : #include "common.h"
17 : #include "connid.h"
18 :
19 : /* Lookup a source connection ID (scid) in the global source connection ID hash table. */
20 6573255 : struct quic_conn_id *quic_conn_id_lookup(struct net *net, u8 *scid, u32 len)
21 : {
22 6573255 : struct quic_hash_head *head = quic_source_conn_id_head(net, scid);
23 6573186 : struct quic_source_conn_id *s_conn_id;
24 :
25 6573186 : spin_lock(&head->s_lock);
26 14797196 : hlist_for_each_entry(s_conn_id, &head->head, node) {
27 8221650 : if (net == sock_net(s_conn_id->sk) && s_conn_id->common.id.len == len &&
28 16442878 : !memcmp(scid, &s_conn_id->common.id.data, s_conn_id->common.id.len))
29 : break;
30 : }
31 :
32 6574318 : spin_unlock(&head->s_lock);
33 6574346 : return &s_conn_id->common.id;
34 : }
35 :
36 : /* Check if a given stateless reset token exists in any connection ID in the connection ID set. */
37 0 : bool quic_conn_id_token_exists(struct quic_conn_id_set *id_set, u8 *token)
38 : {
39 0 : struct quic_common_conn_id *common;
40 0 : struct quic_dest_conn_id *dcid;
41 :
42 0 : dcid = (struct quic_dest_conn_id *)id_set->active;
43 0 : if (!memcmp(dcid->token, token, QUIC_CONN_ID_TOKEN_LEN)) /* Fast path. */
44 : return true;
45 :
46 0 : list_for_each_entry(common, &id_set->head, list) {
47 0 : dcid = (struct quic_dest_conn_id *)common;
48 0 : if (common == id_set->active)
49 0 : continue;
50 0 : if (!memcmp(dcid->token, token, QUIC_CONN_ID_TOKEN_LEN))
51 : return true;
52 : }
53 : return false;
54 : }
55 :
56 6975 : static void quic_source_conn_id_free_rcu(struct rcu_head *head)
57 : {
58 6975 : struct quic_source_conn_id *s_conn_id;
59 :
60 6975 : s_conn_id = container_of(head, struct quic_source_conn_id, rcu);
61 6975 : kfree(s_conn_id);
62 6981 : }
63 :
64 6985 : static void quic_source_conn_id_free(struct quic_source_conn_id *s_conn_id)
65 : {
66 6985 : u8 *data = s_conn_id->common.id.data;
67 6985 : struct quic_hash_head *head;
68 :
69 6985 : if (!hlist_unhashed(&s_conn_id->node)) {
70 6985 : head = quic_source_conn_id_head(sock_net(s_conn_id->sk), data);
71 6985 : spin_lock_bh(&head->s_lock);
72 6986 : hlist_del_init(&s_conn_id->node);
73 6986 : spin_unlock_bh(&head->s_lock);
74 : }
75 :
76 : /* Freeing is deferred via RCU to avoid use-after-free during concurrent lookups. */
77 6986 : call_rcu(&s_conn_id->rcu, quic_source_conn_id_free_rcu);
78 6987 : }
79 :
80 12922 : static void quic_conn_id_del(struct quic_common_conn_id *common)
81 : {
82 12922 : list_del(&common->list);
83 12925 : if (!common->hashed) {
84 5940 : kfree(common);
85 5940 : return;
86 : }
87 6985 : quic_source_conn_id_free((struct quic_source_conn_id *)common);
88 : }
89 :
90 : /* Add a connection ID with sequence number and associated private data to the connection ID set. */
91 13467 : int quic_conn_id_add(struct quic_conn_id_set *id_set,
92 : struct quic_conn_id *conn_id, u32 number, void *data)
93 : {
94 13467 : struct quic_source_conn_id *s_conn_id;
95 13467 : struct quic_dest_conn_id *d_conn_id;
96 13467 : struct quic_common_conn_id *common;
97 13467 : struct quic_hash_head *head;
98 13467 : struct list_head *list;
99 :
100 : /* Locate insertion point to keep list ordered by number. */
101 13467 : list = &id_set->head;
102 49093 : list_for_each_entry(common, list, list) {
103 37445 : if (number == common->number)
104 : return 0; /* Ignore if it is already exists on the list. */
105 36911 : if (number < common->number) {
106 : list = &common->list;
107 : break;
108 : }
109 : }
110 :
111 12933 : if (conn_id->len > QUIC_CONN_ID_MAX_LEN)
112 : return -EINVAL;
113 12933 : common = kzalloc(id_set->entry_size, GFP_ATOMIC);
114 12933 : if (!common)
115 : return -ENOMEM;
116 12933 : common->id = *conn_id;
117 12933 : common->number = number;
118 12933 : if (id_set->entry_size == sizeof(struct quic_dest_conn_id)) {
119 : /* For destination connection IDs, copy the stateless reset token if available. */
120 5944 : if (data) {
121 4825 : d_conn_id = (struct quic_dest_conn_id *)common;
122 9650 : memcpy(d_conn_id->token, data, QUIC_CONN_ID_TOKEN_LEN);
123 : }
124 : } else {
125 : /* For source connection IDs, mark as hashed and insert into the global source
126 : * connection ID hashtable.
127 : */
128 6989 : common->hashed = 1;
129 6989 : s_conn_id = (struct quic_source_conn_id *)common;
130 6989 : s_conn_id->sk = data;
131 :
132 6989 : head = quic_source_conn_id_head(sock_net(s_conn_id->sk), common->id.data);
133 6989 : spin_lock_bh(&head->s_lock);
134 6989 : hlist_add_head(&s_conn_id->node, &head->head);
135 6989 : spin_unlock_bh(&head->s_lock);
136 : }
137 12933 : list_add_tail(&common->list, list);
138 :
139 12933 : if (number == quic_conn_id_last_number(id_set) + 1) {
140 11638 : if (!id_set->active)
141 2238 : id_set->active = common;
142 11638 : id_set->count++;
143 :
144 : /* Increment count for consecutive following IDs. */
145 12921 : list_for_each_entry_continue(common, &id_set->head, list) {
146 1286 : if (common->number != ++number)
147 : break;
148 1283 : id_set->count++;
149 : }
150 : }
151 : return 0;
152 : }
153 :
154 : /* Remove connection IDs from the set with sequence numbers less than or equal to a number. */
155 275 : void quic_conn_id_remove(struct quic_conn_id_set *id_set, u32 number)
156 : {
157 275 : struct quic_common_conn_id *common, *tmp;
158 275 : struct list_head *list;
159 :
160 275 : list = &id_set->head;
161 2061 : list_for_each_entry_safe(common, tmp, list, list) {
162 1786 : if (common->number <= number) {
163 284 : if (id_set->active == common)
164 226 : id_set->active = tmp;
165 284 : quic_conn_id_del(common);
166 284 : id_set->count--;
167 : }
168 : }
169 275 : }
170 :
171 96 : struct quic_conn_id *quic_conn_id_find(struct quic_conn_id_set *id_set, u32 number)
172 : {
173 96 : struct quic_common_conn_id *common;
174 :
175 332 : list_for_each_entry(common, &id_set->head, list)
176 324 : if (common->number == number)
177 88 : return &common->id;
178 : return NULL;
179 : }
180 :
181 81 : void quic_conn_id_update_active(struct quic_conn_id_set *id_set, u32 number)
182 : {
183 81 : struct quic_conn_id *conn_id;
184 :
185 81 : if (number == id_set->active->number)
186 : return;
187 68 : conn_id = quic_conn_id_find(id_set, number);
188 68 : if (!conn_id)
189 : return;
190 68 : quic_conn_id_set_active(id_set, conn_id);
191 : }
192 :
193 2238 : void quic_conn_id_set_init(struct quic_conn_id_set *id_set, bool source)
194 : {
195 2238 : id_set->entry_size = source ? sizeof(struct quic_source_conn_id)
196 : : sizeof(struct quic_dest_conn_id);
197 2238 : INIT_LIST_HEAD(&id_set->head);
198 2238 : }
199 :
200 2236 : void quic_conn_id_set_free(struct quic_conn_id_set *id_set)
201 : {
202 2236 : struct quic_common_conn_id *common, *tmp;
203 :
204 14877 : list_for_each_entry_safe(common, tmp, &id_set->head, list)
205 12641 : quic_conn_id_del(common);
206 2236 : id_set->count = 0;
207 2236 : id_set->active = NULL;
208 2236 : }
209 :
210 2079 : void quic_conn_id_get_param(struct quic_conn_id_set *id_set, struct quic_transport_param *p)
211 : {
212 2079 : p->active_connection_id_limit = id_set->max_count;
213 2079 : }
214 :
215 3172 : void quic_conn_id_set_param(struct quic_conn_id_set *id_set, struct quic_transport_param *p)
216 : {
217 3172 : id_set->max_count = p->active_connection_id_limit;
218 3172 : }
|