Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2023 Marvell.
3 : : */
4 : :
5 : : #include <stdalign.h>
6 : :
7 : : #include <eal_export.h>
8 : : #include <rte_errno.h>
9 : : #include <rte_pdcp.h>
10 : : #include <rte_malloc.h>
11 : :
12 : : #include "pdcp_cnt.h"
13 : : #include "pdcp_crypto.h"
14 : : #include "pdcp_ctrl_pdu.h"
15 : : #include "pdcp_entity.h"
16 : : #include "pdcp_process.h"
17 : :
18 : : #define RTE_PDCP_DYNFIELD_NAME "rte_pdcp_dynfield"
19 : :
20 : : struct entity_layout {
21 : : size_t bitmap_offset;
22 : : size_t bitmap_size;
23 : :
24 : : size_t reorder_buf_offset;
25 : : size_t reorder_buf_size;
26 : :
27 : : size_t total_size;
28 : : };
29 : :
30 : : int rte_pdcp_dynfield_offset = -1;
31 : :
32 : : static int
33 : 0 : pdcp_dynfield_register(void)
34 : : {
35 : 0 : const struct rte_mbuf_dynfield dynfield_desc = {
36 : : .name = RTE_PDCP_DYNFIELD_NAME,
37 : : .size = sizeof(rte_pdcp_dynfield_t),
38 : : .align = alignof(rte_pdcp_dynfield_t),
39 : : };
40 : :
41 [ # # ]: 0 : if (rte_pdcp_dynfield_offset != -1)
42 : : return rte_pdcp_dynfield_offset;
43 : :
44 : 0 : rte_pdcp_dynfield_offset = rte_mbuf_dynfield_register(&dynfield_desc);
45 : 0 : return rte_pdcp_dynfield_offset;
46 : : }
47 : :
48 : : static int
49 : 0 : pdcp_entity_layout_get(const struct rte_pdcp_entity_conf *conf, struct entity_layout *layout)
50 : : {
51 : : size_t size;
52 [ # # ]: 0 : const uint32_t window_size = pdcp_window_size_get(conf->pdcp_xfrm.sn_size);
53 : :
54 : : size = sizeof(struct rte_pdcp_entity) + sizeof(struct entity_priv);
55 : :
56 [ # # ]: 0 : if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) {
57 : : size += sizeof(struct entity_priv_dl_part);
58 : : /* Bitmap require memory to be cache aligned */
59 : : size = RTE_CACHE_LINE_ROUNDUP(size);
60 : 0 : layout->bitmap_offset = size;
61 : 0 : layout->bitmap_size = pdcp_cnt_bitmap_get_memory_footprint(conf);
62 : 0 : size += layout->bitmap_size;
63 : 0 : layout->reorder_buf_offset = size;
64 : 0 : layout->reorder_buf_size = pdcp_reorder_memory_footprint_get(window_size);
65 : 0 : size += layout->reorder_buf_size;
66 [ # # ]: 0 : } else if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK)
67 : : size += sizeof(struct entity_priv_ul_part);
68 : : else
69 : : return -EINVAL;
70 : :
71 : 0 : layout->total_size = size;
72 : :
73 : 0 : return 0;
74 : : }
75 : :
76 : : static int
77 : 0 : pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_conf *conf,
78 : : const struct entity_layout *layout)
79 : : {
80 : 0 : const uint32_t window_size = pdcp_window_size_get(conf->pdcp_xfrm.sn_size);
81 : : struct entity_priv_dl_part *dl = entity_dl_part_get(entity);
82 : : void *memory;
83 : : int ret;
84 : :
85 : 0 : entity->max_pkt_cache = RTE_MAX(entity->max_pkt_cache, window_size);
86 : 0 : dl->t_reorder.handle = conf->t_reordering;
87 : :
88 : 0 : memory = RTE_PTR_ADD(entity, layout->reorder_buf_offset);
89 : 0 : ret = pdcp_reorder_create(&dl->reorder, window_size, memory, layout->reorder_buf_size);
90 [ # # ]: 0 : if (ret)
91 : : return ret;
92 : :
93 : 0 : memory = RTE_PTR_ADD(entity, layout->bitmap_offset);
94 : 0 : ret = pdcp_cnt_bitmap_create(dl, window_size, memory, layout->bitmap_size);
95 [ # # ]: 0 : if (ret)
96 : 0 : return ret;
97 : :
98 : : return 0;
99 : : }
100 : :
101 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pdcp_entity_establish, 23.07)
102 : : struct rte_pdcp_entity *
103 : 0 : rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf)
104 : : {
105 : 0 : struct entity_layout entity_layout = { 0 };
106 : : struct rte_pdcp_entity *entity = NULL;
107 : : struct entity_priv *en_priv;
108 : : uint32_t count;
109 : : int ret;
110 : :
111 [ # # ]: 0 : if (pdcp_dynfield_register() < 0)
112 : : return NULL;
113 : :
114 [ # # # # : 0 : if (conf == NULL || conf->cop_pool == NULL || conf->ctrl_pdu_pool == NULL) {
# # ]
115 : 0 : rte_errno = EINVAL;
116 : 0 : return NULL;
117 : : }
118 : :
119 [ # # # # ]: 0 : if (conf->pdcp_xfrm.en_ordering || conf->pdcp_xfrm.remove_duplicates || conf->is_slrb ||
120 : : conf->en_sec_offload) {
121 : 0 : rte_errno = ENOTSUP;
122 : 0 : return NULL;
123 : : }
124 : :
125 : : /*
126 : : * 6.3.2 PDCP SN
127 : : * Length: 12 or 18 bits as indicated in table 6.3.2-1. The length of the PDCP SN is
128 : : * configured by upper layers (pdcp-SN-SizeUL, pdcp-SN-SizeDL, or sl-PDCP-SN-Size in
129 : : * TS 38.331 [3])
130 : : */
131 [ # # ]: 0 : if ((conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_12) &&
132 : : (conf->pdcp_xfrm.sn_size != RTE_SECURITY_PDCP_SN_SIZE_18)) {
133 : 0 : rte_errno = ENOTSUP;
134 : 0 : return NULL;
135 : : }
136 : :
137 [ # # ]: 0 : if (conf->pdcp_xfrm.hfn_threshold) {
138 : 0 : rte_errno = EINVAL;
139 : 0 : return NULL;
140 : : }
141 : :
142 : 0 : ret = pdcp_entity_layout_get(conf, &entity_layout);
143 [ # # ]: 0 : if (ret < 0) {
144 : 0 : rte_errno = EINVAL;
145 : 0 : return NULL;
146 : : }
147 : :
148 : 0 : entity = rte_zmalloc_socket("pdcp_entity", entity_layout.total_size, RTE_CACHE_LINE_SIZE,
149 : : SOCKET_ID_ANY);
150 [ # # ]: 0 : if (entity == NULL) {
151 : 0 : rte_errno = ENOMEM;
152 : 0 : return NULL;
153 : : }
154 : :
155 : : en_priv = entity_priv_get(entity);
156 : :
157 : 0 : count = pdcp_count_from_hfn_sn_get(conf->pdcp_xfrm.hfn, conf->sn, conf->pdcp_xfrm.sn_size);
158 : :
159 : 0 : en_priv->state.rx_deliv = count;
160 : 0 : en_priv->state.tx_next = count;
161 : 0 : en_priv->cop_pool = conf->cop_pool;
162 : 0 : en_priv->ctrl_pdu_pool = conf->ctrl_pdu_pool;
163 : :
164 : : /* Setup crypto session */
165 : 0 : ret = pdcp_crypto_sess_create(entity, conf);
166 [ # # ]: 0 : if (ret)
167 : 0 : goto entity_free;
168 : :
169 : 0 : ret = pdcp_process_func_set(entity, conf);
170 [ # # ]: 0 : if (ret)
171 : 0 : goto crypto_sess_destroy;
172 : :
173 [ # # ]: 0 : if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) {
174 : 0 : ret = pdcp_dl_establish(entity, conf, &entity_layout);
175 [ # # ]: 0 : if (ret)
176 : 0 : goto crypto_sess_destroy;
177 : : }
178 : :
179 : : return entity;
180 : :
181 : 0 : crypto_sess_destroy:
182 : 0 : pdcp_crypto_sess_destroy(entity);
183 : 0 : entity_free:
184 : 0 : rte_free(entity);
185 : 0 : rte_errno = -ret;
186 : 0 : return NULL;
187 : : }
188 : :
189 : : static int
190 : : pdcp_dl_release(struct rte_pdcp_entity *entity, struct rte_mbuf *out_mb[])
191 : : {
192 : : struct entity_priv_dl_part *dl = entity_dl_part_get(entity);
193 : : struct entity_priv *en_priv = entity_priv_get(entity);
194 : : int nb_out;
195 : :
196 : 0 : nb_out = pdcp_reorder_up_to_get(&dl->reorder, out_mb, entity->max_pkt_cache,
197 : : en_priv->state.rx_next);
198 : :
199 : : return nb_out;
200 : : }
201 : :
202 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pdcp_entity_release, 23.07)
203 : : int
204 : 0 : rte_pdcp_entity_release(struct rte_pdcp_entity *pdcp_entity, struct rte_mbuf *out_mb[])
205 : : {
206 : : struct entity_priv *en_priv;
207 : : int nb_out = 0;
208 : :
209 [ # # ]: 0 : if (pdcp_entity == NULL)
210 : : return -EINVAL;
211 : :
212 : : en_priv = entity_priv_get(pdcp_entity);
213 : :
214 [ # # ]: 0 : if (!en_priv->flags.is_ul_entity)
215 : : nb_out = pdcp_dl_release(pdcp_entity, out_mb);
216 : :
217 : : /* Teardown crypto sessions */
218 : 0 : pdcp_crypto_sess_destroy(pdcp_entity);
219 : :
220 : 0 : rte_free(pdcp_entity);
221 : :
222 : 0 : return nb_out;
223 : : }
224 : :
225 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pdcp_entity_suspend, 23.07)
226 : : int
227 : 0 : rte_pdcp_entity_suspend(struct rte_pdcp_entity *pdcp_entity,
228 : : struct rte_mbuf *out_mb[])
229 : : {
230 : : struct entity_priv_dl_part *dl;
231 : : struct entity_priv *en_priv;
232 : : int nb_out = 0;
233 : :
234 [ # # ]: 0 : if (pdcp_entity == NULL)
235 : : return -EINVAL;
236 : :
237 : : en_priv = entity_priv_get(pdcp_entity);
238 : :
239 [ # # ]: 0 : if (en_priv->flags.is_ul_entity) {
240 : 0 : en_priv->state.tx_next = 0;
241 : : } else {
242 : : dl = entity_dl_part_get(pdcp_entity);
243 : 0 : nb_out = pdcp_reorder_up_to_get(&dl->reorder, out_mb, pdcp_entity->max_pkt_cache,
244 : : en_priv->state.rx_next);
245 : : pdcp_reorder_stop(&dl->reorder);
246 : 0 : en_priv->state.rx_next = 0;
247 : 0 : en_priv->state.rx_deliv = 0;
248 : : }
249 : :
250 : : return nb_out;
251 : : }
252 : :
253 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pdcp_control_pdu_create, 23.07)
254 : : struct rte_mbuf *
255 : 0 : rte_pdcp_control_pdu_create(struct rte_pdcp_entity *pdcp_entity,
256 : : enum rte_pdcp_ctrl_pdu_type type)
257 : : {
258 : : struct entity_priv_dl_part *dl;
259 : : struct entity_priv *en_priv;
260 : : struct rte_mbuf *m;
261 : : int ret;
262 : :
263 [ # # ]: 0 : if (pdcp_entity == NULL) {
264 : 0 : rte_errno = EINVAL;
265 : 0 : return NULL;
266 : : }
267 : :
268 : : en_priv = entity_priv_get(pdcp_entity);
269 : : dl = entity_dl_part_get(pdcp_entity);
270 : :
271 : 0 : m = rte_pktmbuf_alloc(en_priv->ctrl_pdu_pool);
272 [ # # ]: 0 : if (m == NULL) {
273 : 0 : rte_errno = ENOMEM;
274 : 0 : return NULL;
275 : : }
276 : :
277 [ # # ]: 0 : switch (type) {
278 : 0 : case RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT:
279 : 0 : ret = pdcp_ctrl_pdu_status_gen(en_priv, dl, m);
280 : : break;
281 : : default:
282 : : ret = -ENOTSUP;
283 : : }
284 : :
285 [ # # ]: 0 : if (ret) {
286 : 0 : rte_pktmbuf_free(m);
287 : 0 : rte_errno = -ret;
288 : 0 : return NULL;
289 : : }
290 : :
291 : : return m;
292 : : }
293 : :
294 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pdcp_t_reordering_expiry_handle, 23.07)
295 : : uint16_t
296 : 0 : rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity *entity, struct rte_mbuf *out_mb[])
297 : : {
298 : : struct entity_priv_dl_part *dl = entity_dl_part_get(entity);
299 : : struct entity_priv *en_priv = entity_priv_get(entity);
300 : 0 : uint16_t capacity = entity->max_pkt_cache;
301 : : uint16_t nb_out, nb_seq;
302 : :
303 : : /* 5.2.2.2 Actions when a t-Reordering expires */
304 : :
305 : : /*
306 : : * - deliver to upper layers in ascending order of the associated COUNT value after
307 : : * performing header decompression, if not decompressed before:
308 : : */
309 : :
310 : : /* - all stored PDCP SDU(s) with associated COUNT value(s) < RX_REORD; */
311 : 0 : nb_out = pdcp_reorder_up_to_get(&dl->reorder, out_mb, capacity, en_priv->state.rx_reord);
312 : 0 : capacity -= nb_out;
313 : 0 : out_mb = &out_mb[nb_out];
314 : :
315 : : /*
316 : : * - all stored PDCP SDU(s) with consecutively associated COUNT value(s) starting from
317 : : * RX_REORD;
318 : : */
319 : 0 : nb_seq = pdcp_reorder_get_sequential(&dl->reorder, out_mb, capacity);
320 : 0 : nb_out += nb_seq;
321 : :
322 : : /*
323 : : * - update RX_DELIV to the COUNT value of the first PDCP SDU which has not been delivered
324 : : * to upper layers, with COUNT value >= RX_REORD;
325 : : */
326 : 0 : pdcp_rx_deliv_set(entity, en_priv->state.rx_reord + nb_seq);
327 : :
328 : : /*
329 : : * - if RX_DELIV < RX_NEXT:
330 : : * - update RX_REORD to RX_NEXT;
331 : : * - start t-Reordering.
332 : : */
333 [ # # ]: 0 : if (en_priv->state.rx_deliv < en_priv->state.rx_next) {
334 : 0 : en_priv->state.rx_reord = en_priv->state.rx_next;
335 : 0 : dl->t_reorder.state = TIMER_RUNNING;
336 : 0 : dl->t_reorder.handle.start(dl->t_reorder.handle.timer, dl->t_reorder.handle.args);
337 : : } else {
338 : 0 : dl->t_reorder.state = TIMER_EXPIRED;
339 : : }
340 : :
341 : 0 : return nb_out;
342 : : }
|