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 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 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 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 * 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 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 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 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 * 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 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