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
pdcp_dynfield_register(void)32 pdcp_dynfield_register(void)
33 {
34 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 if (rte_pdcp_dynfield_offset != -1)
41 return rte_pdcp_dynfield_offset;
42
43 rte_pdcp_dynfield_offset = rte_mbuf_dynfield_register(&dynfield_desc);
44 return rte_pdcp_dynfield_offset;
45 }
46
47 static int
pdcp_entity_layout_get(const struct rte_pdcp_entity_conf * conf,struct entity_layout * layout)48 pdcp_entity_layout_get(const struct rte_pdcp_entity_conf *conf, struct entity_layout *layout)
49 {
50 size_t size;
51 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 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 layout->bitmap_offset = size;
60 layout->bitmap_size = pdcp_cnt_bitmap_get_memory_footprint(conf);
61 size += layout->bitmap_size;
62 layout->reorder_buf_offset = size;
63 layout->reorder_buf_size = pdcp_reorder_memory_footprint_get(window_size);
64 size += layout->reorder_buf_size;
65 } 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 layout->total_size = size;
71
72 return 0;
73 }
74
75 static int
pdcp_dl_establish(struct rte_pdcp_entity * entity,const struct rte_pdcp_entity_conf * conf,const struct entity_layout * layout)76 pdcp_dl_establish(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_conf *conf,
77 const struct entity_layout *layout)
78 {
79 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 entity->max_pkt_cache = RTE_MAX(entity->max_pkt_cache, window_size);
85 dl->t_reorder.handle = conf->t_reordering;
86
87 memory = RTE_PTR_ADD(entity, layout->reorder_buf_offset);
88 ret = pdcp_reorder_create(&dl->reorder, window_size, memory, layout->reorder_buf_size);
89 if (ret)
90 return ret;
91
92 memory = RTE_PTR_ADD(entity, layout->bitmap_offset);
93 ret = pdcp_cnt_bitmap_create(dl, window_size, memory, layout->bitmap_size);
94 if (ret)
95 return ret;
96
97 return 0;
98 }
99
100 struct rte_pdcp_entity *
rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf * conf)101 rte_pdcp_entity_establish(const struct rte_pdcp_entity_conf *conf)
102 {
103 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 if (pdcp_dynfield_register() < 0)
110 return NULL;
111
112 if (conf == NULL || conf->cop_pool == NULL || conf->ctrl_pdu_pool == NULL) {
113 rte_errno = EINVAL;
114 return NULL;
115 }
116
117 if (conf->pdcp_xfrm.en_ordering || conf->pdcp_xfrm.remove_duplicates || conf->is_slrb ||
118 conf->en_sec_offload) {
119 rte_errno = ENOTSUP;
120 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 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 rte_errno = ENOTSUP;
132 return NULL;
133 }
134
135 if (conf->pdcp_xfrm.hfn_threshold) {
136 rte_errno = EINVAL;
137 return NULL;
138 }
139
140 ret = pdcp_entity_layout_get(conf, &entity_layout);
141 if (ret < 0) {
142 rte_errno = EINVAL;
143 return NULL;
144 }
145
146 entity = rte_zmalloc_socket("pdcp_entity", entity_layout.total_size, RTE_CACHE_LINE_SIZE,
147 SOCKET_ID_ANY);
148 if (entity == NULL) {
149 rte_errno = ENOMEM;
150 return NULL;
151 }
152
153 en_priv = entity_priv_get(entity);
154
155 count = pdcp_count_from_hfn_sn_get(conf->pdcp_xfrm.hfn, conf->sn, conf->pdcp_xfrm.sn_size);
156
157 en_priv->state.rx_deliv = count;
158 en_priv->state.tx_next = count;
159 en_priv->cop_pool = conf->cop_pool;
160 en_priv->ctrl_pdu_pool = conf->ctrl_pdu_pool;
161
162 /* Setup crypto session */
163 ret = pdcp_crypto_sess_create(entity, conf);
164 if (ret)
165 goto entity_free;
166
167 ret = pdcp_process_func_set(entity, conf);
168 if (ret)
169 goto crypto_sess_destroy;
170
171 if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) {
172 ret = pdcp_dl_establish(entity, conf, &entity_layout);
173 if (ret)
174 goto crypto_sess_destroy;
175 }
176
177 return entity;
178
179 crypto_sess_destroy:
180 pdcp_crypto_sess_destroy(entity);
181 entity_free:
182 rte_free(entity);
183 rte_errno = -ret;
184 return NULL;
185 }
186
187 static int
pdcp_dl_release(struct rte_pdcp_entity * entity,struct rte_mbuf * out_mb[])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 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
rte_pdcp_entity_release(struct rte_pdcp_entity * pdcp_entity,struct rte_mbuf * out_mb[])201 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 if (pdcp_entity == NULL)
207 return -EINVAL;
208
209 en_priv = entity_priv_get(pdcp_entity);
210
211 if (!en_priv->flags.is_ul_entity)
212 nb_out = pdcp_dl_release(pdcp_entity, out_mb);
213
214 /* Teardown crypto sessions */
215 pdcp_crypto_sess_destroy(pdcp_entity);
216
217 rte_free(pdcp_entity);
218
219 return nb_out;
220 }
221
222 int
rte_pdcp_entity_suspend(struct rte_pdcp_entity * pdcp_entity,struct rte_mbuf * out_mb[])223 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 if (pdcp_entity == NULL)
231 return -EINVAL;
232
233 en_priv = entity_priv_get(pdcp_entity);
234
235 if (en_priv->flags.is_ul_entity) {
236 en_priv->state.tx_next = 0;
237 } else {
238 dl = entity_dl_part_get(pdcp_entity);
239 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 en_priv->state.rx_next = 0;
243 en_priv->state.rx_deliv = 0;
244 }
245
246 return nb_out;
247 }
248
249 struct rte_mbuf *
rte_pdcp_control_pdu_create(struct rte_pdcp_entity * pdcp_entity,enum rte_pdcp_ctrl_pdu_type type)250 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 if (pdcp_entity == NULL) {
259 rte_errno = EINVAL;
260 return NULL;
261 }
262
263 en_priv = entity_priv_get(pdcp_entity);
264 dl = entity_dl_part_get(pdcp_entity);
265
266 m = rte_pktmbuf_alloc(en_priv->ctrl_pdu_pool);
267 if (m == NULL) {
268 rte_errno = ENOMEM;
269 return NULL;
270 }
271
272 switch (type) {
273 case RTE_PDCP_CTRL_PDU_TYPE_STATUS_REPORT:
274 ret = pdcp_ctrl_pdu_status_gen(en_priv, dl, m);
275 break;
276 default:
277 ret = -ENOTSUP;
278 }
279
280 if (ret) {
281 rte_pktmbuf_free(m);
282 rte_errno = -ret;
283 return NULL;
284 }
285
286 return m;
287 }
288
289 uint16_t
rte_pdcp_t_reordering_expiry_handle(const struct rte_pdcp_entity * entity,struct rte_mbuf * out_mb[])290 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 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 nb_out = pdcp_reorder_up_to_get(&dl->reorder, out_mb, capacity, en_priv->state.rx_reord);
306 capacity -= nb_out;
307 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 nb_seq = pdcp_reorder_get_sequential(&dl->reorder, out_mb, capacity);
314 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 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 if (en_priv->state.rx_deliv < en_priv->state.rx_next) {
328 en_priv->state.rx_reord = en_priv->state.rx_next;
329 dl->t_reorder.state = TIMER_RUNNING;
330 dl->t_reorder.handle.start(dl->t_reorder.handle.timer, dl->t_reorder.handle.args);
331 } else {
332 dl->t_reorder.state = TIMER_EXPIRED;
333 }
334
335 return nb_out;
336 }
337