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