diff --git a/platform/linux-generic/include/odp_classification_datamodel.h b/platform/linux-generic/include/odp_classification_datamodel.h
index 63f3ec6..550e9d3 100644
--- a/platform/linux-generic/include/odp_classification_datamodel.h
+++ b/platform/linux-generic/include/odp_classification_datamodel.h
@@ -52,9 +52,22 @@ Stores the Term and Value mapping for a PMR.
 The maximum size of value currently supported in 64 bits
 **/
 typedef struct pmr_term_value {
-	odp_pmr_term_t  term;	/* PMR Term */
-	uint64_t	val;	/**< Value to be matched */
-	uint64_t	mask;	/**< Masked set of bits to be matched */
+	odp_cls_pmr_term_e	term;	/* PMR Term */
+	odp_bool_t		range_term; /* True if range, false if match */
+	union {
+		struct {
+			/** Value to be matched */
+			uint64_t	value;
+			/** Masked set of bits to be matched */
+			uint64_t	mask;
+		} match;
+		struct {
+			/** Start value of the range */
+			uint64_t	val_start;
+			/** End value of the range */
+			uint64_t	val_end;
+		} range;
+	};
 	uint32_t	offset;	/**< Offset if term == ODP_PMR_CUSTOM_FRAME */
 	uint32_t	val_sz;	/**< Size of the value to be matched */
 } pmr_term_value_t;
