diff options
author | Anca Jeanina FLOAREA <anca.floarea@freescale.com> | 2013-08-02 11:56:08 (GMT) |
---|---|---|
committer | Rivera Jose-B46482 <Jose.G.Rivera@freescale.com> | 2013-08-14 22:51:03 (GMT) |
commit | f6ec6d368cb9d8a3cb4e73a47ddb4438c1ff20db (patch) | |
tree | 6588ee1c091ceaea85090d4282e30275710514ca /drivers | |
parent | 10fc25ba7530e123bee4eefc466c07aa5a629961 (diff) | |
download | linux-fsl-qoriq-f6ec6d368cb9d8a3cb4e73a47ddb4438c1ff20db.tar.xz |
dpa_offload: Add support in DPA Stats for miss statistics
Added support in DPA Stats to retrieve the statistics for
the miss-entry of either a Classification Node or a
Classification Table. The user can request statistics for
miss-entry by providing the key set to NULL. The Classification
counter API was changed in order to allow the user to
provide NULL instead of a valid key.
Signed-off-by: Anca Jeanina FLOAREA <anca.floarea@freescale.com>
Change-Id: Idf1324414f25e45dae908df01e0dc008db0fd083
Reviewed-on: http://git.am.freescale.net:8181/3740
Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com>
Reviewed-by: Zanoschi Aurelian-B43522 <Aurelian.Zanoschi@freescale.com>
Reviewed-by: Rivera Jose-B46482 <Jose.G.Rivera@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/fsl_dpa_offload/dpa_stats.c | 563 | ||||
-rw-r--r-- | drivers/staging/fsl_dpa_offload/dpa_stats.h | 1 | ||||
-rw-r--r-- | drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h | 12 | ||||
-rw-r--r-- | drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c | 950 |
4 files changed, 1023 insertions, 503 deletions
diff --git a/drivers/staging/fsl_dpa_offload/dpa_stats.c b/drivers/staging/fsl_dpa_offload/dpa_stats.c index 49ef4cb..ef6dd1a 100644 --- a/drivers/staging/fsl_dpa_offload/dpa_stats.c +++ b/drivers/staging/fsl_dpa_offload/dpa_stats.c @@ -114,6 +114,46 @@ static int check_dpa_stats_params(const struct dpa_stats_params *params) return 0; } +static int set_cnt_classif_tbl_retrieve_func(struct dpa_stats_cnt_cb *cnt_cb) +{ + switch (cnt_cb->tbl_cb.type) { + case DPA_CLS_TBL_HASH: + cnt_cb->f_get_cnt_stats = get_cnt_cls_tbl_hash_stats; + break; + case DPA_CLS_TBL_INDEXED: + cnt_cb->f_get_cnt_stats = get_cnt_cls_tbl_index_stats; + break; + case DPA_CLS_TBL_EXACT_MATCH: + cnt_cb->f_get_cnt_stats = get_cnt_cls_tbl_match_stats; + break; + default: + log_err("Unsupported DPA Classifier table type %d\n", + cnt_cb->tbl_cb.type); + return -EINVAL; + } + return 0; +} + +static int set_cnt_classif_node_retrieve_func(struct dpa_stats_cnt_cb *cnt_cb, + enum dpa_stats_classif_node_type ccnode_type) +{ + switch (ccnode_type) { + case DPA_CLS_TBL_HASH: + cnt_cb->f_get_cnt_stats = get_cnt_ccnode_hash_stats; + break; + case DPA_CLS_TBL_INDEXED: + cnt_cb->f_get_cnt_stats = get_cnt_ccnode_index_stats; + break; + case DPA_CLS_TBL_EXACT_MATCH: + cnt_cb->f_get_cnt_stats = get_cnt_ccnode_match_stats; + break; + default: + log_err("Unsupported Classification Node type %d", ccnode_type); + return -EINVAL; + } + return 0; +} + static int check_tbl_cls_counter(struct dpa_stats_cnt_cb *cnt_cb, struct dpa_stats_lookup_key *entry) { @@ -132,7 +172,6 @@ static int check_tbl_cls_counter(struct dpa_stats_cnt_cb *cnt_cb, dump_lookup_key(&entry->key); return -EIO; } - cnt_cb->f_get_cnt_stats = get_cnt_cls_tbl_hash_stats; break; case DPA_CLS_TBL_INDEXED: err = FM_PCD_MatchTableGetKeyStatistics( @@ -145,7 +184,6 @@ static int check_tbl_cls_counter(struct dpa_stats_cnt_cb *cnt_cb, dump_lookup_key(&entry->key); return -EIO; } - cnt_cb->f_get_cnt_stats = get_cnt_cls_tbl_index_stats; break; case DPA_CLS_TBL_EXACT_MATCH: err = FM_PCD_MatchTableFindNGetKeyStatistics(entry->cc_node, @@ -159,7 +197,6 @@ static int check_tbl_cls_counter(struct dpa_stats_cnt_cb *cnt_cb, dump_lookup_key(&entry->key); return -EINVAL; } - cnt_cb->f_get_cnt_stats = get_cnt_cls_tbl_match_stats; break; default: log_err("Unsupported DPA Classifier table type %d\n", @@ -189,7 +226,6 @@ static int check_ccnode_counter(struct dpa_stats_cnt_cb *cnt_cb, dump_lookup_key(key); return -EIO; } - cnt_cb->f_get_cnt_stats = get_cnt_ccnode_hash_stats; break; case DPA_STATS_CLASSIF_NODE_INDEXED: err = FM_PCD_MatchTableGetKeyStatistics( @@ -203,7 +239,6 @@ static int check_ccnode_counter(struct dpa_stats_cnt_cb *cnt_cb, dump_lookup_key(key); return -EIO; } - cnt_cb->f_get_cnt_stats = get_cnt_ccnode_index_stats; break; case DPA_STATS_CLASSIF_NODE_EXACT_MATCH: err = FM_PCD_MatchTableFindNGetKeyStatistics( @@ -217,7 +252,6 @@ static int check_ccnode_counter(struct dpa_stats_cnt_cb *cnt_cb, dump_lookup_key(key); return -EINVAL; } - cnt_cb->f_get_cnt_stats = get_cnt_ccnode_match_stats; break; default: log_err("Unsupported Classification Node type %d", @@ -227,6 +261,47 @@ static int check_ccnode_counter(struct dpa_stats_cnt_cb *cnt_cb, return 0; } +static int check_ccnode_miss_counter(void *cc_node, uint32_t id, + enum dpa_stats_classif_node_type ccnode_type) +{ + t_FmPcdCcKeyStatistics stats; + int err; + + switch (ccnode_type) { + case DPA_STATS_CLASSIF_NODE_HASH: + err = FM_PCD_HashTableGetMissStatistics(cc_node, &stats); + if (err != 0) { + log_err("Check failed for Classification Node counter " + "id %d due to incorrect parameters: handle=" + "0x%p\n", id, cc_node); + return -EIO; + } + break; + case DPA_STATS_CLASSIF_NODE_INDEXED: + err = FM_PCD_MatchTableGetMissStatistics(cc_node, &stats); + if (err != 0) { + log_err("Check failed for Classification Node counter " + "id %d due to incorrect parameters: handle=0x%p" + "\n", id, cc_node); + return -EIO; + } + break; + case DPA_STATS_CLASSIF_NODE_EXACT_MATCH: + err = FM_PCD_MatchTableGetMissStatistics(cc_node, &stats); + if (err != 0) { + log_err("Check failed for Classification Node counter " + "id %d due to incorrect parameters: handle=0x%p" + "\n", id, cc_node); + return -EINVAL; + } + break; + default: + log_err("Unsupported Classification Node type %d", ccnode_type); + return -EINVAL; + } + return 0; +} + static int get_new_cnt(struct dpa_stats *dpa_stats, struct dpa_stats_cnt_cb **cnt_cb) { @@ -344,8 +419,7 @@ static int put_cnt(struct dpa_stats *dpa_stats, struct dpa_stats_cnt_cb *cnt_cb) } /* Mark the Counter id as 'not used' */ - dpa_stats->used_cnt_ids[cnt_cb->index] = - DPA_OFFLD_INVALID_OBJECT_ID; + dpa_stats->used_cnt_ids[cnt_cb->index] = DPA_OFFLD_INVALID_OBJECT_ID; /* Clear all 'cnt_cb' information */ cnt_cb->index = DPA_OFFLD_INVALID_OBJECT_ID; @@ -627,7 +701,7 @@ static int free_resources(void) /* Sanity check */ if (!gbl_dpa_stats) { log_err("DPA Stats component is not initialized\n"); - return; + return 0; } dpa_stats = gbl_dpa_stats; @@ -1149,11 +1223,20 @@ static int set_frag_manip(int td, struct dpa_stats_lookup_key *entry) struct t_FmPcdManipStats stats; int err = 0; - err = dpa_classif_table_lookup_by_key(td, &entry->key, &action); - if (err != 0) { - log_err("Cannot retrieve next action parameters from table " - "%d\n", td); - return -EINVAL; + if (entry->miss_key) { + err = dpa_classif_get_miss_action(td, &action); + if (err != 0) { + log_err("Cannot retrieve miss action parameters from " + "table %d\n", td); + return -EINVAL; + } + } else { + err = dpa_classif_table_lookup_by_key(td, &entry->key, &action); + if (err != 0) { + log_err("Cannot retrieve next action parameters from " + "table %d\n", td); + return -EINVAL; + } } if (action.type != DPA_CLS_TBL_ACTION_ENQ) { @@ -1175,7 +1258,6 @@ static int set_frag_manip(int td, struct dpa_stats_lookup_key *entry) log_err("Invalid Fragmentation manip handle\n"); return -EINVAL; } - return 0; } @@ -1447,13 +1529,6 @@ static int set_cnt_classif_tbl_cb(struct dpa_stats_cnt_cb *cnt_cb, return -EINVAL; } - /* Copy the key descriptor */ - err = copy_key_descriptor(&prm.key, &cnt_tbl_cb->keys[0].key); - if (err != 0) { - log_err("Cannot copy key descriptor from user parameters\n"); - return -EINVAL; - } - /* Store CcNode handle and set number of keys to one */ cnt_tbl_cb->keys[0].cc_node = cls_tbl.cc_node; cnt_tbl_cb->keys[0].valid = TRUE; @@ -1462,11 +1537,35 @@ static int set_cnt_classif_tbl_cb(struct dpa_stats_cnt_cb *cnt_cb, /* Store DPA Classifier Table type */ cnt_tbl_cb->type = cls_tbl.type; - /* Check the Classifier Table counter */ - err = check_tbl_cls_counter(cnt_cb, &cnt_tbl_cb->keys[0]); + /* Set retrieve function depending on table type */ + err = set_cnt_classif_tbl_retrieve_func(cnt_cb); if (err != 0) return -EINVAL; + /* Determine if counter is for 'miss' entry or for a valid key */ + if (!prm.key) { + cnt_tbl_cb->keys[0].miss_key = TRUE; + + /* Check the Classifier Table counter parameters for "miss" */ + err = check_ccnode_miss_counter(cnt_tbl_cb->keys[0].cc_node, + cnt_cb->id, cnt_tbl_cb->type); + if (err != 0) + return -EINVAL; + } else { + /* Copy the key descriptor */ + err = copy_key_descriptor(prm.key, &cnt_tbl_cb->keys[0].key); + if (err != 0) { + log_err("Cannot copy key descriptor from user " + "parameters\n"); + return -EINVAL; + } + + /* Check the Classifier Table counter */ + err = check_tbl_cls_counter(cnt_cb, &cnt_tbl_cb->keys[0]); + if (err != 0) + return -EINVAL; + } + if (frag_stats) { err = set_frag_manip(prm.td, &cnt_tbl_cb->keys[0]); if (err < 0) { @@ -1518,23 +1617,40 @@ static int set_cnt_ccnode_cb(struct dpa_stats_cnt_cb *cnt_cb, return -EFAULT; } - /* Copy the key descriptor */ - err = copy_key_descriptor(&prm.key, &cnt_cb->ccnode_cb.keys[0]); - if (err != 0) { - log_err("Cannot copy key descriptor from user parameters\n"); - return -EINVAL; - } - /* Store CcNode handle and set number of keys to one */ cnt_cb->ccnode_cb.cc_node = prm.cc_node; cnt_cb->members_num = 1; - /* Check the Classifier Node counter parameters */ - err = check_ccnode_counter(cnt_cb, - prm.ccnode_type, &cnt_cb->ccnode_cb.keys[0]); + /* Set retrieve function depending on counter type */ + err = set_cnt_classif_node_retrieve_func(cnt_cb, prm.ccnode_type); if (err != 0) return -EINVAL; + if (!params->classif_node_params.key) { + /* Set the key byte to NULL, to mark it for 'miss' entry */ + cnt_cb->ccnode_cb.keys[0].byte = NULL; + + /* Check the Classifier Node counter parameters for 'miss' */ + err = check_ccnode_miss_counter(cnt_cb->ccnode_cb.cc_node, + cnt_cb->id, prm.ccnode_type); + if (err != 0) + return -EINVAL; + } else { + /* Copy the key descriptor */ + err = copy_key_descriptor(prm.key, &cnt_cb->ccnode_cb.keys[0]); + if (err != 0) { + log_err("Cannot copy key descriptor from user " + "parameters\n"); + return -EINVAL; + } + + /* Check the Classifier Node counter parameters */ + err = check_ccnode_counter(cnt_cb, prm.ccnode_type, + &cnt_cb->ccnode_cb.keys[0]); + if (err != 0) + return -EINVAL; + } + /* Map Classif Node counter selection to CcNode statistics */ cnt_sel_to_stats(&cnt_cb->info, dpa_stats->stats_sel[DPA_STATS_CNT_CLASSIF_NODE], @@ -1907,36 +2023,49 @@ static int set_cls_cnt_plcr_cb(struct dpa_stats_cnt_cb *cnt_cb, } static int set_cls_cnt_classif_tbl_pair( - struct dpa_stats_cnt_classif_tbl_cb *cnt_tbl_cb, int td, + struct dpa_stats_cnt_cb *cnt_cb, int td, const struct dpa_offload_lookup_key_pair *pair, struct dpa_stats_lookup_key *lookup_key) { + struct dpa_stats_cnt_classif_tbl_cb *cnt_tbl_cb = &cnt_cb->tbl_cb; struct dpa_cls_tbl_params cls_tbl; struct dpa_offload_lookup_key tbl_key; struct dpa_cls_tbl_action action; int err = 0; - /* Check that key byte is not NULL */ - if (!pair->first_key.byte) { - log_err("First key descriptor byte of the user pair cannot be " - "NULL for table descriptor %d\n", td); - return -EFAULT; - } + /* If either the entire 'pair' or the first key is NULL, then retrieve + * the action associated with the 'miss action '*/ + if ((!pair) || (pair && !pair->first_key)) { + err = dpa_classif_get_miss_action(td, &action); + if (err != 0) { + log_err("Cannot retrieve miss action parameters for " + "table descriptor %d\n", td); + return -EINVAL; + } + } else { + /* Check that key byte is not NULL */ + if (!pair->first_key->byte) { + log_err("First key descriptor byte of the user pair " + "cannot be NULL for table descriptor %d\n", td); + return -EFAULT; + } - /* Copy first key descriptor parameters*/ - err = copy_key_descriptor(&pair->first_key, &tbl_key); - if (err != 0) { - log_err("Cannot copy first key descriptor of the user pair\n"); - return -EINVAL; - } + /* Copy first key descriptor parameters*/ + err = copy_key_descriptor(pair->first_key, &tbl_key); + if (err != 0) { + log_err("Cannot copy second key descriptor of " + "the user pair\n"); + return -EINVAL; + } - /* Use the first key of the pair to lookup in the classifier - * table the next table connected on a "next-action" */ - err = dpa_classif_table_lookup_by_key(td, &tbl_key, &action); - if (err != 0) { - log_err("Cannot retrieve next action parameters for table " - "descriptor %d\n", td); - return -EINVAL; + /* Use the first key of the pair to lookup in the classifier + * table the next table connected on a "next-action" */ + err = dpa_classif_table_lookup_by_key(td, &tbl_key, &action); + if (err != 0) { + log_err("Cannot retrieve next action parameters for " + "table descriptor %d\n", td); + return -EINVAL; + } } if (action.type != DPA_CLS_TBL_ACTION_NEXT_TABLE) { @@ -1956,23 +2085,41 @@ static int set_cls_cnt_classif_tbl_pair( /* Store DPA Classifier Table type */ cnt_tbl_cb->type = cls_tbl.type; + /* Set retrieve function depending on table type */ + set_cnt_classif_tbl_retrieve_func(cnt_cb); + /* Store CcNode handle */ lookup_key->cc_node = cls_tbl.cc_node; - /* Set as lookup key the second key descriptor from the pair */ - err = copy_key_descriptor(&pair->second_key, &lookup_key->key); - if (err != 0) { - log_err("Cannot copy second key descriptor of the user pair\n"); - return -EINVAL; + if (!pair || (pair && !pair->second_key)) { + /* Set as the key as "for miss" */ + lookup_key->miss_key = TRUE; + + /* Check the Classifier Table counter parameters for "miss" */ + err = check_ccnode_miss_counter(lookup_key->cc_node, + cnt_cb->id, cnt_tbl_cb->type); + } else { + lookup_key->miss_key = FALSE; + + /* Set as lookup key the second key descriptor from the pair */ + err = copy_key_descriptor(pair->second_key, &lookup_key->key); + if (err != 0) { + log_err("Cannot copy second key descriptor of " + "the user pair\n"); + return -EINVAL; + } + + /* Check the Classifier Table counter */ + err = check_tbl_cls_counter(cnt_cb, lookup_key); } - return 0; + return err; } static int set_cls_cnt_classif_tbl_cb(struct dpa_stats_cnt_cb *cnt_cb, const struct dpa_stats_cls_cnt_params *params) { - struct dpa_stats_cnt_classif_tbl_cb *cnt_tbl_cb = &cnt_cb->tbl_cb; + struct dpa_stats_cnt_classif_tbl_cb *tbl_cb = &cnt_cb->tbl_cb; struct dpa_stats_cls_cnt_classif_tbl prm = params->classif_tbl_params; struct dpa_stats *dpa_stats = cnt_cb->dpa_stats; struct dpa_cls_tbl_params cls_tbl; @@ -2012,11 +2159,17 @@ static int set_cls_cnt_classif_tbl_cb(struct dpa_stats_cnt_cb *cnt_cb, return -EINVAL; } - cnt_tbl_cb->td = params->classif_tbl_params.td; + tbl_cb->td = params->classif_tbl_params.td; cnt_cb->members_num = params->class_members; switch (prm.key_type) { case DPA_STATS_CLASSIF_SINGLE_KEY: + if (!prm.keys) { + log_err("Pointer to the array of keys cannot be NULL " + "for counter id %d\n", cnt_cb->id); + return -EINVAL; + } + /* Get CcNode from table descriptor */ err = dpa_classif_table_get_params(prm.td, &cls_tbl); if (err != 0) { @@ -2026,21 +2179,37 @@ static int set_cls_cnt_classif_tbl_cb(struct dpa_stats_cnt_cb *cnt_cb, } /* Store DPA Classifier Table type */ - cnt_tbl_cb->type = cls_tbl.type; + tbl_cb->type = cls_tbl.type; + + /* Set retrieve function depending on table type */ + set_cnt_classif_tbl_retrieve_func(cnt_cb); for (i = 0; i < params->class_members; i++) { /* Store CcNode handle */ - cnt_tbl_cb->keys[i].cc_node = cls_tbl.cc_node; + tbl_cb->keys[i].cc_node = cls_tbl.cc_node; + + /* Determine if key represents a 'miss' entry */ + if (!prm.keys[i]) { + tbl_cb->keys[i].miss_key = TRUE; + tbl_cb->keys[i].valid = TRUE; + + err = check_ccnode_miss_counter( + tbl_cb->keys[i].cc_node, + cnt_cb->id, tbl_cb->type); + if (err != 0) + return -EINVAL; + continue; + } - if (!prm.keys[i].byte) { + if (!prm.keys[i]->byte) { /* Key is not valid for now */ - cnt_tbl_cb->keys[i].valid = FALSE; + tbl_cb->keys[i].valid = FALSE; continue; } /* Copy the key descriptor */ - err = copy_key_descriptor(&prm.keys[i], - &cnt_tbl_cb->keys[i].key); + err = copy_key_descriptor(prm.keys[i], + &tbl_cb->keys[i].key); if (err != 0) { log_err("Cannot copy key descriptor from user " "parameters\n"); @@ -2048,37 +2217,39 @@ static int set_cls_cnt_classif_tbl_cb(struct dpa_stats_cnt_cb *cnt_cb, } /* Check the Classifier Table counter */ - err = check_tbl_cls_counter(cnt_cb, - &cnt_tbl_cb->keys[i]); + err = check_tbl_cls_counter(cnt_cb, &tbl_cb->keys[i]); if (err != 0) return -EINVAL; - cnt_tbl_cb->keys[i].valid = TRUE; + tbl_cb->keys[i].valid = TRUE; } break; case DPA_STATS_CLASSIF_PAIR_KEY: + if (!prm.pairs) { + log_err("Pointer to the array of pairs cannot be NULL " + "for counter id %d\n", cnt_cb->id); + return -EINVAL; + } + for (i = 0; i < params->class_members; i++) { - if (!prm.pairs[i].first_key.byte) { - /* Key is not valid for now */ - cnt_tbl_cb->keys[i].valid = FALSE; - continue; + if (prm.pairs[i]) { + if (prm.pairs[i]->first_key) { + if (!prm.pairs[i]->first_key->byte) { + /* Key is not valid for now */ + tbl_cb->keys[i].valid = FALSE; + continue; + } + } } - err = set_cls_cnt_classif_tbl_pair(cnt_tbl_cb, prm.td, - &prm.pairs[i], &cnt_tbl_cb->keys[i]); + err = set_cls_cnt_classif_tbl_pair(cnt_cb, prm.td, + prm.pairs[i], &tbl_cb->keys[i]); if (err != 0) { log_err("Cannot set classifier table pair key " "for counter id %d\n", cnt_cb->id); return -EINVAL; } - - /* Check the Classifier Table counter */ - err = check_tbl_cls_counter(cnt_cb, - &cnt_tbl_cb->keys[i]); - if (err != 0) - return -EINVAL; - - cnt_tbl_cb->keys[i].valid = TRUE; + tbl_cb->keys[i].valid = TRUE; } break; default: @@ -2092,7 +2263,7 @@ static int set_cls_cnt_classif_tbl_cb(struct dpa_stats_cnt_cb *cnt_cb, if (frag_stats) { /* For every valid key, retrieve the hmcd */ for (i = 0; i < params->class_members; i++) { - if (!cnt_tbl_cb->keys[i].valid) + if (!tbl_cb->keys[i].valid) continue; err = set_frag_manip(prm.td, &cnt_cb->tbl_cb.keys[i]); @@ -2148,24 +2319,46 @@ static int set_cls_cnt_ccnode_cb(struct dpa_stats_cnt_cb *cnt_cb, return -EFAULT; } + if (!prm.keys) { + log_err("Pointer to the array of keys cannot be NULL " + "for counter id %d\n", cnt_cb->id); + return -EINVAL; + } + cnt_cb->ccnode_cb.cc_node = prm.cc_node; cnt_cb->members_num = params->class_members; + /* Set retrieve function depending on counter type */ + err = set_cnt_classif_node_retrieve_func(cnt_cb, prm.ccnode_type); + if (err != 0) + return -EINVAL; + for (i = 0; i < params->class_members; i++) { - /* Copy the key descriptor */ - err = copy_key_descriptor(&prm.keys[i], - &cnt_cb->ccnode_cb.keys[i]); - if (err != 0) { - log_err("Cannot copy key descriptor from user " - "parameters\n"); - return -EINVAL; - } + if (!prm.keys[i]) { + /* Set the key byte to NULL, to mark it for 'miss' */ + cnt_cb->ccnode_cb.keys[i].byte = NULL; - /* Check the Classifier Node counter parameters */ - err = check_ccnode_counter(cnt_cb, - prm.ccnode_type, &cnt_cb->ccnode_cb.keys[i]); - if (err != 0) - return -EINVAL; + /* Check the Classifier Node counter parameters */ + err = check_ccnode_miss_counter(prm.cc_node, + cnt_cb->id, prm.ccnode_type); + if (err != 0) + return -EINVAL; + } else { + /* Copy the key descriptor */ + err = copy_key_descriptor(prm.keys[i], + &cnt_cb->ccnode_cb.keys[i]); + if (err != 0) { + log_err("Cannot copy key descriptor from user " + "parameters\n"); + return -EINVAL; + } + + /* Check the Classifier Node counter parameters */ + err = check_ccnode_counter(cnt_cb, prm.ccnode_type, + &cnt_cb->ccnode_cb.keys[i]); + if (err != 0) + return -EINVAL; + } } /* Map Classif Node counter selection to CcNode statistics */ @@ -2335,8 +2528,7 @@ static int set_cls_cnt_traffic_mng_cb(struct dpa_stats_cnt_cb *cnt_cb, } int set_classif_tbl_member(const struct dpa_stats_cls_member_params *prm, - int member_index, - struct dpa_stats_cnt_cb *cnt_cb) + int mbr_idx, struct dpa_stats_cnt_cb *cnt_cb) { struct dpa_stats_cnt_classif_tbl_cb *tbl_cb = &cnt_cb->tbl_cb; uint32_t i = 0; @@ -2351,67 +2543,80 @@ int set_classif_tbl_member(const struct dpa_stats_cls_member_params *prm, } /* Check that member index does not exceeds class size */ - if (member_index < 0 || member_index >= cnt_cb->members_num) { + if (mbr_idx < 0 || mbr_idx >= cnt_cb->members_num) { log_err("Parameter member_index %d must be in range (0 - %d) " - "for counter id %d\n", member_index, + "for counter id %d\n", mbr_idx, cnt_cb->members_num - 1, cnt_cb->id); return -EINVAL; } /* Release the old key memory */ - kfree(tbl_cb->keys[member_index].key.byte); - tbl_cb->keys[member_index].key.byte = NULL; + kfree(tbl_cb->keys[mbr_idx].key.byte); + tbl_cb->keys[mbr_idx].key.byte = NULL; - kfree(tbl_cb->keys[member_index].key.mask); - tbl_cb->keys[member_index].key.mask = NULL; + kfree(tbl_cb->keys[mbr_idx].key.mask); + tbl_cb->keys[mbr_idx].key.mask = NULL; /* Reset the statistics */ for (i = 0; i < cnt_cb->info.stats_num; i++) { - cnt_cb->info.stats[member_index][i] = 0; - cnt_cb->info.last_stats[member_index][i] = 0; - } - - if ((prm->type == DPA_STATS_CLS_MEMBER_SINGLE_KEY && !prm->key.byte) || - (prm->type == DPA_STATS_CLS_MEMBER_PAIR_KEY && - !prm->pair.first_key.byte)) { - /* Mark the key as invalid */ - tbl_cb->keys[member_index].valid = FALSE; - return 0; - } else { - tbl_cb->keys[member_index].valid = TRUE; - - if (prm->type == DPA_STATS_CLS_MEMBER_SINGLE_KEY) { + cnt_cb->info.stats[mbr_idx][i] = 0; + cnt_cb->info.last_stats[mbr_idx][i] = 0; + } + + if (prm->type == DPA_STATS_CLS_MEMBER_SINGLE_KEY) { + if (!prm->key) { + /* Mark the key as 'miss' entry */ + tbl_cb->keys[mbr_idx].miss_key = TRUE; + tbl_cb->keys[mbr_idx].valid = TRUE; + return 0; + } else if (!prm->key->byte) { + /* Mark the key as invalid */ + tbl_cb->keys[mbr_idx].valid = FALSE; + tbl_cb->keys[mbr_idx].miss_key = FALSE; + return 0; + } else { /* Copy the key descriptor */ - err = copy_key_descriptor(&prm->key, - &tbl_cb->keys[member_index].key); + err = copy_key_descriptor(prm->key, + &tbl_cb->keys[mbr_idx].key); if (err != 0) { log_err("Cannot copy key descriptor from user " "parameters\n"); return -EINVAL; } - } else { - err = set_cls_cnt_classif_tbl_pair(tbl_cb, tbl_cb->td, - &prm->pair, &tbl_cb->keys[member_index]); - if (err != 0) { - log_err("Cannot configure the pair key for " - "counter id %d of member %d\n", - cnt_cb->id, member_index); - return -EINVAL; - } } - if (cnt_cb->f_get_cnt_stats != get_cnt_cls_tbl_frag_stats) { + } else { + if (prm->pair) + if (prm->pair->first_key) + if (!prm->pair->first_key->byte) { + /* Mark the key as invalid */ + tbl_cb->keys[mbr_idx].valid = FALSE; + tbl_cb->keys[mbr_idx].miss_key = FALSE; + return 0; + } + err = set_cls_cnt_classif_tbl_pair(cnt_cb, tbl_cb->td, + prm->pair, &tbl_cb->keys[mbr_idx]); + if (err != 0) { + log_err("Cannot configure the pair key for counter id " + "%d of member %d\n", cnt_cb->id, mbr_idx); + return -EINVAL; + } + } + + tbl_cb->keys[mbr_idx].valid = TRUE; + + if (cnt_cb->f_get_cnt_stats != get_cnt_cls_tbl_frag_stats) { + if (!tbl_cb->keys[mbr_idx].miss_key) { err = check_tbl_cls_counter(cnt_cb, - &tbl_cb->keys[member_index]); + &tbl_cb->keys[mbr_idx]); if (err != 0) return -EINVAL; - } else{ - err = set_frag_manip(tbl_cb->td, - &tbl_cb->keys[member_index]); - if (err < 0) { - log_err("Invalid Fragmentation manip handle for" - " counter id %d\n", cnt_cb->id); - return -EINVAL; - } + } + } else{ + err = set_frag_manip(tbl_cb->td, &tbl_cb->keys[mbr_idx]); + if (err < 0) { + log_err("Invalid Fragmentation manip handle for" + " counter id %d\n", cnt_cb->id); + return -EINVAL; } } @@ -2662,11 +2867,19 @@ static int get_cnt_cls_tbl_match_stats(struct dpa_stats_req_cb *req_cb, cnt_cb->info.stats_num; continue; } - err = FM_PCD_MatchTableFindNGetKeyStatistics( - cnt_cb->tbl_cb.keys[i].cc_node, - cnt_cb->tbl_cb.keys[i].key.size, - cnt_cb->tbl_cb.keys[i].key.byte, - cnt_cb->tbl_cb.keys[i].key.mask, &stats); + + if (cnt_cb->tbl_cb.keys[i].miss_key) { + err = FM_PCD_MatchTableGetMissStatistics( + cnt_cb->tbl_cb.keys[i].cc_node, &stats); + } else { + err = FM_PCD_MatchTableFindNGetKeyStatistics( + cnt_cb->tbl_cb.keys[i].cc_node, + cnt_cb->tbl_cb.keys[i].key.size, + cnt_cb->tbl_cb.keys[i].key.byte, + cnt_cb->tbl_cb.keys[i].key.mask, + &stats); + } + if (err != 0) { log_err("Cannot retrieve Classifier Exact Match Table " "statistics for counter id %d\n", cnt_cb->id); @@ -2696,11 +2909,17 @@ static int get_cnt_cls_tbl_hash_stats(struct dpa_stats_req_cb *req_cb, cnt_cb->info.stats_num; continue; } - err = FM_PCD_HashTableFindNGetKeyStatistics( - cnt_cb->tbl_cb.keys[i].cc_node, - cnt_cb->tbl_cb.keys[i].key.size, - cnt_cb->tbl_cb.keys[i].key.byte, - &stats); + + if (cnt_cb->tbl_cb.keys[i].miss_key) { + err = FM_PCD_HashTableGetMissStatistics( + cnt_cb->tbl_cb.keys[i].cc_node, &stats); + } else { + err = FM_PCD_HashTableFindNGetKeyStatistics( + cnt_cb->tbl_cb.keys[i].cc_node, + cnt_cb->tbl_cb.keys[i].key.size, + cnt_cb->tbl_cb.keys[i].key.byte, + &stats); + } if (err != 0) { log_err("Cannot retrieve Classifier Hash Table " "statistics for counter id %d\n", cnt_cb->id); @@ -2730,10 +2949,17 @@ static int get_cnt_cls_tbl_index_stats(struct dpa_stats_req_cb *req_cb, cnt_cb->info.stats_num; continue; } - err = FM_PCD_MatchTableGetKeyStatistics( - cnt_cb->tbl_cb.keys[i].cc_node, - cnt_cb->tbl_cb.keys[i].key.byte[0], - &stats); + + if (cnt_cb->tbl_cb.keys[i].miss_key) { + err = FM_PCD_MatchTableGetMissStatistics( + cnt_cb->tbl_cb.keys[i].cc_node, &stats); + } else { + err = FM_PCD_MatchTableGetKeyStatistics( + cnt_cb->tbl_cb.keys[i].cc_node, + cnt_cb->tbl_cb.keys[i].key.byte[0], + &stats); + } + if (err != 0) { log_err("Cannot retrieve Classifier Indexed Table " "statistics for counter id %d\n", cnt_cb->id); @@ -2786,11 +3012,16 @@ static int get_cnt_ccnode_match_stats(struct dpa_stats_req_cb *req_cb, int err = 0; for (i = 0; i < cnt_cb->members_num; i++) { - err = FM_PCD_MatchTableFindNGetKeyStatistics( + if (!cnt_cb->ccnode_cb.keys[i].byte) { + err = FM_PCD_MatchTableGetMissStatistics( + cnt_cb->ccnode_cb.cc_node, &stats); + } else { + err = FM_PCD_MatchTableFindNGetKeyStatistics( cnt_cb->ccnode_cb.cc_node, cnt_cb->ccnode_cb.keys[i].size, cnt_cb->ccnode_cb.keys[i].byte, cnt_cb->ccnode_cb.keys[i].mask, &stats); + } if (err != 0) { log_err("Cannot retrieve Classification Cc Node Exact " "Match statistics for counter id %d\n", @@ -2811,10 +3042,16 @@ static int get_cnt_ccnode_hash_stats(struct dpa_stats_req_cb *req_cb, int err = 0; for (i = 0; i < cnt_cb->members_num; i++) { - err = FM_PCD_HashTableFindNGetKeyStatistics( + if (!cnt_cb->ccnode_cb.keys[i].byte) { + err = FM_PCD_HashTableGetMissStatistics( + cnt_cb->ccnode_cb.cc_node, &stats); + } else { + err = FM_PCD_HashTableFindNGetKeyStatistics( cnt_cb->ccnode_cb.cc_node, cnt_cb->ccnode_cb.keys[i].size, cnt_cb->ccnode_cb.keys[i].byte, &stats); + } + if (err != 0) { log_err("Cannot retrieve Classification Cc Node Hash " "statistics for counter id %d\n", cnt_cb->id); @@ -2834,9 +3071,14 @@ static int get_cnt_ccnode_index_stats(struct dpa_stats_req_cb *req_cb, int err = 0; for (i = 0; i < cnt_cb->members_num; i++) { - err = FM_PCD_MatchTableGetKeyStatistics( + if (!cnt_cb->ccnode_cb.keys[i].byte) { + err = FM_PCD_MatchTableGetMissStatistics( + cnt_cb->ccnode_cb.cc_node, &stats); + } else { + err = FM_PCD_MatchTableGetKeyStatistics( cnt_cb->ccnode_cb.cc_node, cnt_cb->ccnode_cb.keys[i].byte[0], &stats); + } if (err != 0) { log_err("Cannot retrieve Classification Cc Node Index " "statistics for counter id %d\n", cnt_cb->id); @@ -3283,6 +3525,7 @@ int dpa_stats_create_class_counter(int dpa_stats_id, break; case DPA_STATS_CNT_CLASSIF_TBL: cnt_cb->type = DPA_STATS_CNT_CLASSIF_TBL; + cnt_cb->f_get_cnt_stats = get_cnt_cls_tbl_match_stats; err = set_cls_cnt_classif_tbl_cb(cnt_cb, params); if (err != 0) { @@ -3406,7 +3649,7 @@ int dpa_stats_modify_class_counter(int dpa_stats_cnt_id, } if (params->type == DPA_STATS_CLS_MEMBER_SINGLE_KEY || - params->type == DPA_STATS_CLS_MEMBER_PAIR_KEY) { + params->type == DPA_STATS_CLS_MEMBER_PAIR_KEY) { /* Modify classifier table class member */ err = set_classif_tbl_member(params, member_index, cnt_cb); if (err < 0) { diff --git a/drivers/staging/fsl_dpa_offload/dpa_stats.h b/drivers/staging/fsl_dpa_offload/dpa_stats.h index a429258..5843dca 100644 --- a/drivers/staging/fsl_dpa_offload/dpa_stats.h +++ b/drivers/staging/fsl_dpa_offload/dpa_stats.h @@ -114,6 +114,7 @@ struct dpa_stats_lookup_key { struct dpa_offload_lookup_key key; /* Key descriptor */ bool valid; /* Lookup key is valid */ void *frag; /* Fragmentation handle corresponding to this key */ + bool miss_key; /* Provide statistics for miss entry */ }; /* DPA Stats Classif Table control block */ diff --git a/drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h b/drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h index 070a6f0..d375a0f 100644 --- a/drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h +++ b/drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h @@ -116,14 +116,14 @@ struct compat_ioc_dpa_offld_lookup_key { struct dpa_stats_compat_cnt_classif_tbl { int td; - struct compat_ioc_dpa_offld_lookup_key key; + compat_uptr_t key; unsigned int cnt_sel; }; struct dpa_stats_compat_cnt_classif_node { compat_uptr_t cc_node; enum dpa_stats_classif_node_type ccnode_type; - struct compat_ioc_dpa_offld_lookup_key key; + compat_uptr_t key; unsigned int cnt_sel; }; @@ -202,15 +202,15 @@ struct compat_ioc_dpa_stats_cls_cnt_params { }; struct compat_ioc_dpa_offld_lookup_key_pair { - struct compat_ioc_dpa_offld_lookup_key first_key; - struct compat_ioc_dpa_offld_lookup_key second_key; + compat_uptr_t first_key; + compat_uptr_t second_key; }; struct dpa_stats_compat_cls_member_params { enum dpa_stats_cls_member_type type; union { - struct compat_ioc_dpa_offld_lookup_key key; - struct compat_ioc_dpa_offld_lookup_key_pair pair; + compat_uptr_t key; + compat_uptr_t pair; int sa_id; }; }; diff --git a/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c b/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c index 5c2cb90..0fdcdc5 100644 --- a/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c +++ b/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c @@ -90,7 +90,10 @@ static long wrp_dpa_stats_do_ioctl(struct file *filp, unsigned int cmd, unsigned long args); static int copy_key_descriptor(struct dpa_offload_lookup_key *src, - struct dpa_offload_lookup_key *dst); + struct dpa_offload_lookup_key **dst); + +static int copy_pair_descriptor(struct dpa_offload_lookup_key_pair *src, + struct dpa_offload_lookup_key_pair **dst); static int copy_class_members(void *objs, unsigned int size, void *dst); @@ -103,8 +106,12 @@ static long wrp_dpa_stats_do_compat_ioctl(struct file *filp, unsigned long args); static int copy_key_descriptor_compatcpy( - struct dpa_offload_lookup_key *kprm, - const struct compat_ioc_dpa_offld_lookup_key *uprm); + struct dpa_offload_lookup_key **kprm, + compat_uptr_t uparam); + +static int copy_pair_descriptor_compatcpy( + struct dpa_offload_lookup_key_pair **ks_pair, + struct compat_ioc_dpa_offld_lookup_key_pair pair); static void dpa_stats_init_compatcpy( struct ioc_dpa_stats_params *kprm, @@ -625,39 +632,70 @@ static long do_ioctl_stats_free(void *args) static int do_ioctl_stats_create_counter(void *args) { struct ioc_dpa_stats_cnt_params prm; - struct dpa_offload_lookup_key key; + struct dpa_offload_lookup_key *us_key = NULL; long ret = 0; if (copy_from_user(&prm, args, sizeof(prm))) { - log_err("Cannot copy from user the counter parameters\n"); + log_err("Could not copy counter parameters\n"); return -EINVAL; } - if (prm.cnt_params.type == DPA_STATS_CNT_CLASSIF_NODE) - ret = copy_key_descriptor( - &prm.cnt_params.classif_node_params.key, &key); - else if (prm.cnt_params.type == DPA_STATS_CNT_CLASSIF_TBL) - ret = copy_key_descriptor( - &prm.cnt_params.classif_tbl_params.key, &key); - if (ret != 0) { - log_err("Cannot copy the key descriptor\n"); - return -EINVAL; + if (prm.cnt_params.type == DPA_STATS_CNT_CLASSIF_NODE && + prm.cnt_params.classif_node_params.key) { + /* Save user-space provided key */ + us_key = prm.cnt_params.classif_node_params.key; + + /* Override user-space pointers with kernel memory */ + ret = copy_key_descriptor(us_key, + &prm.cnt_params.classif_node_params.key); + if (ret != 0) { + log_err("Could not copy the key descriptor\n"); + kfree(prm.cnt_params.classif_node_params.key); + return ret; + } + } + + if (prm.cnt_params.type == DPA_STATS_CNT_CLASSIF_TBL && + prm.cnt_params.classif_tbl_params.key) { + /* Save user-space provided key */ + us_key = prm.cnt_params.classif_tbl_params.key; + + /* Override user-space pointers with kernel memory */ + ret = copy_key_descriptor(us_key, + &prm.cnt_params.classif_tbl_params.key); + if (ret != 0) { + log_err("Could not copy the key descriptor\n"); + kfree(prm.cnt_params.classif_tbl_params.key); + return ret; + } } ret = dpa_stats_create_counter(prm.stats_id, &prm.cnt_params, &prm.cnt_id); - if (ret < 0) - return ret; - if (copy_to_user(args, &prm, sizeof(prm))) { - log_err("Cannot copy to user the counter parameters\n"); - ret = -EINVAL; + if (prm.cnt_params.type == DPA_STATS_CNT_CLASSIF_NODE && + prm.cnt_params.classif_node_params.key) { + /* Release kernel-allocated memory */ + kfree(prm.cnt_params.classif_node_params.key->byte); + kfree(prm.cnt_params.classif_node_params.key->mask); + kfree(prm.cnt_params.classif_node_params.key); + /* Restore user-provided key */ + prm.cnt_params.classif_node_params.key = us_key; } - if (prm.cnt_params.type == DPA_STATS_CNT_CLASSIF_NODE || - prm.cnt_params.type == DPA_STATS_CNT_CLASSIF_TBL) { - kfree(key.byte); - kfree(key.mask); + if (prm.cnt_params.type == DPA_STATS_CNT_CLASSIF_TBL && + prm.cnt_params.classif_tbl_params.key) { + /* Release kernel-allocated memory */ + kfree(prm.cnt_params.classif_tbl_params.key->byte); + kfree(prm.cnt_params.classif_tbl_params.key->mask); + kfree(prm.cnt_params.classif_tbl_params.key); + /* Restore user-provided key */ + prm.cnt_params.classif_tbl_params.key = us_key; + } + + if (copy_to_user(args, &prm, sizeof(prm))) { + log_err("Could not copy to user the Counter ID\n"); + ret = -EINVAL; } return ret; @@ -702,14 +740,14 @@ static int do_ioctl_stats_compat_create_counter(void *args) &kprm.cnt_params.classif_tbl_params, &uprm.cnt_params.classif_tbl_params); if (ret < 0) - return ret; + goto compat_create_counter_cleanup; break; case DPA_STATS_CNT_CLASSIF_NODE: ret = dpa_stats_ccnode_cnt_compatcpy( &kprm.cnt_params.classif_node_params, &uprm.cnt_params.classif_node_params); if (ret < 0) - return ret; + goto compat_create_counter_cleanup; break; case DPA_STATS_CNT_IPSEC: memcpy(&kprm.cnt_params.ipsec_params, @@ -728,7 +766,7 @@ static int do_ioctl_stats_compat_create_counter(void *args) ret = dpa_stats_create_counter(kprm.stats_id, &kprm.cnt_params, &kprm.cnt_id); if (ret < 0) - return ret; + goto compat_create_counter_cleanup; uprm.cnt_id = kprm.cnt_id; @@ -737,14 +775,20 @@ static int do_ioctl_stats_compat_create_counter(void *args) ret = -EINVAL; } - if (kprm.cnt_params.type == DPA_STATS_CNT_CLASSIF_NODE) { - kfree(kprm.cnt_params.classif_node_params.key.byte); - kfree(kprm.cnt_params.classif_node_params.key.mask); - } else if (kprm.cnt_params.type == DPA_STATS_CNT_CLASSIF_TBL) { - kfree(kprm.cnt_params.classif_tbl_params.key.byte); - kfree(kprm.cnt_params.classif_tbl_params.key.mask); +compat_create_counter_cleanup: + if (kprm.cnt_params.type == DPA_STATS_CNT_CLASSIF_NODE && + compat_ptr(uprm.cnt_params.classif_node_params.key)) { + kfree(kprm.cnt_params.classif_node_params.key->byte); + kfree(kprm.cnt_params.classif_node_params.key->mask); + kfree(kprm.cnt_params.classif_node_params.key); } + if (kprm.cnt_params.type == DPA_STATS_CNT_CLASSIF_TBL && + compat_ptr(uprm.cnt_params.classif_tbl_params.key)) { + kfree(kprm.cnt_params.classif_tbl_params.key->byte); + kfree(kprm.cnt_params.classif_tbl_params.key->mask); + kfree(kprm.cnt_params.classif_tbl_params.key); + } return ret; } #endif @@ -754,9 +798,10 @@ static int do_ioctl_stats_create_class_counter(void *args) struct ioc_dpa_stats_cls_cnt_params prm; struct dpa_stats_cls_cnt_classif_node *cnode; struct dpa_stats_cls_cnt_classif_tbl *tbl; - struct dpa_offload_lookup_key key; - struct dpa_stats_cnt_eth_src *eth_src = NULL; - uint32_t i = 0, eth_src_size = 0; + struct dpa_offload_lookup_key **us_keys = NULL; + struct dpa_offload_lookup_key_pair **us_pairs = NULL; + uint32_t i = 0; + unsigned int cls_mbrs; void *cls_objs = NULL; int *sa_ids = NULL; long ret = 0; @@ -766,13 +811,14 @@ static int do_ioctl_stats_create_class_counter(void *args) return -EINVAL; } + cls_mbrs = prm.cnt_params.class_members; + switch (prm.cnt_params.type) { - case DPA_STATS_CNT_ETH: - eth_src_size = prm.cnt_params.class_members * - sizeof(struct dpa_stats_cnt_eth_src); + case DPA_STATS_CNT_ETH: { + struct dpa_stats_cnt_eth_src *eth_src = NULL; /* Allocate memory to store the sources array */ - eth_src = kmalloc(eth_src_size, GFP_KERNEL); + eth_src = kmalloc(sizeof(*eth_src) * cls_mbrs, GFP_KERNEL); if (!eth_src) { log_err("Cannot allocate memory for Ethernet sources " "array\n"); @@ -781,17 +827,17 @@ static int do_ioctl_stats_create_class_counter(void *args) if (copy_from_user(eth_src, prm.cnt_params.eth_params.src, - eth_src_size)) { + sizeof(*eth_src) * cls_mbrs)) { log_err("Cannot copy array of Ethernet sources\n"); kfree(eth_src); return -EBUSY; } prm.cnt_params.eth_params.src = eth_src; break; + } case DPA_STATS_CNT_REASS: - ret = copy_class_members(cls_objs, - prm.cnt_params.class_members, - prm.cnt_params.reass_params.reass); + ret = copy_class_members(cls_objs, cls_mbrs, + prm.cnt_params.reass_params.reass); if (ret < 0) { log_err("Cannot copy array of Reassembly objects\n"); kfree(cls_objs); @@ -799,8 +845,7 @@ static int do_ioctl_stats_create_class_counter(void *args) } break; case DPA_STATS_CNT_FRAG: - ret = copy_class_members(cls_objs, - prm.cnt_params.class_members, + ret = copy_class_members(cls_objs, cls_mbrs, prm.cnt_params.frag_params.frag); if (ret < 0) { log_err("Cannot copy array of Fragmentation objects\n"); @@ -809,8 +854,7 @@ static int do_ioctl_stats_create_class_counter(void *args) } break; case DPA_STATS_CNT_POLICER: - ret = copy_class_members(cls_objs, - prm.cnt_params.class_members, + ret = copy_class_members(cls_objs, cls_mbrs, prm.cnt_params.plcr_params.plcr); if (ret < 0) { log_err("Cannot copy array of Policer objects\n"); @@ -822,36 +866,50 @@ static int do_ioctl_stats_create_class_counter(void *args) tbl = &prm.cnt_params.classif_tbl_params; if (tbl->key_type == DPA_STATS_CLASSIF_SINGLE_KEY) { - for (i = 0; i < prm.cnt_params.class_members; i++) { - if (!tbl->keys[i].byte) - continue; + /* Save array of user-space provided key pointers */ + us_keys = tbl->keys; + + /* Override user-space pointers with kernel memory */ + tbl->keys = kzalloc(cls_mbrs * + sizeof(**tbl->keys), GFP_KERNEL); + if (!tbl->keys) { + log_err("Cannot allocate kernel memory for " + "lookup keys array\n"); + return -ENOMEM; + } - ret = copy_key_descriptor(&tbl->keys[i], &key); + for (i = 0; i < cls_mbrs; i++) { + if (!us_keys[i]) + continue; + ret = copy_key_descriptor(us_keys[i], + &tbl->keys[i]); if (ret != 0) { - log_err("Cannot copy the key descriptor" - "\n"); - return -EINVAL; + log_err("Cannot copy key descriptor\n"); + goto create_cls_counter_cleanup; } } } else if (tbl->key_type == DPA_STATS_CLASSIF_PAIR_KEY) { - for (i = 0; i < prm.cnt_params.class_members; i++) { - if (!tbl->pairs[i].first_key.byte) - continue; - - ret = copy_key_descriptor( - &tbl->pairs[i].first_key, &key); - if (ret != 0) { - log_err("Cannot copy the first key " - "descriptor of pair-key\n"); - return -EINVAL; - } + /* Save array of user-space provided pairs pointers */ + us_pairs = tbl->pairs; + + /* Override user-space pointers with kernel memory */ + tbl->pairs = kzalloc(cls_mbrs * + sizeof(**tbl->pairs), GFP_KERNEL); + if (!tbl->pairs) { + log_err("Cannot allocate kernel memory for " + "lookup pairs array\n"); + return -ENOMEM; + } - ret = copy_key_descriptor( - &tbl->pairs[i].second_key, &key); + for (i = 0; i < cls_mbrs; i++) { + if (!us_pairs[i]) + continue; + ret = copy_pair_descriptor(us_pairs[i], + &tbl->pairs[i]); if (ret != 0) { - log_err("Cannot copy the second key " - "descriptor of pair-key\n"); - return -EINVAL; + log_err("Could not copy the " + "pair key descriptor\n"); + goto create_cls_counter_cleanup; } } } @@ -859,11 +917,28 @@ static int do_ioctl_stats_create_class_counter(void *args) case DPA_STATS_CNT_CLASSIF_NODE: cnode = &prm.cnt_params.classif_node_params; - for (i = 0; i < prm.cnt_params.class_members; i++) { - ret = copy_key_descriptor(&cnode->keys[i], &key); + if (!cnode->keys) { + log_err("Pointer to array of keys can't be NULL\n"); + return -EINVAL; + } + /* Save array of user-space provided key pointers */ + us_keys = cnode->keys; + + /* Override user-space pointers with kernel memory */ + cnode->keys = kzalloc(cls_mbrs * + sizeof(**cnode->keys), GFP_KERNEL); + if (!cnode->keys) { + log_err("No more memory to store array of keys\n"); + return -ENOMEM; + } + + for (i = 0; i < cls_mbrs; i++) { + if (!us_keys[i]) + continue; + ret = copy_key_descriptor(us_keys[i], &cnode->keys[i]); if (ret != 0) { log_err("Cannot copy the key descriptor\n"); - return -EINVAL; + goto create_cls_counter_cleanup; } } break; @@ -891,17 +966,10 @@ static int do_ioctl_stats_create_class_counter(void *args) ret = dpa_stats_create_class_counter(prm.stats_id, &prm.cnt_params, &prm.cnt_id); - if (ret < 0) - return ret; - - if (copy_to_user(args, &prm, sizeof(prm))) { - log_err("Cannot copy to user class counter parameters\n"); - ret = -EINVAL; - } - +create_cls_counter_cleanup: switch (prm.cnt_params.type) { case DPA_STATS_CNT_ETH: - kfree(eth_src); + kfree(prm.cnt_params.eth_params.src); break; case DPA_STATS_CNT_REASS: case DPA_STATS_CNT_FRAG: @@ -911,25 +979,53 @@ static int do_ioctl_stats_create_class_counter(void *args) case DPA_STATS_CNT_CLASSIF_TBL: tbl = &prm.cnt_params.classif_tbl_params; - for (i = 0; i < prm.cnt_params.class_members; i++) { - if (tbl->key_type == DPA_STATS_CLASSIF_SINGLE_KEY) { - kfree(tbl->keys[i].byte); - kfree(tbl->keys[i].mask); + if (tbl->key_type == DPA_STATS_CLASSIF_SINGLE_KEY) { + for (i = 0; i < cls_mbrs; i++) { + if (!tbl->keys[i]) + continue; + /* Free allocated memory */ + kfree(tbl->keys[i]->byte); + kfree(tbl->keys[i]->mask); + kfree(tbl->keys[i]); } + /* Restore user-space pointers */ + tbl->keys = us_keys; + } + + if (tbl->key_type == DPA_STATS_CLASSIF_PAIR_KEY) { + for (i = 0; i < cls_mbrs; i++) { + if (!tbl->pairs[i]) + continue; - if (tbl->key_type == DPA_STATS_CLASSIF_PAIR_KEY) { - kfree(tbl->pairs[i].first_key.byte); - kfree(tbl->pairs[i].first_key.mask); - kfree(tbl->pairs[i].second_key.byte); - kfree(tbl->pairs[i].second_key.mask); + if (tbl->pairs[i]->first_key) { + kfree(tbl->pairs[i]->first_key->byte); + kfree(tbl->pairs[i]->first_key->mask); + kfree(tbl->pairs[i]->first_key); + } + + if (tbl->pairs[i]->second_key) { + kfree(tbl->pairs[i]->second_key->byte); + kfree(tbl->pairs[i]->second_key->mask); + kfree(tbl->pairs[i]->second_key); + } } + /* Restore user-space pointers */ + tbl->keys = us_keys; } break; case DPA_STATS_CNT_CLASSIF_NODE: - for (i = 0; i < prm.cnt_params.class_members; i++) { - kfree(prm.cnt_params.classif_node_params.keys[i].byte); - kfree(prm.cnt_params.classif_node_params.keys[i].mask); + cnode = &prm.cnt_params.classif_node_params; + + for (i = 0; i < cls_mbrs; i++) { + if (!cnode->keys[i]) + continue; + /* Free allocated memory */ + kfree(cnode->keys[i]->byte); + kfree(cnode->keys[i]->mask); + kfree(cnode->keys[i]); } + /* Restore user-space pointers */ + tbl->keys = us_keys; break; case DPA_STATS_CNT_IPSEC: kfree(sa_ids); @@ -939,6 +1035,11 @@ static int do_ioctl_stats_create_class_counter(void *args) break; } + if (copy_to_user(args, &prm, sizeof(prm))) { + log_err("Cannot copy to user class counter parameters\n"); + ret = -EINVAL; + } + return ret; } @@ -988,46 +1089,18 @@ static int do_ioctl_stats_compat_create_class_counter(void *args) return ret; break; case DPA_STATS_CNT_CLASSIF_TBL: - { - struct dpa_stats_cls_cnt_classif_tbl *tbl = - &kprm_cls->classif_tbl_params; - - ret = dpa_stats_tbl_cls_compatcpy(tbl, + ret = dpa_stats_tbl_cls_compatcpy(&kprm_cls->classif_tbl_params, &uprm_cls->classif_tbl_params, kprm_cls->class_members); if (!ret) break; - - if (tbl->key_type == DPA_STATS_CLASSIF_SINGLE_KEY) { - for (i = 0; i < kprm_cls->class_members; i++) { - kfree(tbl->keys[i].byte); - kfree(tbl->keys[i].mask); - } - kfree(tbl->keys); - - } else if (tbl->key_type == DPA_STATS_CLASSIF_PAIR_KEY) { - for (i = 0; i < kprm_cls->class_members; i++) { - kfree(tbl->pairs[i].first_key.byte); - kfree(tbl->pairs[i].first_key.mask); - kfree(tbl->pairs[i].second_key.byte); - kfree(tbl->pairs[i].second_key.mask); - } - kfree(tbl->pairs); - } - return ret; - } + goto compat_create_cls_counter_cleanup; case DPA_STATS_CNT_CLASSIF_NODE: ret = dpa_stats_ccnode_cls_compatcpy( - &kprm_cls->classif_node_params, - &uprm_cls->ccnode_params, - kprm_cls->class_members); + &kprm_cls->classif_node_params, + &uprm_cls->ccnode_params, kprm_cls->class_members); if (!ret) break; - for (i = 0; i < kprm_cls->class_members; i++) { - kfree(kprm_cls->classif_node_params.keys[i].byte); - kfree(kprm_cls->classif_node_params.keys[i].mask); - } - kfree(kprm_cls->classif_node_params.keys); - return ret; + goto compat_create_cls_counter_cleanup; case DPA_STATS_CNT_IPSEC: ret = dpa_stats_ipsec_cls_compatcpy(&kprm_cls->ipsec_params, &uprm_cls->ipsec_params, kprm_cls->class_members); @@ -1038,10 +1111,10 @@ static int do_ioctl_stats_compat_create_class_counter(void *args) break; } - ret = dpa_stats_create_class_counter( - kprm.stats_id, kprm_cls, &kprm.cnt_id); + ret = dpa_stats_create_class_counter(kprm.stats_id, + kprm_cls, &kprm.cnt_id); if (ret < 0) - return ret; + goto compat_create_cls_counter_cleanup; uprm.cnt_id = kprm.cnt_id; @@ -1050,6 +1123,7 @@ static int do_ioctl_stats_compat_create_class_counter(void *args) ret = -EINVAL; } +compat_create_cls_counter_cleanup: switch (uprm.cnt_params.type) { case DPA_STATS_CNT_ETH: kfree(kprm_cls->eth_params.src); @@ -1070,17 +1144,29 @@ static int do_ioctl_stats_compat_create_class_counter(void *args) if (tbl->key_type == DPA_STATS_CLASSIF_SINGLE_KEY) { for (i = 0; i < kprm_cls->class_members; i++) { - kfree(tbl->keys[i].byte); - kfree(tbl->keys[i].mask); + if (!tbl->keys[i]) + continue; + kfree(tbl->keys[i]->byte); + kfree(tbl->keys[i]->mask); + kfree(tbl->keys[i]); } kfree(tbl->keys); } else if (tbl->key_type == DPA_STATS_CLASSIF_PAIR_KEY) { for (i = 0; i < kprm_cls->class_members; i++) { - kfree(tbl->pairs[i].first_key.byte); - kfree(tbl->pairs[i].first_key.mask); - kfree(tbl->pairs[i].second_key.byte); - kfree(tbl->pairs[i].second_key.mask); + if (!tbl->pairs[i]) + continue; + if (tbl->pairs[i]->first_key) { + kfree(tbl->pairs[i]->first_key->byte); + kfree(tbl->pairs[i]->first_key->mask); + kfree(tbl->pairs[i]->first_key); + } + if (tbl->pairs[i]->second_key) { + kfree(tbl->pairs[i]->second_key->byte); + kfree(tbl->pairs[i]->second_key->mask); + kfree(tbl->pairs[i]->second_key); + } + kfree(tbl->pairs[i]); } kfree(tbl->pairs); } @@ -1088,11 +1174,15 @@ static int do_ioctl_stats_compat_create_class_counter(void *args) } case DPA_STATS_CNT_CLASSIF_NODE: for (i = 0; i < kprm_cls->class_members; i++) { - kfree(kprm_cls->classif_node_params.keys[i].byte); - kfree(kprm_cls->classif_node_params.keys[i].mask); + if (!kprm_cls->classif_node_params.keys[i]) + continue; + kfree(kprm_cls->classif_node_params.keys[i]->byte); + kfree(kprm_cls->classif_node_params.keys[i]->mask); + kfree(kprm_cls->classif_node_params.keys[i]); } kfree(kprm_cls->classif_node_params.keys); break; + case DPA_STATS_CNT_IPSEC: kfree(kprm_cls->ipsec_params.sa_id); break; @@ -1108,8 +1198,9 @@ static int do_ioctl_stats_compat_create_class_counter(void *args) static int do_ioctl_stats_modify_class_counter(void *args) { struct ioc_dpa_stats_cls_member_params prm; - struct dpa_offload_lookup_key key; - int ret; + struct dpa_offload_lookup_key *us_key = NULL; + struct dpa_offload_lookup_key_pair *us_pair = NULL; + int ret = 0; if (copy_from_user(&prm, args, sizeof(prm))) { log_err("Cannot copy from user the class counter parameters\n"); @@ -1118,32 +1209,32 @@ static int do_ioctl_stats_modify_class_counter(void *args) switch (prm.params.type) { case DPA_STATS_CLS_MEMBER_SINGLE_KEY: - if (prm.params.key.byte) { - ret = copy_key_descriptor(&prm.params.key, &key); - if (ret != 0) { - log_err("Cannot copy the key descriptor\n"); - return -EINVAL; - } + if (!prm.params.key) + break; + + /* Save user-space provided key */ + us_key = prm.params.key; + + /* Override user-space pointers with kernel memory */ + ret = copy_key_descriptor(us_key, &prm.params.key); + if (ret != 0) { + log_err("Could not copy the key descriptor\n"); + goto modify_counter_cleanup; } + break; case DPA_STATS_CLS_MEMBER_PAIR_KEY: - if (prm.params.pair.first_key.byte && - prm.params.pair.first_key.mask) { - ret = copy_key_descriptor( - &prm.params.pair.first_key, &key); - if (ret != 0) { - log_err("Cannot copy the first key descriptor " - "of the pair-key\n"); - return -EINVAL; - } + if (!prm.params.pair) + break; - ret = copy_key_descriptor( - &prm.params.pair.second_key, &key); - if (ret != 0) { - log_err("Cannot copy the second key descriptor " - "of the pair-key\n"); - return -EINVAL; - } + /* Save array of user-space provided pairs pointers */ + us_pair = prm.params.pair; + + /* Override user-space pointers with kernel memory */ + ret = copy_pair_descriptor(us_pair, &prm.params.pair); + if (ret != 0) { + log_err("Could not copy the pair key descriptor\n"); + goto modify_counter_cleanup; } break; case DPA_STATS_CLS_MEMBER_SA_ID: @@ -1154,32 +1245,53 @@ static int do_ioctl_stats_modify_class_counter(void *args) ret = dpa_stats_modify_class_counter(prm.cnt_id, &prm.params, prm.member_index); - if (ret < 0) - return ret; - +modify_counter_cleanup: switch (prm.params.type) { case DPA_STATS_CLS_MEMBER_SINGLE_KEY: - kfree(prm.params.key.byte); - kfree(prm.params.key.mask); + if (prm.params.key) { + /* Release kernel-allocated memory */ + kfree(prm.params.key->byte); + kfree(prm.params.key->mask); + kfree(prm.params.key); + /* Restore user-provided key */ + prm.params.key = us_key; + } break; case DPA_STATS_CLS_MEMBER_PAIR_KEY: - kfree(prm.params.pair.first_key.byte); - kfree(prm.params.pair.first_key.mask); - kfree(prm.params.pair.second_key.byte); - kfree(prm.params.pair.second_key.mask); + if (prm.params.pair) { + if (prm.params.pair->first_key) { + /* Release kernel-allocated memory */ + kfree(prm.params.pair->first_key->byte); + kfree(prm.params.pair->first_key->mask); + kfree(prm.params.pair->first_key); + } + if (prm.params.pair->second_key) { + /* Release kernel-allocated memory */ + kfree(prm.params.pair->second_key->byte); + kfree(prm.params.pair->second_key->mask); + kfree(prm.params.pair->second_key); + } + kfree(prm.params.pair); + /* Restore user-provided key */ + prm.params.pair->first_key = us_pair->first_key; + prm.params.pair->second_key = us_pair->second_key; + prm.params.pair = us_pair; + } break; case DPA_STATS_CLS_MEMBER_SA_ID: break; default: + log_err("Invalid class member type\n"); break; } if (copy_to_user(args, &prm, sizeof(prm))) { - log_err("Cannot copy to user the class counter result\n"); - return -EBUSY; + log_err("Could not write " + "dpa_stats_modify_class_counter result\n"); + ret = -EBUSY; } - return 0; + return ret; } #ifdef CONFIG_COMPAT @@ -1187,10 +1299,11 @@ static int do_ioctl_stats_compat_modify_class_counter(void *args) { struct ioc_dpa_stats_cls_member_params kprm; struct compat_ioc_dpa_stats_cls_member_params uprm; + struct compat_ioc_dpa_offld_lookup_key_pair pair; int ret; if (copy_from_user(&uprm, args, sizeof(uprm))) { - log_err("Cannot copy from user the class counter parameters\n"); + log_err("Cannot copy from user the modify counter parameters\n"); return -EINVAL; } @@ -1201,35 +1314,35 @@ static int do_ioctl_stats_compat_modify_class_counter(void *args) switch (kprm.params.type) { case DPA_STATS_CLS_MEMBER_SINGLE_KEY: - if (compat_ptr(uprm.params.key.byte)) { - ret = copy_key_descriptor_compatcpy( - &kprm.params.key, - &uprm.params.key); - if (ret < 0) { - log_err("Cannot copy the key descriptor\n"); - return ret; - } - + if (!compat_ptr(uprm.params.key)) + break; + /* Copy user-provided key descriptor */ + ret = copy_key_descriptor_compatcpy(&kprm.params.key, + uprm.params.key); + if (ret < 0) { + log_err("Cannot copy the key descriptor\n"); + goto compat_modify_counter_cleanup; } break; case DPA_STATS_CLS_MEMBER_PAIR_KEY: - if (compat_ptr(uprm.params.pair.first_key.byte)) { - ret = copy_key_descriptor_compatcpy( - &kprm.params.pair.first_key, - &uprm.params.pair.first_key); - if (ret < 0) - return ret; + if (!compat_ptr(uprm.params.pair)) + break; - ret = copy_key_descriptor_compatcpy( - &kprm.params.pair.second_key, - &uprm.params.pair.second_key); - if (ret != 0) { - log_err("Cannot copy the key descriptor of the " - "pair-key\n"); - return -EINVAL; - } + if (copy_from_user(&pair, compat_ptr(uprm.params.pair), + (sizeof(pair)))) { + log_err("Cannot copy from user array of " + "lookup pairs\n"); + return -EBUSY; + } + + /* Copy user-provided lookup pair descriptor */ + ret = copy_pair_descriptor_compatcpy(&kprm.params.pair, pair); + if (ret < 0) { + log_err("Cannot copy the pair key descriptor\n"); + goto compat_modify_counter_cleanup; } break; + case DPA_STATS_CLS_MEMBER_SA_ID: kprm.params.sa_id = uprm.params.sa_id; break; @@ -1238,34 +1351,45 @@ static int do_ioctl_stats_compat_modify_class_counter(void *args) } ret = dpa_stats_modify_class_counter(kprm.cnt_id, - &kprm.params, kprm.member_index); + &kprm.params, kprm.member_index); if (ret < 0) - return ret; + goto compat_modify_counter_cleanup; uprm.cnt_id = kprm.cnt_id; + if (copy_to_user(args, &uprm, sizeof(uprm))) { + log_err("Cannot copy to user class counter result\n"); + return -EBUSY; + } + +compat_modify_counter_cleanup: switch (kprm.params.type) { case DPA_STATS_CLS_MEMBER_SINGLE_KEY: - kfree(kprm.params.key.byte); - kfree(kprm.params.key.mask); + if (!kprm.params.key) + break; + kfree(kprm.params.key->byte); + kfree(kprm.params.key->mask); + kfree(kprm.params.key); break; case DPA_STATS_CLS_MEMBER_PAIR_KEY: - kfree(kprm.params.pair.first_key.byte); - kfree(kprm.params.pair.first_key.mask); - kfree(kprm.params.pair.second_key.byte); - kfree(kprm.params.pair.second_key.mask); + if (!kprm.params.pair) + break; + if (kprm.params.pair->first_key) { + kfree(kprm.params.pair->first_key->byte); + kfree(kprm.params.pair->first_key->mask); + kfree(kprm.params.pair->first_key); + } + if (kprm.params.pair->second_key) { + kfree(kprm.params.pair->second_key->byte); + kfree(kprm.params.pair->second_key->mask); + kfree(kprm.params.pair->second_key); + } break; case DPA_STATS_CLS_MEMBER_SA_ID: break; default: break; } - - if (copy_to_user(args, &uprm, sizeof(uprm))) { - log_err("Cannot copy to user class counter result\n"); - return -EBUSY; - } - return 0; } #endif @@ -1720,89 +1844,196 @@ static long store_get_cnts_async_params( } static int copy_key_descriptor(struct dpa_offload_lookup_key *src, - struct dpa_offload_lookup_key *tmp) + struct dpa_offload_lookup_key **ks_key) { - if (!src->byte) { - log_err("Key descriptor byte from user cannot be NULL\n"); - return -EINVAL; - } + struct dpa_offload_lookup_key *tmp = NULL; - /* Allocate memory to store the key byte array */ - tmp->byte = kmalloc(src->size, GFP_KERNEL); - if (!tmp->byte) { - log_err("Cannot allocate memory for key descriptor byte\n"); + /* Allocate kernel memory for key descriptor */ + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) { + log_err("Cannot allocate kernel memory for key descriptor\n"); return -ENOMEM; } - if (copy_from_user(tmp->byte, src->byte, src->size)) { - log_err("Cannot copy from user the key descriptor byte\n"); - kfree(tmp->byte); - return -EBUSY; + if (src->byte) { + /* Allocate memory to store the key byte array */ + tmp->byte = kmalloc(src->size, GFP_KERNEL); + if (!tmp->byte) { + log_err("Cannot allocate memory for key " + "descriptor byte\n"); + return -ENOMEM; + } + + if (copy_from_user(tmp->byte, src->byte, src->size)) { + log_err("Cannot copy from user the key " + "descriptor byte\n"); + kfree(tmp->byte); + kfree(tmp); + return -EBUSY; + } } - src->byte = tmp->byte; if (src->mask) { /* Allocate memory to store the key mask array */ tmp->mask = kmalloc(src->size, GFP_KERNEL); if (!tmp->mask) { - log_err("Cannot allocate memory for key descriptor " - "mask\n"); + log_err("Cannot allocate memory for key " + "descriptor mask\n"); kfree(tmp->byte); + kfree(tmp); return -ENOMEM; } if (copy_from_user(tmp->mask, src->mask, src->size)) { - log_err("Cannot copy from user the key descriptor " - "mask\n"); + log_err("Cannot copy from user the " + "key descriptor mask\n"); kfree(tmp->byte); kfree(tmp->mask); + kfree(tmp); return -EBUSY; } - src->mask = tmp->mask; } + + tmp->size = src->size; + *ks_key = tmp; + return 0; +} + +static int copy_pair_descriptor(struct dpa_offload_lookup_key_pair *src, + struct dpa_offload_lookup_key_pair **ks_pair) +{ + struct dpa_offload_lookup_key_pair *tmp; + int ret = 0; + + /* Allocate kernel memory for pair descriptor*/ + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) { + log_err("Cannot allocate kernel memory for pair descriptor\n"); + return -ENOMEM; + } + + if (src->first_key) { + ret = copy_key_descriptor(src->first_key, &tmp->first_key); + if (ret != 0) { + log_err("Could not copy the first key descriptor\n"); + kfree(tmp); + return ret; + } + } + + if (src->second_key) { + ret = copy_key_descriptor(src->second_key, &tmp->second_key); + if (ret != 0) { + log_err("Could not copy the second key descriptor\n"); + kfree(tmp); + return ret; + } + } + *ks_pair = tmp; return 0; } #ifdef CONFIG_COMPAT static int copy_key_descriptor_compatcpy( - struct dpa_offload_lookup_key *kparam, - const struct compat_ioc_dpa_offld_lookup_key *uparam) + struct dpa_offload_lookup_key **ks_key, compat_uptr_t uparam) { - BUG_ON(uparam->size <= 0); + struct compat_ioc_dpa_offld_lookup_key key; + struct dpa_offload_lookup_key *kparam; - kparam->size = uparam->size; + if (copy_from_user(&key, (compat_ptr)(uparam), + sizeof(struct compat_ioc_dpa_offld_lookup_key))) { + log_err("Cannot copy from user key descriptor\n"); + return -EBUSY; + } - /* Allocate memory to store the key byte array */ - kparam->byte = kmalloc(kparam->size, GFP_KERNEL); - if (!kparam->byte) { - log_err("Cannot allocate memory for key descriptor byte\n"); + /* Allocate kernel memory for key descriptor */ + kparam = kzalloc(sizeof(*kparam), GFP_KERNEL); + if (!kparam) { + log_err("Cannot allocate kernel memory for key descriptor\n"); return -ENOMEM; } - if (copy_from_user(kparam->byte, compat_ptr(uparam->byte), - uparam->size)) { - log_err("Cannot copy from user the key descriptor byte\n"); - return -EBUSY; + if (compat_ptr(key.byte)) { + /* Allocate memory to store the key byte array */ + kparam->byte = kmalloc(key.size, GFP_KERNEL); + if (!kparam->byte) { + log_err("Cannot allocate memory for key descriptor " + "byte\n"); + kfree(kparam); + return -ENOMEM; + } + + if (copy_from_user(kparam->byte, + compat_ptr(key.byte), key.size)) { + log_err("Cannot copy from user the key descriptor " + "byte\n"); + kfree(kparam->byte); + kfree(kparam); + return -EBUSY; + } } - if (compat_ptr(uparam->mask)) { + + if (compat_ptr(key.mask)) { /* Allocate memory to store the key mask array */ - kparam->mask = kmalloc(kparam->size, GFP_KERNEL); + kparam->mask = kmalloc(key.size, GFP_KERNEL); if (!kparam->mask) { log_err("Cannot allocate memory for key descriptor " "mask\n"); kfree(kparam->byte); + kfree(kparam); return -ENOMEM; } - if (copy_from_user(kparam->mask, compat_ptr(uparam->mask), - uparam->size)) { + if (copy_from_user(kparam->mask, + compat_ptr(key.mask), key.size)) { log_err("Cannot copy from user the key descriptor " "mask\n"); + kfree(kparam->byte); + kfree(kparam->mask); + kfree(kparam); return -EBUSY; } - } else - kparam->mask = NULL; + } + kparam->size = key.size; + *ks_key = kparam; + return 0; +} + +static int copy_pair_descriptor_compatcpy( + struct dpa_offload_lookup_key_pair **ks_pair, + struct compat_ioc_dpa_offld_lookup_key_pair pair) +{ + struct dpa_offload_lookup_key_pair *kpair; + int ret = 0; + /* Allocate kernel memory for lookup pair descriptor */ + kpair = kzalloc(sizeof(*kpair), GFP_KERNEL); + if (!kpair) { + log_err("Cannot allocate kernel memory for pair descriptor\n"); + return -ENOMEM; + } + + if (compat_ptr(pair.first_key)) { + /* Copy user-provided key descriptor */ + ret = copy_key_descriptor_compatcpy( + &kpair->first_key, pair.first_key); + if (ret != 0) { + log_err("Cannot copy first key of the pair\n"); + kfree(kpair); + return ret; + } + } + + if (compat_ptr(pair.second_key)) { + ret = copy_key_descriptor_compatcpy( + &kpair->second_key, pair.second_key); + if (ret != 0) { + log_err("Cannot copy second key of the pair\n"); + kfree(kpair); + return ret; + } + } + *ks_pair = kpair; return 0; } #endif @@ -1859,12 +2090,25 @@ static void dpa_stats_plcr_cnt_compatcpy(struct dpa_stats_cnt_plcr *kprm, kprm->cnt_sel = uprm->cnt_sel; } + static long dpa_stats_tbl_cnt_compatcpy(struct dpa_stats_cnt_classif_tbl *kprm, struct dpa_stats_compat_cnt_classif_tbl *uprm) { kprm->td = uprm->td; kprm->cnt_sel = uprm->cnt_sel; - return copy_key_descriptor_compatcpy(&kprm->key, &uprm->key); + /* If different than NULL, it will be overwritten */ + kprm->key = compat_ptr(uprm->key); + + if (compat_ptr(uprm->key)) { + /* Allocate memory for kernel-space key descriptor */ + kprm->key = kmalloc(sizeof(*kprm->key), GFP_KERNEL); + if (!kprm->key) { + log_err("Cannot allocate memory for key descriptor\n"); + return -ENOMEM; + } + return copy_key_descriptor_compatcpy(&kprm->key, uprm->key); + } + return 0; } static long dpa_stats_ccnode_cnt_compatcpy( @@ -1874,7 +2118,19 @@ static long dpa_stats_ccnode_cnt_compatcpy( kprm->cnt_sel = uprm->cnt_sel; kprm->ccnode_type = uprm->ccnode_type; kprm->cc_node = compat_get_id2ptr(uprm->cc_node, FM_MAP_TYPE_PCD_NODE); - return copy_key_descriptor_compatcpy(&kprm->key, &uprm->key); + /* If different than NULL, it will be overwritten */ + kprm->key = compat_ptr(uprm->key); + + if (compat_ptr(uprm->key)) { + /* Allocate memory for kernel-space key descriptor */ + kprm->key = kmalloc(sizeof(*kprm->key), GFP_KERNEL); + if (!kprm->key) { + log_err("Cannot allocate memory for key descriptor\n"); + return -ENOMEM; + } + return copy_key_descriptor_compatcpy(&kprm->key, uprm->key); + } + return 0; } static long dpa_stats_eth_cls_compatcpy(struct dpa_stats_cls_cnt_eth *kprm, @@ -2016,102 +2272,117 @@ static long dpa_stats_tbl_cls_compatcpy( struct dpa_stats_compat_cls_cnt_classif_tbl *uprm, uint32_t cls_members) { - struct compat_ioc_dpa_offld_lookup_key *keys; - struct compat_ioc_dpa_offld_lookup_key_pair *pairs; - uint32_t size = 0, i; + struct compat_ioc_dpa_offld_lookup_key_pair pair; + compat_uptr_t *us_keys; + uint32_t i; long ret; kprm->cnt_sel = uprm->cnt_sel; kprm->td = uprm->td; kprm->key_type = uprm->key_type; + /* Allocate memory to store array of user-space keys descriptors */ + us_keys = kzalloc(sizeof(compat_uptr_t) * cls_members, GFP_KERNEL); + if (!us_keys) { + log_err("Cannot allocate memory array of lookup keys\n"); + return -ENOMEM; + } + if (kprm->key_type == DPA_STATS_CLASSIF_SINGLE_KEY) { - size = sizeof(struct dpa_offload_lookup_key) * cls_members; - kprm->keys = kzalloc(size, GFP_KERNEL); - if (!kprm->keys) { - log_err("Cannot allocate kernel memory for lookup keys " - "array\n"); - return -ENOMEM; + if (copy_from_user(us_keys, compat_ptr(uprm->keys), + (sizeof(compat_uptr_t) * cls_members))) { + log_err("Cannot copy from user-space array of keys " + "descriptors\n"); + kfree(us_keys); + return -EBUSY; } - size = sizeof(struct compat_ioc_dpa_offld_lookup_key) * - cls_members; - keys = kzalloc(size, GFP_KERNEL); - if (!keys) { - log_err("Cannot allocate memory for lookup keys " + /* Allocate memory for array of kernel-space keys descriptors */ + kprm->keys = kzalloc((sizeof(*kprm->keys) * cls_members), + GFP_KERNEL); + if (!kprm->keys) { + log_err("Cannot allocate kernel memory for lookup keys " "array\n"); + kfree(us_keys); return -ENOMEM; } - - if (copy_from_user(keys, (compat_ptr)(uprm->keys), size)) { - log_err("Cannot copy from user array of lookup keys\n"); - kfree(keys); - return -EBUSY; - } - for (i = 0; i < cls_members; i++) { - if (!compat_ptr(keys[i].byte)) + if (!compat_ptr(us_keys[i])) continue; - + /* Copy user-provided key descriptor */ ret = copy_key_descriptor_compatcpy(&kprm->keys[i], - &keys[i]); + us_keys[i]); if (ret != 0) { log_err("Cannot copy the key descriptor\n"); - kfree(keys); - return -EINVAL; + kfree(us_keys); + return ret; } } - kfree(keys); - } else if (kprm->key_type == DPA_STATS_CLASSIF_PAIR_KEY) { - size = sizeof(struct dpa_offload_lookup_key_pair) * cls_members; - kprm->pairs = kzalloc(size, GFP_KERNEL); - if (!kprm->pairs) { - log_err("Cannot allocate kernel memory for pair lookup " - "keys array\n"); - return -ENOMEM; + kfree(us_keys); + } + + if (kprm->key_type == DPA_STATS_CLASSIF_PAIR_KEY) { + if (copy_from_user(us_keys, compat_ptr(uprm->pairs), + (sizeof(compat_uptr_t) * cls_members))) { + log_err("Cannot copy from user-space array of pairs " + "descriptors\n"); + kfree(us_keys); + return -EBUSY; } - size = sizeof(struct compat_ioc_dpa_offld_lookup_key_pair) * - cls_members; - pairs = kzalloc(size, GFP_KERNEL); - if (!pairs) { - log_err("Cannot allocate memory for pair lookup keys " + /* Allocate memory for array of kernel-space pairs descriptors*/ + kprm->pairs = kzalloc((sizeof(*kprm->pairs) * cls_members), + GFP_KERNEL); + if (!kprm->pairs) { + log_err("Cannot allocate kernel memory for lookup pairs" "array\n"); + kfree(us_keys); return -ENOMEM; } - if (copy_from_user(pairs, (compat_ptr)(uprm->pairs), size)) { - log_err("Cannot copy from user array of pair lookup " - "keys\n"); - kfree(pairs); - return -EBUSY; - } - for (i = 0; i < cls_members; i++) { - if (!compat_ptr(pairs[i].first_key.byte)) + if (!compat_ptr(us_keys[i])) continue; - ret = copy_key_descriptor_compatcpy( - &kprm->pairs[i].first_key, - &pairs[i].first_key); - if (ret != 0) { - log_err("Cannot copy the key descriptor for the" - " first lookup key\n"); - kfree(pairs); - return -EINVAL; + /* Allocate memory for kernel pair descriptor */ + kprm->pairs[i] = kzalloc(sizeof(*kprm->pairs[i]), + GFP_KERNEL); + if (!kprm->pairs[i]) { + log_err("Cannot allocate kernel memory for pair" + " descriptor\n"); + return -ENOMEM; } - ret = copy_key_descriptor_compatcpy( - &kprm->pairs[i].second_key, - &pairs[i].second_key); - if (ret != 0) { - log_err("Cannot copy the key descriptor for the" - " second lookup key\n", uprm->td); - kfree(pairs); - return -EINVAL; + if (copy_from_user(&pair, compat_ptr(us_keys[i]), + (sizeof(pair)))) { + log_err("Cannot copy pair descriptor\n"); + return -EBUSY; + } + + if (compat_ptr(pair.first_key)) { + /* Copy user-provided first key descriptor */ + ret = copy_key_descriptor_compatcpy( + &kprm->pairs[i]->first_key, + pair.first_key); + if (ret != 0) { + log_err("Cannot copy first key\n"); + kfree(us_keys); + return ret; + } + } + + if (compat_ptr(pair.second_key)) { + /* Copy user-provided second key descriptor */ + ret = copy_key_descriptor_compatcpy( + &kprm->pairs[i]->second_key, + pair.second_key); + if (ret != 0) { + log_err("Cannot copy second key\n"); + kfree(us_keys); + return ret; + } } } - kfree(pairs); } return 0; } @@ -2121,45 +2392,50 @@ static long dpa_stats_ccnode_cls_compatcpy( struct dpa_stats_compat_cls_cnt_classif_node *uprm, uint32_t cls_members) { - struct compat_ioc_dpa_offld_lookup_key *keys; - uint32_t size, i; + compat_uptr_t *us_keys; + uint32_t i; long ret = 0; kprm->cc_node = compat_get_id2ptr(uprm->cc_node, FM_MAP_TYPE_PCD_NODE); kprm->cnt_sel = uprm->cnt_sel; kprm->ccnode_type = uprm->ccnode_type; - size = sizeof(struct dpa_offload_lookup_key) * cls_members; - kprm->keys = kzalloc(size, GFP_KERNEL); - if (!kprm->keys) { - log_err("Cannot allocate kernel memory for lookup keys " - "array\n"); + /* Allocate memory to store array of user-space keys descriptors */ + us_keys = kzalloc(sizeof(compat_uptr_t) * cls_members, GFP_KERNEL); + if (!us_keys) { + log_err("Cannot allocate memory array of lookup keys\n"); return -ENOMEM; } - size = sizeof(struct compat_ioc_dpa_offld_lookup_key) * cls_members; - keys = kzalloc(size, GFP_KERNEL); - if (!keys) { - log_err("Cannot allocate memory for lookup keys array\n"); - return -ENOMEM; - } - - if (copy_from_user(keys, (compat_ptr)(uprm->keys), size)) { - log_err("Cannot copy from user array of lookup keys\n"); - kfree(keys); + if (copy_from_user(us_keys, compat_ptr(uprm->keys), + (sizeof(compat_uptr_t) * cls_members))) { + log_err("Cannot copy from user-space array of keys " + "descriptors\n"); + kfree(us_keys); return -EBUSY; } + /* Allocate memory to store array of kernel-space keys descriptors */ + kprm->keys = kzalloc((sizeof(*kprm->keys) * cls_members), GFP_KERNEL); + if (!kprm->keys) { + log_err("Cannot allocate kernel memory for lookup keys " + "array\n"); + kfree(us_keys); + return -ENOMEM; + } for (i = 0; i < cls_members; i++) { - ret = copy_key_descriptor_compatcpy(&kprm->keys[i], &keys[i]); + if (!compat_ptr(us_keys[i])) + continue; + /* Copy user-provided key descriptor */ + ret = copy_key_descriptor_compatcpy(&kprm->keys[i], us_keys[i]); if (ret != 0) { log_err("Cannot copy the key descriptor\n"); - kfree(keys); - return -EINVAL; + kfree(us_keys); + return ret; } } - kfree(keys); - return ret; + kfree(us_keys); + return 0; } static long dpa_stats_ipsec_cls_compatcpy(struct dpa_stats_cls_cnt_ipsec *kprm, |