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