diff --git a/platform/linux-generic/include/odp_classification_inlines.h b/platform/linux-generic/include/odp_classification_inlines.h
index bac5b48..b8b04ce 100644
--- a/platform/linux-generic/include/odp_classification_inlines.h
+++ b/platform/linux-generic/include/odp_classification_inlines.h
@@ -34,8 +34,8 @@ These following functions return 1 on success and 0 on failure
 static inline int verify_pmr_packet_len(odp_packet_hdr_t *pkt_hdr,
 					pmr_term_value_t *term_value)
 {
-	if (term_value->val == (packet_len(pkt_hdr) &
-				     term_value->mask))
+	if (term_value->match.value == (packet_len(pkt_hdr) &
+				     term_value->match.mask))
 		return 1;
 
 	return 0;
@@ -51,7 +51,7 @@ static inline int verify_pmr_ip_proto(const uint8_t *pkt_addr,
 		return 0;
 	ip = (const odph_ipv4hdr_t *)(pkt_addr + pkt_hdr->l3_offset);
 	proto = ip->proto;
-	if (term_value->val == (proto & term_value->mask))
+	if (term_value->match.value == (proto & term_value->match.mask))
 		return 1;
 
 	return 0;
@@ -67,7 +67,7 @@ static inline int verify_pmr_ipv4_saddr(const uint8_t *pkt_addr,
 		return 0;
 	ip = (const odph_ipv4hdr_t *)(pkt_addr + pkt_hdr->l3_offset);
 	ipaddr = odp_be_to_cpu_32(ip->src_addr);
-	if (term_value->val == (ipaddr & term_value->mask))
+	if (term_value->match.value == (ipaddr & term_value->match.mask))
 		return 1;
 
 	return 0;
@@ -83,7 +83,7 @@ static inline int verify_pmr_ipv4_daddr(const uint8_t *pkt_addr,
 		return 0;
 	ip = (const odph_ipv4hdr_t *)(pkt_addr + pkt_hdr->l3_offset);
 	ipaddr = odp_be_to_cpu_32(ip->dst_addr);
-	if (term_value->val == (ipaddr & term_value->mask))
+	if (term_value->match.value == (ipaddr & term_value->match.mask))
 		return 1;
 
 	return 0;
@@ -99,7 +99,7 @@ static inline int verify_pmr_tcp_sport(const uint8_t *pkt_addr,
 		return 0;
 	tcp = (const odph_tcphdr_t *)(pkt_addr + pkt_hdr->l4_offset);
 	sport = odp_be_to_cpu_16(tcp->src_port);
-	if (term_value->val == (sport & term_value->mask))
+	if (term_value->match.value == (sport & term_value->match.mask))
 		return 1;
 
 	return 0;
@@ -115,7 +115,7 @@ static inline int verify_pmr_tcp_dport(const uint8_t *pkt_addr,
 		return 0;
 	tcp = (const odph_tcphdr_t *)(pkt_addr + pkt_hdr->l4_offset);
 	dport = odp_be_to_cpu_16(tcp->dst_port);
-	if (term_value->val == (dport & term_value->mask))
+	if (term_value->match.value == (dport & term_value->match.mask))
 		return 1;
 
 	return 0;
@@ -131,7 +131,7 @@ static inline int verify_pmr_udp_dport(const uint8_t *pkt_addr,
 		return 0;
 	udp = (const odph_udphdr_t *)(pkt_addr + pkt_hdr->l4_offset);
 	dport = odp_be_to_cpu_16(udp->dst_port);
-	if (term_value->val == (dport & term_value->mask))
+	if (term_value->match.value == (dport & term_value->match.mask))
 			return 1;
 
 	return 0;
@@ -148,7 +148,7 @@ static inline int verify_pmr_udp_sport(const uint8_t *pkt_addr,
 		return 0;
 	udp = (const odph_udphdr_t *)(pkt_addr + pkt_hdr->l4_offset);
 	sport = odp_be_to_cpu_16(udp->src_port);
-	if (term_value->val == (sport & term_value->mask))
+	if (term_value->match.value == (sport & term_value->match.mask))
 		return 1;
 
 	return 0;
@@ -174,7 +174,7 @@ static inline int verify_pmr_dmac(const uint8_t *pkt_addr,
 	if (dmac_be != dmac)
 		dmac = dmac >> (64 - (ODPH_ETHADDR_LEN * 8));
 
-	if (term_value->val == (dmac & term_value->mask))
+	if (term_value->match.value == (dmac & term_value->match.mask))
 		return 1;
 	return 0;
 }
@@ -234,7 +234,7 @@ static inline int verify_pmr_ipsec_spi(const uint8_t *pkt_addr,
 		return 0;
 	}
 
-	if (term_value->val == (spi & term_value->mask))
+	if (term_value->match.value == (spi & term_value->match.mask))
 		return 1;
 
 	return 0;
@@ -262,7 +262,7 @@ static inline int verify_pmr_custom_frame(const uint8_t *pkt_addr,
 		return 0;
 
 	memcpy(&val, pkt_addr + offset, val_sz);
-	if (term_value->val == (val & term_value->mask))
+	if (term_value->match.value == (val & term_value->match.mask))
 		return 1;
 
 	return 0;
diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c
index f5e4673..5e4bce5 100644
--- a/platform/linux-generic/odp_classification.c
+++ b/platform/linux-generic/odp_classification.c
@@ -124,6 +124,34 @@ void odp_cls_cos_param_init(odp_cls_cos_param_t *param)
 	param->drop_policy = ODP_COS_DROP_NEVER;
 }
 
+void odp_cls_pmr_param_init(odp_pmr_param_t *param)
+{
+	memset(param, 0, sizeof(odp_pmr_param_t));
+}
+
+int odp_cls_capability(odp_cls_capability_t *capability)
+{
+	unsigned count = 0;
+
+	for (int i = 0; i < ODP_PMR_MAX_ENTRY; i++)
+		if (!pmr_tbl->pmr[i].s.valid)
+			count++;
+
+	capability->max_pmr_terms = ODP_PMR_MAX_ENTRY;
+	capability->available_pmr_terms = count;
+	capability->max_cos = ODP_COS_MAX_ENTRY;
+	capability->pmr_range_supported = false;
+	capability->supported_terms.all_bits = 0;
+	capability->supported_terms.bit.ip_proto = 1;
+	capability->supported_terms.bit.udp_dport = 1;
+	capability->supported_terms.bit.udp_sport = 1;
+	capability->supported_terms.bit.tcp_dport = 1;
+	capability->supported_terms.bit.tcp_sport = 1;
+	capability->supported_terms.bit.sip_addr = 1;
+	capability->supported_terms.bit.dip_addr = 1;
+	return 0;
+}
+
 odp_cos_t odp_cls_cos_create(const char *name, odp_cls_cos_param_t *param)
 {
 	int i, j;
@@ -409,17 +437,28 @@ int odp_cos_with_l3_qos(odp_pktio_t pktio_in,
 	return 0;
 }
 
-static void odp_pmr_create_term(pmr_term_value_t *value,
-				const odp_pmr_match_t *match)
+static int odp_pmr_create_term(pmr_term_value_t *value,
+			       const odp_pmr_param_t *param)
 {
-	value->term = match->term;
-	value->offset = match->offset;
-	value->val_sz = match->val_sz;
-	value->val = 0;
-	value->mask = 0;
-	memcpy(&value->val, match->val, match->val_sz);
-	memcpy(&value->mask, match->mask, match->val_sz);
-	value->val &= value->mask;
+	value->term = param->term;
+	value->range_term = param->range_term;
+	if (!value->range_term) {
+		value->match.value = 0;
+		value->match.mask = 0;
+		memcpy(&value->match.value, param->match.value, param->val_sz);
+		memcpy(&value->match.mask, param->match.mask, param->val_sz);
+		value->match.value &= value->match.mask;
+	} else {
+		value->range.val_start = 0;
+		value->range.val_end = 0;
+		memcpy(&value->range.val_start, param->range.val_start,
+		       param->val_sz);
+		memcpy(&value->range.val_end, param->range.val_end,
+		       param->val_sz);
+	}
+	value->offset = param->offset;
+	value->val_sz = param->val_sz;
+	return 0;
 }
 
 int odp_cls_pmr_destroy(odp_pmr_t pmr_id)
@@ -452,33 +491,7 @@ no_rule:
 	return 0;
 }
 
-unsigned long long odp_pmr_terms_cap(void)
-{
-	unsigned long long term_cap = 0;
-
-	term_cap |= (1 << ODP_PMR_LEN);
-	term_cap |= (1 << ODP_PMR_IPPROTO);
-	term_cap |= (1 << ODP_PMR_UDP_DPORT);
-	term_cap |= (1 << ODP_PMR_TCP_DPORT);
-	term_cap |= (1 << ODP_PMR_UDP_SPORT);
-	term_cap |= (1 << ODP_PMR_TCP_SPORT);
-	term_cap |= (1 << ODP_PMR_SIP_ADDR);
-	term_cap |= (1 << ODP_PMR_DIP_ADDR);
-	return term_cap;
-}
-
-unsigned odp_pmr_terms_avail(void)
-{
-	unsigned count = 0;
-	int i;
-
-	for (i = 0; i < ODP_PMR_MAX_ENTRY; i++)
-		if (!pmr_tbl->pmr[i].s.valid)
-			count++;
-	return count;
-}
-
-odp_pmr_t odp_cls_pmr_create(const odp_pmr_match_t *terms, int num_terms,
+odp_pmr_t odp_cls_pmr_create(const odp_pmr_param_t *terms, int num_terms,
 			     odp_cos_t src_cos, odp_cos_t dst_cos)
 {
 	pmr_t *pmr;
@@ -512,10 +525,13 @@ odp_pmr_t odp_cls_pmr_create(const odp_pmr_match_t *terms, int num_terms,
 		val_sz = terms[i].val_sz;
 		if (val_sz > ODP_PMR_TERM_BYTES_MAX) {
 			pmr->s.valid = 0;
+			return ODP_PMR_INVAL;
+		}
+		if (0 > odp_pmr_create_term(&pmr->s.pmr_term_value[i],
+					    &terms[i])) {
 			UNLOCK(&pmr->s.lock);
 			return ODP_PMR_INVAL;
 		}
-		odp_pmr_create_term(&pmr->s.pmr_term_value[i], &terms[i]);
 	}
 
 	loc = odp_atomic_fetch_inc_u32(&cos_src->s.num_rule);
