Define a number of transmit parameters for TLV Parameter table
definitions. These will be used for validating TLVs that are set
on a socket.
---
 include/net/ipv6.h         | 26 ++++++++++++++++++++-
 include/uapi/linux/in6.h   |  8 +++++++
 net/ipv6/exthdrs.c         |  2 +-
 net/ipv6/exthdrs_core.c    | 22 +++++++++++++++++-
 net/ipv6/exthdrs_options.c | 57 ++++++++++++++++++++++++++++++++++++++++++----
 5 files changed, 108 insertions(+), 7 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 41da032..9b25d08 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -390,8 +390,26 @@ struct tlv_ops {
        bool    (*func)(unsigned int class, struct sk_buff *skb, int offset);
 };
 
+struct tlv_rx_params {
+       unsigned char class : 3;
+};
+
+struct tlv_tx_params {
+       unsigned char admin_perm : 2;
+       unsigned char user_perm : 2;
+       unsigned char class : 3;
+       unsigned char align_mult : 4;
+       unsigned char align_off : 4;
+       unsigned char data_len_mult : 4;
+       unsigned char data_len_off : 4;
+       unsigned char min_data_len;
+       unsigned char max_data_len;
+       unsigned char preferred_order;
+};
+
 struct tlv_params {
-       unsigned char rx_class : 3;
+       struct tlv_rx_params r;
+       struct tlv_tx_params t;
 };
 
 struct tlv_proc {
@@ -417,6 +435,12 @@ struct tlv_param_table {
 
 extern struct tlv_param_table ipv6_tlv_param_table;
 
+/* Preferred TLV ordering (placed by increasing order) */
+#define TLV_PREF_ORDER_HAO             10
+#define TLV_PREF_ORDER_ROUTERALERT     20
+#define TLV_PREF_ORDER_JUMBO           30
+#define TLV_PREF_ORDER_CALIPSO         40
+
 int tlv_set_proc(struct tlv_param_table *tlv_param_table,
                 unsigned char type, const struct tlv_proc *proc);
 int tlv_unset_proc(struct tlv_param_table *tlv_param_table, unsigned char 
type);
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index 8b9ac7f..6a99ee1 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -307,4 +307,12 @@ struct in6_flowlabel_req {
 #define IPV6_TLV_CLASS_ANY_DSTOPT      (IPV6_TLV_CLASS_FLAG_RTRDSTOPT | \
                                        IPV6_TLV_CLASS_FLAG_DSTOPT)
 
+/* TLV permissions values */
+enum {
+       IPV6_TLV_PERM_NONE,
+       IPV6_TLV_PERM_WITH_CHECK,
+       IPV6_TLV_PERM_NO_CHECK,
+       IPV6_TLV_PERM_MAX = IPV6_TLV_PERM_NO_CHECK
+};
+
 #endif /* _UAPI_LINUX_IN6_H */
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index b28c108..520c2eb 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -166,7 +166,7 @@ static bool ip6_parse_tlv(unsigned int class, struct 
sk_buff *skb,
                                goto bad;
 
                        curr = tlv_get_proc(&ipv6_tlv_param_table, nh[off]);
-                       if ((curr->params.rx_class & class) && curr->ops.func) {
+                       if ((curr->params.r.class & class) && curr->ops.func) {
                                /* Handler will apply additional checks to
                                 * the TLV
                                 */
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
index aaa4582..98b5bc1 100644
--- a/net/ipv6/exthdrs_core.c
+++ b/net/ipv6/exthdrs_core.c
@@ -431,7 +431,18 @@ static void tlv_param_table_release(struct rcu_head *rcu)
 
 /* Default (unset) values for TLV parameters */
 static const struct tlv_proc tlv_default_proc = {
-       .params.rx_class = 0,
+       .params.r.class = 0,
+
+       .params.t.preferred_order = 0,
+       .params.t.admin_perm = IPV6_TLV_PERM_NO_CHECK,
+       .params.t.user_perm = IPV6_TLV_PERM_NONE,
+       .params.t.class = 0,
+       .params.t.align_mult = (4 - 1), /* Default alignment: 4n + 2 */
+       .params.t.align_off = 2,
+       .params.t.min_data_len = 0,
+       .params.t.max_data_len = 255,
+       .params.t.data_len_mult = (1 - 1), /* No default length align */
+       .params.t.data_len_off = 0,
 };
 
 static size_t tlv_param_table_size(unsigned char count)
@@ -650,10 +661,13 @@ int exthdrs_init(struct tlv_param_table *tlv_param_table,
                 const struct tlv_proc_init *tlv_init_params,
                 int num_init_params)
 {
+       unsigned long check_map[BITS_TO_LONGS(256)];
        struct tlv_param_table_data *tpt;
        size_t tsize;
        int i;
 
+       memset(check_map, 0, sizeof(check_map));
+
        tsize = tlv_param_table_size(num_init_params + 1);
 
        tpt = vmalloc(tsize);
@@ -667,6 +681,7 @@ int exthdrs_init(struct tlv_param_table *tlv_param_table,
 
        for (i = 0; i < num_init_params; i++) {
                const struct tlv_proc_init *tpi = &tlv_init_params[i];
+               unsigned int order = tpi->proc.params.t.preferred_order;
                struct tlv_proc *tp = &tpt->procs[i + 1];
 
                if (WARN_ON(tpi->type < 2)) {
@@ -680,6 +695,11 @@ int exthdrs_init(struct tlv_param_table *tlv_param_table,
                        return -EINVAL;
                }
 
+               if (order) {
+                       WARN_ON(test_bit(order, check_map));
+                       set_bit(order, check_map);
+               }
+
                *tp = tpi->proc;
                tpt->entries[tpi->type] = i + 1;
        }
diff --git a/net/ipv6/exthdrs_options.c b/net/ipv6/exthdrs_options.c
index 9be82ef..b316143 100644
--- a/net/ipv6/exthdrs_options.c
+++ b/net/ipv6/exthdrs_options.c
@@ -180,25 +180,74 @@ static const struct tlv_proc_init tlv_init_params[] 
__initconst = {
                .type = IPV6_TLV_HAO,
 
                .proc.ops.func = ipv6_dest_hao,
-               .proc.params.rx_class = IPV6_TLV_CLASS_FLAG_DSTOPT,
+
+               .proc.params.r.class = IPV6_TLV_CLASS_FLAG_DSTOPT,
+
+               .proc.params.t.preferred_order = TLV_PREF_ORDER_HAO,
+               .proc.params.t.admin_perm = IPV6_TLV_PERM_NO_CHECK,
+               .proc.params.t.user_perm = IPV6_TLV_PERM_NONE,
+               .proc.params.t.class = IPV6_TLV_CLASS_FLAG_DSTOPT,
+               .proc.params.t.align_mult = (8 - 1), /* Align to 8n + 6 */
+               .proc.params.t.align_off = 6,
+               .proc.params.t.min_data_len = 16,
+               .proc.params.t.max_data_len = 16,
+               .proc.params.t.data_len_mult = (1 - 1), /* Fixed length */
+               .proc.params.t.data_len_off = 0,
        },
        {
                .type = IPV6_TLV_ROUTERALERT,
 
                .proc.ops.func = ipv6_hop_ra,
-               .proc.params.rx_class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+
+               .proc.params.r.class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+
+               .proc.params.t.preferred_order = TLV_PREF_ORDER_ROUTERALERT,
+               .proc.params.t.admin_perm = IPV6_TLV_PERM_NO_CHECK,
+               .proc.params.t.user_perm = IPV6_TLV_PERM_NONE,
+               .proc.params.t.class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+               .proc.params.t.align_mult = (2 - 1), /* Align to 2n */
+               .proc.params.t.align_off = 0,
+               .proc.params.t.min_data_len = 2,
+               .proc.params.t.max_data_len = 2,
+               .proc.params.t.data_len_mult = (1 - 1), /* Fixed length */
+               .proc.params.t.data_len_off = 0,
+
        },
        {
                .type = IPV6_TLV_JUMBO,
 
                .proc.ops.func  = ipv6_hop_jumbo,
-               .proc.params.rx_class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+
+               .proc.params.r.class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+
+               .proc.params.t.preferred_order = TLV_PREF_ORDER_JUMBO,
+               .proc.params.t.admin_perm = IPV6_TLV_PERM_NO_CHECK,
+               .proc.params.t.user_perm = IPV6_TLV_PERM_NONE,
+               .proc.params.t.class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+               .proc.params.t.align_mult = (4 - 1), /* Align to 4n + 2 */
+               .proc.params.t.align_off = 2,
+               .proc.params.t.min_data_len = 4,
+               .proc.params.t.max_data_len = 4,
+               .proc.params.t.data_len_mult = (1 - 1), /* Fixed length */
+               .proc.params.t.data_len_off = 0,
        },
        {
                .type = IPV6_TLV_CALIPSO,
 
                .proc.ops.func = ipv6_hop_calipso,
-               .proc.params.rx_class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+               .proc.params.r.class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+
+               .proc.params.t.preferred_order = TLV_PREF_ORDER_CALIPSO,
+               .proc.params.t.admin_perm = IPV6_TLV_PERM_NO_CHECK,
+               .proc.params.t.user_perm = IPV6_TLV_PERM_NONE,
+               .proc.params.t.class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+               .proc.params.t.align_mult = (4 - 1), /* Align to 4n + 2 */
+               .proc.params.t.align_off = 2,
+               .proc.params.t.min_data_len = 8,
+               .proc.params.t.max_data_len = 252,
+               .proc.params.t.data_len_mult = (4 - 1),
+                                       /* Length is multiple of 4 */
+               .proc.params.t.data_len_off = 0,
        },
 };
 
-- 
2.7.4

Reply via email to