1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2021 Marvell. 3 */ 4 #include "roc_api.h" 5 #include "roc_priv.h" 6 7 const struct roc_npc_item_info * 8 npc_parse_skip_void_and_any_items(const struct roc_npc_item_info *pattern) 9 { 10 while ((pattern->type == ROC_NPC_ITEM_TYPE_VOID) || 11 (pattern->type == ROC_NPC_ITEM_TYPE_ANY)) 12 pattern++; 13 14 return pattern; 15 } 16 17 int 18 npc_parse_meta_items(struct npc_parse_state *pst) 19 { 20 PLT_SET_USED(pst); 21 return 0; 22 } 23 24 int 25 npc_parse_mark_item(struct npc_parse_state *pst) 26 { 27 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MARK) { 28 if (pst->flow->nix_intf != NIX_INTF_RX) 29 return -EINVAL; 30 31 pst->is_second_pass_rule = true; 32 pst->pattern++; 33 } 34 35 return 0; 36 } 37 38 int 39 npc_parse_port_representor_id(struct npc_parse_state *pst) 40 { 41 if (pst->pattern->type != ROC_NPC_ITEM_TYPE_REPRESENTED_PORT) 42 return 0; 43 44 pst->pattern++; 45 46 return 0; 47 } 48 49 int 50 npc_parse_represented_port_id(struct npc_parse_state *pst) 51 { 52 if (pst->pattern->type != ROC_NPC_ITEM_TYPE_REPRESENTED_PORT) 53 return 0; 54 55 if (pst->flow->nix_intf != NIX_INTF_RX) 56 return -EINVAL; 57 58 pst->pattern++; 59 60 return 0; 61 } 62 63 static int 64 npc_flow_raw_item_prepare(const struct roc_npc_flow_item_raw *raw_spec, 65 const struct roc_npc_flow_item_raw *raw_mask, 66 struct npc_parse_item_info *info, uint8_t *spec_buf, uint8_t *mask_buf) 67 { 68 69 memset(spec_buf, 0, NPC_MAX_RAW_ITEM_LEN); 70 memset(mask_buf, 0, NPC_MAX_RAW_ITEM_LEN); 71 72 memcpy(spec_buf + raw_spec->offset, raw_spec->pattern, 73 raw_spec->length); 74 75 if (raw_mask && raw_mask->pattern) { 76 memcpy(mask_buf + raw_spec->offset, raw_mask->pattern, 77 raw_spec->length); 78 } else { 79 memset(mask_buf + raw_spec->offset, 0xFF, raw_spec->length); 80 } 81 82 info->len = NPC_MAX_RAW_ITEM_LEN; 83 info->spec = spec_buf; 84 info->mask = mask_buf; 85 return 0; 86 } 87 88 int 89 npc_parse_pre_l2(struct npc_parse_state *pst) 90 { 91 uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN] = {0}; 92 uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN] = {0}; 93 uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN] = {0}; 94 const struct roc_npc_flow_item_raw *raw_spec; 95 struct npc_parse_item_info info; 96 int lid, lt, len; 97 int rc; 98 99 if (pst->npc->switch_header_type != ROC_PRIV_FLAGS_PRE_L2) 100 return 0; 101 102 /* Identify the pattern type into lid, lt */ 103 if (pst->pattern->type != ROC_NPC_ITEM_TYPE_RAW) 104 return 0; 105 106 lid = NPC_LID_LA; 107 lt = NPC_LT_LA_CUSTOM_PRE_L2_ETHER; 108 info.hw_hdr_len = 0; 109 110 raw_spec = pst->pattern->spec; 111 len = raw_spec->length + raw_spec->offset; 112 if (len > NPC_MAX_RAW_ITEM_LEN) 113 return -EINVAL; 114 115 if (raw_spec->relative == 0 || raw_spec->search || raw_spec->limit || 116 raw_spec->offset < 0) 117 return -EINVAL; 118 119 npc_flow_raw_item_prepare( 120 (const struct roc_npc_flow_item_raw *)pst->pattern->spec, 121 (const struct roc_npc_flow_item_raw *)pst->pattern->mask, &info, 122 raw_spec_buf, raw_mask_buf); 123 124 info.def_mask = NULL; 125 info.hw_mask = &hw_mask; 126 npc_get_hw_supp_mask(pst, &info, lid, lt); 127 128 /* Basic validation of item parameters */ 129 rc = npc_parse_item_basic(pst->pattern, &info); 130 if (rc) 131 return rc; 132 133 /* Update pst if not validate only? clash check? */ 134 return npc_update_parse_state(pst, &info, lid, lt, 0); 135 } 136 137 int 138 npc_parse_cpt_hdr(struct npc_parse_state *pst) 139 { 140 uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 141 struct npc_parse_item_info info; 142 int lid, lt; 143 int rc; 144 145 /* Identify the pattern type into lid, lt */ 146 if (pst->pattern->type != ROC_NPC_ITEM_TYPE_CPT_HDR) 147 return 0; 148 149 lid = NPC_LID_LA; 150 lt = NPC_LT_LA_CPT_HDR; 151 info.hw_hdr_len = 0; 152 153 /* Prepare for parsing the item */ 154 info.def_mask = NULL; 155 info.hw_mask = &hw_mask; 156 info.len = pst->pattern->size; 157 npc_get_hw_supp_mask(pst, &info, lid, lt); 158 info.spec = NULL; 159 info.mask = NULL; 160 161 /* Basic validation of item parameters */ 162 rc = npc_parse_item_basic(pst->pattern, &info); 163 if (rc) 164 return rc; 165 166 /* Update pst if not validate only? clash check? */ 167 return npc_update_parse_state(pst, &info, lid, lt, 0); 168 } 169 170 int 171 npc_parse_higig2_hdr(struct npc_parse_state *pst) 172 { 173 uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 174 struct npc_parse_item_info info; 175 int lid, lt; 176 int rc; 177 178 /* Identify the pattern type into lid, lt */ 179 if (pst->pattern->type != ROC_NPC_ITEM_TYPE_HIGIG2) 180 return 0; 181 182 lid = NPC_LID_LA; 183 lt = NPC_LT_LA_HIGIG2_ETHER; 184 info.hw_hdr_len = 0; 185 186 if (pst->flow->nix_intf == NIX_INTF_TX) { 187 lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER; 188 info.hw_hdr_len = NPC_IH_LENGTH; 189 } 190 191 /* Prepare for parsing the item */ 192 info.def_mask = NULL; 193 info.hw_mask = &hw_mask; 194 info.len = pst->pattern->size; 195 npc_get_hw_supp_mask(pst, &info, lid, lt); 196 info.spec = NULL; 197 info.mask = NULL; 198 199 /* Basic validation of item parameters */ 200 rc = npc_parse_item_basic(pst->pattern, &info); 201 if (rc) 202 return rc; 203 204 /* Update pst if not validate only? clash check? */ 205 return npc_update_parse_state(pst, &info, lid, lt, 0); 206 } 207 208 int 209 npc_parse_tx_queue(struct npc_parse_state *pst) 210 { 211 struct nix_inst_hdr_s nix_inst_hdr, nix_inst_hdr_mask; 212 uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 213 struct npc_parse_item_info parse_info; 214 const uint16_t *send_queue; 215 int lid, lt, rc = 0; 216 217 memset(&nix_inst_hdr, 0, sizeof(nix_inst_hdr)); 218 memset(&nix_inst_hdr_mask, 0, sizeof(nix_inst_hdr_mask)); 219 memset(&parse_info, 0, sizeof(parse_info)); 220 221 if (pst->pattern->type != ROC_NPC_ITEM_TYPE_TX_QUEUE) 222 return 0; 223 224 if (pst->flow->nix_intf != NIX_INTF_TX) 225 return NPC_ERR_INVALID_SPEC; 226 227 lid = NPC_LID_LA; 228 lt = NPC_LT_LA_IH_NIX_ETHER; 229 send_queue = (const uint16_t *)pst->pattern->spec; 230 231 if (*send_queue >= pst->nb_tx_queues) 232 return NPC_ERR_INVALID_SPEC; 233 234 nix_inst_hdr.sq = *send_queue; 235 nix_inst_hdr_mask.sq = 0xFFFF; 236 237 parse_info.def_mask = NULL; 238 parse_info.spec = &nix_inst_hdr; 239 parse_info.mask = &nix_inst_hdr_mask; 240 parse_info.len = sizeof(nix_inst_hdr); 241 parse_info.def_mask = NULL; 242 parse_info.hw_hdr_len = 0; 243 244 memset(hw_mask, 0, sizeof(hw_mask)); 245 246 parse_info.hw_mask = &hw_mask; 247 npc_get_hw_supp_mask(pst, &parse_info, lid, lt); 248 249 rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len); 250 if (!rc) 251 return NPC_ERR_INVALID_MASK; 252 253 rc = npc_update_parse_state(pst, &parse_info, lid, lt, 0); 254 if (rc) 255 return rc; 256 257 return 0; 258 } 259 260 int 261 npc_parse_la(struct npc_parse_state *pst) 262 { 263 const struct roc_npc_flow_item_eth *eth_item; 264 uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 265 struct npc_parse_item_info info; 266 int lid, lt; 267 int rc; 268 269 /* Identify the pattern type into lid, lt */ 270 if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH) 271 return 0; 272 273 pst->has_eth_type = true; 274 eth_item = pst->pattern->spec; 275 276 lid = NPC_LID_LA; 277 lt = NPC_LT_LA_ETHER; 278 info.hw_hdr_len = 0; 279 280 if (pst->flow->nix_intf == NIX_INTF_TX) { 281 lt = NPC_LT_LA_IH_NIX_ETHER; 282 info.hw_hdr_len = NPC_IH_LENGTH; 283 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) { 284 lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER; 285 info.hw_hdr_len += NPC_HIGIG2_LENGTH; 286 } 287 } else { 288 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) { 289 lt = NPC_LT_LA_HIGIG2_ETHER; 290 info.hw_hdr_len = NPC_HIGIG2_LENGTH; 291 } 292 } 293 294 /* Prepare for parsing the item */ 295 info.def_mask = NULL; 296 info.hw_mask = &hw_mask; 297 info.len = sizeof(eth_item->hdr); 298 npc_get_hw_supp_mask(pst, &info, lid, lt); 299 info.spec = NULL; 300 info.mask = NULL; 301 302 /* Basic validation of item parameters */ 303 rc = npc_parse_item_basic(pst->pattern, &info); 304 if (rc) 305 return rc; 306 307 rc = npc_update_parse_state(pst, &info, lid, lt, 0); 308 if (rc) 309 return rc; 310 311 if (eth_item && eth_item->has_vlan) 312 pst->set_vlan_ltype_mask = true; 313 314 return 0; 315 } 316 317 #define NPC_MAX_SUPPORTED_VLANS 3 318 319 static int 320 npc_parse_vlan_count(const struct roc_npc_item_info *pattern, 321 const struct roc_npc_item_info **pattern_list, 322 const struct roc_npc_flow_item_vlan **vlan_items, int *vlan_count) 323 { 324 *vlan_count = 0; 325 while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) { 326 if (*vlan_count > NPC_MAX_SUPPORTED_VLANS - 1) 327 return NPC_ERR_PATTERN_NOTSUP; 328 329 /* Don't support ranges */ 330 if (pattern->last != NULL) 331 return NPC_ERR_INVALID_RANGE; 332 333 /* If spec is NULL, both mask and last must be NULL, this 334 * makes it to match ANY value (eq to mask = 0). 335 * Setting either mask or last without spec is an error 336 */ 337 if (pattern->spec == NULL) { 338 if (pattern->last != NULL && pattern->mask != NULL) 339 return NPC_ERR_INVALID_SPEC; 340 } 341 342 pattern_list[*vlan_count] = pattern; 343 vlan_items[*vlan_count] = pattern->spec; 344 (*vlan_count)++; 345 346 pattern++; 347 pattern = npc_parse_skip_void_and_any_items(pattern); 348 } 349 350 return 0; 351 } 352 353 static int 354 npc_parse_vlan_ltype_get(struct npc_parse_state *pst, 355 const struct roc_npc_flow_item_vlan **vlan_item, int vlan_count, 356 int *ltype, int *lflags) 357 { 358 switch (vlan_count) { 359 case 1: 360 *ltype = NPC_LT_LB_CTAG; 361 if (vlan_item[0] && vlan_item[0]->has_more_vlan) 362 *ltype = NPC_LT_LB_STAG_QINQ; 363 break; 364 case 2: 365 if (vlan_item[1] && vlan_item[1]->has_more_vlan) { 366 if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] & 367 0x3ULL << NPC_LFLAG_LB_OFFSET)) 368 return NPC_ERR_PATTERN_NOTSUP; 369 370 /* This lflag value will match either one of 371 * NPC_F_LB_L_WITH_STAG_STAG, 372 * NPC_F_LB_L_WITH_QINQ_CTAG, 373 * NPC_F_LB_L_WITH_QINQ_QINQ and 374 * NPC_F_LB_L_WITH_ITAG (0b0100 to 0b0111). For 375 * NPC_F_LB_L_WITH_ITAG, ltype is NPC_LT_LB_ETAG 376 * hence will not match. 377 */ 378 379 *lflags = NPC_F_LB_L_WITH_QINQ_CTAG & NPC_F_LB_L_WITH_QINQ_QINQ & 380 NPC_F_LB_L_WITH_STAG_STAG; 381 } 382 *ltype = NPC_LT_LB_STAG_QINQ; 383 break; 384 case 3: 385 if (vlan_item[2] && vlan_item[2]->has_more_vlan) 386 return NPC_ERR_PATTERN_NOTSUP; 387 if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] & 0x3ULL << NPC_LFLAG_LB_OFFSET)) 388 return NPC_ERR_PATTERN_NOTSUP; 389 *ltype = NPC_LT_LB_STAG_QINQ; 390 *lflags = NPC_F_STAG_STAG_CTAG; 391 break; 392 default: 393 return NPC_ERR_PATTERN_NOTSUP; 394 } 395 396 return 0; 397 } 398 399 static int 400 npc_update_vlan_parse_state(struct npc_parse_state *pst, const struct roc_npc_item_info *pattern, 401 int lid, int lt, uint8_t lflags, int vlan_count) 402 { 403 uint8_t vlan_spec[NPC_MAX_SUPPORTED_VLANS * sizeof(struct roc_vlan_hdr)]; 404 uint8_t vlan_mask[NPC_MAX_SUPPORTED_VLANS * sizeof(struct roc_vlan_hdr)]; 405 int rc = 0, i, offset = NPC_TPID_LENGTH; 406 struct npc_parse_item_info parse_info; 407 char hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 408 409 memset(vlan_spec, 0, sizeof(struct roc_vlan_hdr) * NPC_MAX_SUPPORTED_VLANS); 410 memset(vlan_mask, 0, sizeof(struct roc_vlan_hdr) * NPC_MAX_SUPPORTED_VLANS); 411 memset(&parse_info, 0, sizeof(parse_info)); 412 413 if (vlan_count > 2) 414 vlan_count = 2; 415 416 for (i = 0; i < vlan_count; i++) { 417 if (pattern[i].spec) 418 memcpy(vlan_spec + offset, pattern[i].spec, sizeof(struct roc_vlan_hdr)); 419 if (pattern[i].mask) 420 memcpy(vlan_mask + offset, pattern[i].mask, sizeof(struct roc_vlan_hdr)); 421 422 offset += 4; 423 } 424 425 parse_info.def_mask = NULL; 426 parse_info.spec = vlan_spec; 427 parse_info.mask = vlan_mask; 428 parse_info.def_mask = NULL; 429 parse_info.hw_hdr_len = 0; 430 431 lid = NPC_LID_LB; 432 parse_info.hw_mask = hw_mask; 433 434 if (lt == NPC_LT_LB_CTAG) 435 parse_info.len = sizeof(struct roc_vlan_hdr) + NPC_TPID_LENGTH; 436 437 if (lt == NPC_LT_LB_STAG_QINQ) 438 parse_info.len = sizeof(struct roc_vlan_hdr) * 2 + NPC_TPID_LENGTH; 439 440 memset(hw_mask, 0, sizeof(hw_mask)); 441 442 parse_info.hw_mask = &hw_mask; 443 npc_get_hw_supp_mask(pst, &parse_info, lid, lt); 444 445 rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len); 446 if (!rc) 447 return NPC_ERR_INVALID_MASK; 448 449 /* Point pattern to last item consumed */ 450 pst->pattern = pattern; 451 return npc_update_parse_state(pst, &parse_info, lid, lt, lflags); 452 } 453 454 static int 455 npc_parse_lb_vlan(struct npc_parse_state *pst) 456 { 457 const struct roc_npc_flow_item_vlan *vlan_items[NPC_MAX_SUPPORTED_VLANS]; 458 const struct roc_npc_item_info *pattern_list[NPC_MAX_SUPPORTED_VLANS]; 459 const struct roc_npc_item_info *last_pattern; 460 int vlan_count = 0, rc = 0; 461 int lid, lt, lflags; 462 463 lid = NPC_LID_LB; 464 lflags = 0; 465 last_pattern = pst->pattern; 466 467 rc = npc_parse_vlan_count(pst->pattern, pattern_list, vlan_items, &vlan_count); 468 if (rc) 469 return rc; 470 471 rc = npc_parse_vlan_ltype_get(pst, vlan_items, vlan_count, <, &lflags); 472 if (rc) 473 return rc; 474 475 if (vlan_count == 3) { 476 if (pattern_list[2]->spec != NULL && pattern_list[2]->mask != NULL && 477 pattern_list[2]->last != NULL) 478 return NPC_ERR_PATTERN_NOTSUP; 479 480 /* Matching can be done only for two tags. */ 481 vlan_count = 2; 482 last_pattern++; 483 } 484 485 rc = npc_update_vlan_parse_state(pst, pattern_list[0], lid, lt, lflags, vlan_count); 486 if (rc) 487 return rc; 488 489 if (vlan_count > 1) 490 pst->pattern = last_pattern + vlan_count; 491 492 return 0; 493 } 494 495 int 496 npc_parse_lb(struct npc_parse_state *pst) 497 { 498 const struct roc_npc_item_info *pattern = pst->pattern; 499 const struct roc_npc_item_info *last_pattern; 500 const struct roc_npc_flow_item_raw *raw_spec; 501 uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN]; 502 uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN]; 503 char hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 504 struct npc_parse_item_info info; 505 int lid, lt, lflags, len = 0; 506 int rc; 507 508 info.def_mask = NULL; 509 info.spec = NULL; 510 info.mask = NULL; 511 info.def_mask = NULL; 512 info.hw_hdr_len = NPC_TPID_LENGTH; 513 514 lid = NPC_LID_LB; 515 lflags = 0; 516 last_pattern = pattern; 517 518 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_VLAN) { 519 /* RTE vlan is either 802.1q or 802.1ad, 520 * this maps to either CTAG/STAG. We need to decide 521 * based on number of VLANS present. Matching is 522 * supported on first two tags. 523 */ 524 525 return npc_parse_lb_vlan(pst); 526 } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_E_TAG) { 527 /* we can support ETAG and match a subsequent CTAG 528 * without any matching support. 529 */ 530 lt = NPC_LT_LB_ETAG; 531 lflags = 0; 532 533 last_pattern = pst->pattern; 534 pattern = npc_parse_skip_void_and_any_items(pst->pattern + 1); 535 if (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) { 536 /* set supported mask to NULL for vlan tag */ 537 info.hw_mask = NULL; 538 info.len = pattern->size; 539 rc = npc_parse_item_basic(pattern, &info); 540 if (rc != 0) 541 return rc; 542 543 lflags = NPC_F_ETAG_CTAG; 544 last_pattern = pattern; 545 } 546 info.len = pattern->size; 547 } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_QINQ) { 548 info.hw_mask = NULL; 549 info.len = pattern->size; 550 lt = NPC_LT_LB_STAG_QINQ; 551 lflags = NPC_F_STAG_CTAG; 552 } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_PPPOES) { 553 info.hw_mask = NULL; 554 info.len = pattern->size; 555 info.hw_hdr_len = 2; 556 lt = NPC_LT_LB_PPPOE; 557 } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_RAW) { 558 raw_spec = pst->pattern->spec; 559 if (raw_spec->relative) 560 return 0; 561 len = raw_spec->length + raw_spec->offset; 562 if (len > NPC_MAX_RAW_ITEM_LEN) 563 return -EINVAL; 564 565 if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_VLAN_EXDSA) { 566 lt = NPC_LT_LB_VLAN_EXDSA; 567 } else if (pst->npc->switch_header_type == 568 ROC_PRIV_FLAGS_EXDSA) { 569 lt = NPC_LT_LB_EXDSA; 570 } else { 571 return -EINVAL; 572 } 573 574 npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *) 575 pst->pattern->spec, 576 (const struct roc_npc_flow_item_raw *) 577 pst->pattern->mask, 578 &info, raw_spec_buf, raw_mask_buf); 579 580 info.hw_hdr_len = 0; 581 } else { 582 return 0; 583 } 584 585 info.hw_mask = &hw_mask; 586 npc_get_hw_supp_mask(pst, &info, lid, lt); 587 588 rc = npc_parse_item_basic(pst->pattern, &info); 589 if (rc != 0) 590 return rc; 591 592 /* Point pattern to last item consumed */ 593 pst->pattern = last_pattern; 594 return npc_update_parse_state(pst, &info, lid, lt, lflags); 595 } 596 597 static int 598 npc_parse_mpls_label_stack(struct npc_parse_state *pst, int *flag) 599 { 600 uint8_t flag_list[] = {0, NPC_F_MPLS_2_LABELS, NPC_F_MPLS_3_LABELS, 601 NPC_F_MPLS_4_LABELS}; 602 const struct roc_npc_item_info *pattern = pst->pattern; 603 struct npc_parse_item_info info; 604 int nr_labels = 0; 605 int rc; 606 607 /* 608 * pst->pattern points to first MPLS label. We only check 609 * that subsequent labels do not have anything to match. 610 */ 611 info.def_mask = NULL; 612 info.hw_mask = NULL; 613 info.len = pattern->size; 614 info.spec = NULL; 615 info.mask = NULL; 616 info.hw_hdr_len = 0; 617 618 while (pattern->type == ROC_NPC_ITEM_TYPE_MPLS) { 619 nr_labels++; 620 621 /* Basic validation of Second/Third/Fourth mpls item */ 622 if (nr_labels > 1) { 623 rc = npc_parse_item_basic(pattern, &info); 624 if (rc != 0) 625 return rc; 626 } 627 pst->last_pattern = pattern; 628 pattern++; 629 pattern = npc_parse_skip_void_and_any_items(pattern); 630 } 631 632 if (nr_labels < 1 || nr_labels > 4) 633 return NPC_ERR_PATTERN_NOTSUP; 634 635 *flag = flag_list[nr_labels - 1]; 636 return 0; 637 } 638 639 static int 640 npc_parse_mpls(struct npc_parse_state *pst, int lid) 641 { 642 /* Find number of MPLS labels */ 643 uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 644 struct npc_parse_item_info info; 645 int lt, lflags; 646 int rc; 647 648 lflags = 0; 649 650 if (lid == NPC_LID_LC) 651 lt = NPC_LT_LC_MPLS; 652 else if (lid == NPC_LID_LD) 653 lt = NPC_LT_LD_TU_MPLS_IN_IP; 654 else 655 lt = NPC_LT_LE_TU_MPLS_IN_UDP; 656 657 /* Prepare for parsing the first item */ 658 info.hw_mask = &hw_mask; 659 info.len = pst->pattern->size; 660 info.spec = NULL; 661 info.mask = NULL; 662 info.def_mask = NULL; 663 info.hw_hdr_len = 0; 664 665 npc_get_hw_supp_mask(pst, &info, lid, lt); 666 rc = npc_parse_item_basic(pst->pattern, &info); 667 if (rc != 0) 668 return rc; 669 670 /* 671 * Parse for more labels. 672 * This sets lflags and pst->last_pattern correctly. 673 */ 674 rc = npc_parse_mpls_label_stack(pst, &lflags); 675 if (rc != 0) 676 return rc; 677 678 pst->tunnel = 1; 679 pst->pattern = pst->last_pattern; 680 681 return npc_update_parse_state(pst, &info, lid, lt, lflags); 682 } 683 684 static inline void 685 npc_check_lc_ip_tunnel(struct npc_parse_state *pst) 686 { 687 const struct roc_npc_item_info *pattern = pst->pattern + 1; 688 689 pattern = npc_parse_skip_void_and_any_items(pattern); 690 if (pattern->type == ROC_NPC_ITEM_TYPE_MPLS || 691 pattern->type == ROC_NPC_ITEM_TYPE_IPV4 || 692 pattern->type == ROC_NPC_ITEM_TYPE_IPV6) 693 pst->tunnel = 1; 694 } 695 696 static int 697 npc_handle_ipv6ext_attr(const struct roc_npc_flow_item_ipv6 *ipv6_spec, 698 struct npc_parse_state *pst, uint8_t *flags) 699 { 700 int flags_count = 0; 701 702 if (ipv6_spec->has_hop_ext) { 703 *flags = NPC_F_LC_L_EXT_HOP; 704 flags_count++; 705 } 706 if (ipv6_spec->has_route_ext) { 707 *flags = NPC_F_LC_L_EXT_ROUT; 708 flags_count++; 709 } 710 if (ipv6_spec->has_frag_ext) { 711 *flags = NPC_F_LC_U_IP6_FRAG; 712 flags_count++; 713 } 714 if (ipv6_spec->has_dest_ext) { 715 *flags = NPC_F_LC_L_EXT_DEST; 716 flags_count++; 717 } 718 if (ipv6_spec->has_mobil_ext) { 719 *flags = NPC_F_LC_L_EXT_MOBILITY; 720 flags_count++; 721 } 722 if (ipv6_spec->has_hip_ext) { 723 *flags = NPC_F_LC_L_EXT_HOSTID; 724 flags_count++; 725 } 726 if (ipv6_spec->has_shim6_ext) { 727 *flags = NPC_F_LC_L_EXT_SHIM6; 728 flags_count++; 729 } 730 if (ipv6_spec->has_auth_ext) { 731 pst->lt[NPC_LID_LD] = NPC_LT_LD_AH; 732 flags_count++; 733 } 734 if (ipv6_spec->has_esp_ext) { 735 pst->lt[NPC_LID_LE] = NPC_LT_LE_ESP; 736 flags_count++; 737 } 738 739 if (flags_count > 1) 740 return -EINVAL; 741 742 if (flags_count) 743 pst->set_ipv6ext_ltype_mask = true; 744 745 return 0; 746 } 747 748 static int 749 npc_process_ipv6_item(struct npc_parse_state *pst) 750 { 751 uint8_t ipv6_hdr_mask[2 * sizeof(struct roc_ipv6_hdr)]; 752 uint8_t ipv6_hdr_buf[2 * sizeof(struct roc_ipv6_hdr)]; 753 const struct roc_npc_flow_item_ipv6 *ipv6_spec, *ipv6_mask; 754 const struct roc_npc_item_info *pattern = pst->pattern; 755 int offset = 0, rc = 0, lid, item_count = 0; 756 struct npc_parse_item_info parse_info; 757 char hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 758 uint8_t flags = 0, ltype; 759 760 memset(ipv6_hdr_buf, 0, sizeof(ipv6_hdr_buf)); 761 memset(ipv6_hdr_mask, 0, sizeof(ipv6_hdr_mask)); 762 763 ipv6_spec = pst->pattern->spec; 764 ipv6_mask = pst->pattern->mask; 765 766 parse_info.def_mask = NULL; 767 parse_info.spec = ipv6_hdr_buf; 768 parse_info.mask = ipv6_hdr_mask; 769 parse_info.def_mask = NULL; 770 parse_info.hw_hdr_len = 0; 771 parse_info.len = sizeof(ipv6_spec->hdr); 772 773 pst->set_ipv6ext_ltype_mask = true; 774 775 lid = NPC_LID_LC; 776 ltype = NPC_LT_LC_IP6; 777 778 if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6) { 779 item_count++; 780 if (ipv6_spec) { 781 memcpy(ipv6_hdr_buf, &ipv6_spec->hdr, sizeof(struct roc_ipv6_hdr)); 782 rc = npc_handle_ipv6ext_attr(ipv6_spec, pst, &flags); 783 if (rc) 784 return rc; 785 } 786 if (ipv6_mask) 787 memcpy(ipv6_hdr_mask, &ipv6_mask->hdr, sizeof(struct roc_ipv6_hdr)); 788 } 789 790 offset = sizeof(struct roc_ipv6_hdr); 791 792 while (pattern->type != ROC_NPC_ITEM_TYPE_END) { 793 /* Don't support ranges */ 794 if (pattern->last != NULL) 795 return NPC_ERR_INVALID_RANGE; 796 797 /* If spec is NULL, both mask and last must be NULL, this 798 * makes it to match ANY value (eq to mask = 0). 799 * Setting either mask or last without spec is 800 * an error 801 */ 802 if (pattern->spec == NULL) { 803 if (pattern->last != NULL && pattern->mask != NULL) 804 return NPC_ERR_INVALID_SPEC; 805 } 806 /* Either one ROC_NPC_ITEM_TYPE_IPV6_EXT or 807 * one ROC_NPC_ITEM_TYPE_IPV6_FRAG_EXT is supported 808 * following an ROC_NPC_ITEM_TYPE_IPV6 item. 809 */ 810 if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6_EXT) { 811 item_count++; 812 ltype = NPC_LT_LC_IP6_EXT; 813 parse_info.len = 814 sizeof(struct roc_ipv6_hdr) + sizeof(struct roc_flow_item_ipv6_ext); 815 if (pattern->spec) 816 memcpy(ipv6_hdr_buf + offset, pattern->spec, 817 sizeof(struct roc_flow_item_ipv6_ext)); 818 if (pattern->mask) 819 memcpy(ipv6_hdr_mask + offset, pattern->mask, 820 sizeof(struct roc_flow_item_ipv6_ext)); 821 break; 822 } else if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6_FRAG_EXT) { 823 item_count++; 824 ltype = NPC_LT_LC_IP6_EXT; 825 flags = NPC_F_LC_U_IP6_FRAG; 826 parse_info.len = 827 sizeof(struct roc_ipv6_hdr) + sizeof(struct roc_ipv6_fragment_ext); 828 if (pattern->spec) 829 memcpy(ipv6_hdr_buf + offset, pattern->spec, 830 sizeof(struct roc_ipv6_fragment_ext)); 831 if (pattern->mask) 832 memcpy(ipv6_hdr_mask + offset, pattern->mask, 833 sizeof(struct roc_ipv6_fragment_ext)); 834 835 break; 836 } else if (pattern->type == ROC_NPC_ITEM_TYPE_IPV6_ROUTING_EXT) { 837 item_count++; 838 ltype = NPC_LT_LC_IP6_EXT; 839 parse_info.len = sizeof(struct roc_ipv6_hdr) + pattern->size; 840 841 if (pattern->spec) 842 memcpy(ipv6_hdr_buf + offset, pattern->spec, pattern->size); 843 if (pattern->mask) 844 memcpy(ipv6_hdr_mask + offset, pattern->mask, pattern->size); 845 break; 846 } 847 848 pattern++; 849 pattern = npc_parse_skip_void_and_any_items(pattern); 850 } 851 852 memset(hw_mask, 0, sizeof(hw_mask)); 853 854 parse_info.hw_mask = &hw_mask; 855 npc_get_hw_supp_mask(pst, &parse_info, lid, ltype); 856 857 rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len); 858 if (!rc) 859 return NPC_ERR_INVALID_MASK; 860 861 rc = npc_update_parse_state(pst, &parse_info, lid, ltype, flags); 862 if (rc) 863 return rc; 864 865 if (pst->npc->hash_extract_cap) { 866 rc = npc_process_ipv6_field_hash(parse_info.spec, parse_info.mask, pst, ltype); 867 if (rc) 868 return rc; 869 } 870 871 /* npc_update_parse_state() increments pattern once. 872 * Check if additional increment is required. 873 */ 874 if (item_count == 2) 875 pst->pattern++; 876 877 return 0; 878 } 879 880 int 881 npc_parse_lc(struct npc_parse_state *pst) 882 { 883 const struct roc_npc_flow_item_raw *raw_spec; 884 uint8_t raw_spec_buf[NPC_MAX_RAW_ITEM_LEN]; 885 uint8_t raw_mask_buf[NPC_MAX_RAW_ITEM_LEN]; 886 uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 887 struct npc_parse_item_info info; 888 int rc, lid, lt, len = 0; 889 uint8_t flags = 0; 890 891 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS) 892 return npc_parse_mpls(pst, NPC_LID_LC); 893 894 info.def_mask = NULL; 895 info.hw_mask = &hw_mask; 896 info.spec = NULL; 897 info.mask = NULL; 898 info.hw_hdr_len = 0; 899 lid = NPC_LID_LC; 900 901 switch (pst->pattern->type) { 902 case ROC_NPC_ITEM_TYPE_IPV4: 903 lt = NPC_LT_LC_IP; 904 info.len = pst->pattern->size; 905 break; 906 case ROC_NPC_ITEM_TYPE_IPV6: 907 case ROC_NPC_ITEM_TYPE_IPV6_EXT: 908 case ROC_NPC_ITEM_TYPE_IPV6_FRAG_EXT: 909 case ROC_NPC_ITEM_TYPE_IPV6_ROUTING_EXT: 910 return npc_process_ipv6_item(pst); 911 case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4: 912 lt = NPC_LT_LC_ARP; 913 info.len = pst->pattern->size; 914 break; 915 case ROC_NPC_ITEM_TYPE_L3_CUSTOM: 916 lt = NPC_LT_LC_CUSTOM0; 917 info.len = pst->pattern->size; 918 break; 919 case ROC_NPC_ITEM_TYPE_RAW: 920 raw_spec = pst->pattern->spec; 921 if (!raw_spec->relative) 922 return 0; 923 924 len = raw_spec->length + raw_spec->offset; 925 if (len > NPC_MAX_RAW_ITEM_LEN) 926 return -EINVAL; 927 928 npc_flow_raw_item_prepare((const struct roc_npc_flow_item_raw *) 929 pst->pattern->spec, 930 (const struct roc_npc_flow_item_raw *) 931 pst->pattern->mask, 932 &info, raw_spec_buf, raw_mask_buf); 933 934 lid = NPC_LID_LC; 935 lt = NPC_LT_LC_NGIO; 936 info.hw_mask = &hw_mask; 937 npc_get_hw_supp_mask(pst, &info, lid, lt); 938 break; 939 default: 940 /* No match at this layer */ 941 return 0; 942 } 943 944 /* Identify if IP tunnels MPLS or IPv4/v6 */ 945 npc_check_lc_ip_tunnel(pst); 946 947 npc_get_hw_supp_mask(pst, &info, lid, lt); 948 rc = npc_parse_item_basic(pst->pattern, &info); 949 950 if (rc != 0) 951 return rc; 952 953 return npc_update_parse_state(pst, &info, lid, lt, flags); 954 } 955 956 int 957 npc_parse_ld(struct npc_parse_state *pst) 958 { 959 char hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 960 struct npc_parse_item_info info; 961 int lid, lt, lflags; 962 int rc; 963 964 if (pst->tunnel) { 965 /* We have already parsed MPLS or IPv4/v6 followed 966 * by MPLS or IPv4/v6. Subsequent TCP/UDP etc 967 * would be parsed as tunneled versions. Skip 968 * this layer, except for tunneled MPLS. If LC is 969 * MPLS, we have anyway skipped all stacked MPLS 970 * labels. 971 */ 972 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS) 973 return npc_parse_mpls(pst, NPC_LID_LD); 974 return 0; 975 } 976 info.def_mask = NULL; 977 info.hw_mask = &hw_mask; 978 info.spec = NULL; 979 info.mask = NULL; 980 info.len = 0; 981 info.hw_hdr_len = 0; 982 983 lid = NPC_LID_LD; 984 lflags = 0; 985 986 switch (pst->pattern->type) { 987 case ROC_NPC_ITEM_TYPE_ICMP: 988 if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6) 989 lt = NPC_LT_LD_ICMP6; 990 else 991 lt = NPC_LT_LD_ICMP; 992 info.len = pst->pattern->size; 993 break; 994 case ROC_NPC_ITEM_TYPE_UDP: 995 lt = NPC_LT_LD_UDP; 996 info.len = pst->pattern->size; 997 break; 998 case ROC_NPC_ITEM_TYPE_IGMP: 999 lt = NPC_LT_LD_IGMP; 1000 info.len = pst->pattern->size; 1001 break; 1002 case ROC_NPC_ITEM_TYPE_TCP: 1003 lt = NPC_LT_LD_TCP; 1004 info.len = pst->pattern->size; 1005 break; 1006 case ROC_NPC_ITEM_TYPE_SCTP: 1007 lt = NPC_LT_LD_SCTP; 1008 info.len = pst->pattern->size; 1009 break; 1010 case ROC_NPC_ITEM_TYPE_GRE: 1011 lt = NPC_LT_LD_GRE; 1012 info.len = pst->pattern->size; 1013 pst->tunnel = 1; 1014 break; 1015 case ROC_NPC_ITEM_TYPE_GRE_KEY: 1016 lt = NPC_LT_LD_GRE; 1017 info.len = pst->pattern->size; 1018 info.hw_hdr_len = 4; 1019 pst->tunnel = 1; 1020 break; 1021 case ROC_NPC_ITEM_TYPE_NVGRE: 1022 lt = NPC_LT_LD_NVGRE; 1023 lflags = NPC_F_GRE_NVGRE; 1024 info.len = pst->pattern->size; 1025 /* Further IP/Ethernet are parsed as tunneled */ 1026 pst->tunnel = 1; 1027 break; 1028 default: 1029 return 0; 1030 } 1031 1032 npc_get_hw_supp_mask(pst, &info, lid, lt); 1033 rc = npc_parse_item_basic(pst->pattern, &info); 1034 if (rc != 0) 1035 return rc; 1036 1037 return npc_update_parse_state(pst, &info, lid, lt, lflags); 1038 } 1039 1040 int 1041 npc_parse_le(struct npc_parse_state *pst) 1042 { 1043 const struct roc_npc_item_info *pattern = pst->pattern; 1044 const struct roc_npc_item_esp_hdr *esp = NULL; 1045 char hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 1046 struct npc_parse_item_info info; 1047 int lid, lt, lflags; 1048 int rc; 1049 1050 if (pst->tunnel) 1051 return 0; 1052 1053 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS) 1054 return npc_parse_mpls(pst, NPC_LID_LE); 1055 1056 info.spec = NULL; 1057 info.mask = NULL; 1058 info.hw_mask = NULL; 1059 info.def_mask = NULL; 1060 info.len = 0; 1061 info.hw_hdr_len = 0; 1062 lid = NPC_LID_LE; 1063 lflags = 0; 1064 1065 /* Ensure we are not matching anything in UDP */ 1066 rc = npc_parse_item_basic(pattern, &info); 1067 if (rc) 1068 return rc; 1069 1070 info.hw_mask = &hw_mask; 1071 pattern = npc_parse_skip_void_and_any_items(pattern); 1072 switch (pattern->type) { 1073 case ROC_NPC_ITEM_TYPE_VXLAN: 1074 lflags = NPC_F_UDP_VXLAN; 1075 info.len = pattern->size; 1076 lt = NPC_LT_LE_VXLAN; 1077 break; 1078 case ROC_NPC_ITEM_TYPE_GTPC: 1079 lflags = NPC_F_UDP_GTP_GTPC; 1080 info.len = pattern->size; 1081 lt = NPC_LT_LE_GTPC; 1082 break; 1083 case ROC_NPC_ITEM_TYPE_GTPU: 1084 lflags = NPC_F_UDP_GTP_GTPU_G_PDU; 1085 info.len = pattern->size; 1086 lt = NPC_LT_LE_GTPU; 1087 break; 1088 case ROC_NPC_ITEM_TYPE_GENEVE: 1089 lflags = NPC_F_UDP_GENEVE; 1090 info.len = pattern->size; 1091 lt = NPC_LT_LE_GENEVE; 1092 break; 1093 case ROC_NPC_ITEM_TYPE_VXLAN_GPE: 1094 lflags = NPC_F_UDP_VXLANGPE; 1095 info.len = pattern->size; 1096 lt = NPC_LT_LE_VXLANGPE; 1097 break; 1098 case ROC_NPC_ITEM_TYPE_ESP: 1099 lt = NPC_LT_LE_ESP; 1100 info.len = pst->pattern->size; 1101 esp = (const struct roc_npc_item_esp_hdr *)pattern->spec; 1102 if (esp) 1103 pst->flow->spi_to_sa_info.spi = esp->spi; 1104 break; 1105 default: 1106 return 0; 1107 } 1108 1109 pst->tunnel = 1; 1110 1111 npc_get_hw_supp_mask(pst, &info, lid, lt); 1112 rc = npc_parse_item_basic(pattern, &info); 1113 if (rc != 0) 1114 return rc; 1115 1116 return npc_update_parse_state(pst, &info, lid, lt, lflags); 1117 } 1118 1119 int 1120 npc_parse_lf(struct npc_parse_state *pst) 1121 { 1122 const struct roc_npc_item_info *pattern, *last_pattern; 1123 char hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 1124 const struct roc_npc_flow_item_eth *eth_item; 1125 struct npc_parse_item_info info; 1126 int lid, lt, lflags; 1127 int nr_vlans = 0; 1128 int rc; 1129 1130 /* We hit this layer if there is a tunneling protocol */ 1131 if (!pst->tunnel) 1132 return 0; 1133 1134 if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH) 1135 return 0; 1136 1137 lid = NPC_LID_LF; 1138 lt = NPC_LT_LF_TU_ETHER; 1139 lflags = 0; 1140 1141 eth_item = pst->pattern->spec; 1142 1143 /* No match support for vlan tags */ 1144 info.def_mask = NULL; 1145 info.hw_mask = NULL; 1146 info.len = sizeof(eth_item->hdr); 1147 info.spec = NULL; 1148 info.mask = NULL; 1149 info.hw_hdr_len = 0; 1150 1151 /* Look ahead and find out any VLAN tags. These can be 1152 * detected but no data matching is available. 1153 */ 1154 last_pattern = pst->pattern; 1155 pattern = pst->pattern + 1; 1156 pattern = npc_parse_skip_void_and_any_items(pattern); 1157 while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) { 1158 nr_vlans++; 1159 last_pattern = pattern; 1160 pattern++; 1161 pattern = npc_parse_skip_void_and_any_items(pattern); 1162 } 1163 switch (nr_vlans) { 1164 case 0: 1165 break; 1166 case 1: 1167 lflags = NPC_F_TU_ETHER_CTAG; 1168 break; 1169 case 2: 1170 lflags = NPC_F_TU_ETHER_STAG_CTAG; 1171 break; 1172 default: 1173 return NPC_ERR_PATTERN_NOTSUP; 1174 } 1175 1176 info.hw_mask = &hw_mask; 1177 info.len = sizeof(eth_item->hdr); 1178 info.hw_hdr_len = 0; 1179 npc_get_hw_supp_mask(pst, &info, lid, lt); 1180 info.spec = NULL; 1181 info.mask = NULL; 1182 1183 if (eth_item && eth_item->has_vlan) 1184 pst->set_vlan_ltype_mask = true; 1185 1186 rc = npc_parse_item_basic(pst->pattern, &info); 1187 if (rc != 0) 1188 return rc; 1189 1190 pst->pattern = last_pattern; 1191 1192 return npc_update_parse_state(pst, &info, lid, lt, lflags); 1193 } 1194 1195 int 1196 npc_parse_lg(struct npc_parse_state *pst) 1197 { 1198 char hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 1199 struct npc_parse_item_info info; 1200 int lid, lt; 1201 int rc; 1202 1203 if (!pst->tunnel) 1204 return 0; 1205 1206 info.def_mask = NULL; 1207 info.hw_mask = &hw_mask; 1208 info.spec = NULL; 1209 info.mask = NULL; 1210 info.hw_hdr_len = 0; 1211 lid = NPC_LID_LG; 1212 1213 if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) { 1214 lt = NPC_LT_LG_TU_IP; 1215 info.len = pst->pattern->size; 1216 } else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) { 1217 lt = NPC_LT_LG_TU_IP6; 1218 info.len = pst->pattern->size; 1219 } else { 1220 /* There is no tunneled IP header */ 1221 return 0; 1222 } 1223 1224 npc_get_hw_supp_mask(pst, &info, lid, lt); 1225 rc = npc_parse_item_basic(pst->pattern, &info); 1226 if (rc != 0) 1227 return rc; 1228 1229 return npc_update_parse_state(pst, &info, lid, lt, 0); 1230 } 1231 1232 int 1233 npc_parse_lh(struct npc_parse_state *pst) 1234 { 1235 char hw_mask[NPC_MAX_EXTRACT_HW_LEN]; 1236 struct npc_parse_item_info info; 1237 int lid, lt; 1238 int rc; 1239 1240 if (!pst->tunnel) 1241 return 0; 1242 1243 info.def_mask = NULL; 1244 info.hw_mask = &hw_mask; 1245 info.spec = NULL; 1246 info.mask = NULL; 1247 info.hw_hdr_len = 0; 1248 lid = NPC_LID_LH; 1249 1250 switch (pst->pattern->type) { 1251 case ROC_NPC_ITEM_TYPE_UDP: 1252 lt = NPC_LT_LH_TU_UDP; 1253 info.len = pst->pattern->size; 1254 break; 1255 case ROC_NPC_ITEM_TYPE_TCP: 1256 lt = NPC_LT_LH_TU_TCP; 1257 info.len = pst->pattern->size; 1258 break; 1259 case ROC_NPC_ITEM_TYPE_SCTP: 1260 lt = NPC_LT_LH_TU_SCTP; 1261 info.len = pst->pattern->size; 1262 break; 1263 case ROC_NPC_ITEM_TYPE_ESP: 1264 lt = NPC_LT_LH_TU_ESP; 1265 info.len = pst->pattern->size; 1266 break; 1267 default: 1268 return 0; 1269 } 1270 1271 npc_get_hw_supp_mask(pst, &info, lid, lt); 1272 rc = npc_parse_item_basic(pst->pattern, &info); 1273 if (rc != 0) 1274 return rc; 1275 1276 return npc_update_parse_state(pst, &info, lid, lt, 0); 1277 } 1278