Define a number of transmit parameters for TLV Parameter table
definitions. These will be used for validating TLVs that are set
on a socket.

Signed-off-by: Tom Herbert <t...@quantonium.net>
---
 include/net/ipv6.h         | 26 ++++++++++++++++++++-
 include/uapi/linux/in6.h   |  8 +++++++
 net/ipv6/exthdrs.c         |  2 +-
 net/ipv6/exthdrs_common.c  | 17 ++++++++++++++
 net/ipv6/exthdrs_options.c | 57 ++++++++++++++++++++++++++++++++++++++++++----
 5 files changed, 104 insertions(+), 6 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index bb667ed..4cebc48 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 71a12a7..92a777f 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_common.c b/net/ipv6/exthdrs_common.c
index 0c0e32d..cda4fb8 100644
--- a/net/ipv6/exthdrs_common.c
+++ b/net/ipv6/exthdrs_common.c
@@ -155,6 +155,14 @@ 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.t = {
+               .preferred_order = 0,
+               .admin_perm = IPV6_TLV_PERM_NO_CHECK,
+               .user_perm = IPV6_TLV_PERM_NONE,
+               .align_mult = (4 - 1), /* Default alignment: 4n + 2 */
+               .align_off = 2,
+               .max_data_len = 255,
+       },
 };
 
 static size_t tlv_param_table_size(unsigned char count)
@@ -373,10 +381,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 = kvmalloc(tsize, GFP_KERNEL);
@@ -390,6 +401,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)) {
@@ -403,6 +415,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 eb3ae2a..7251229 100644
--- a/net/ipv6/exthdrs_options.c
+++ b/net/ipv6/exthdrs_options.c
@@ -181,26 +181,75 @@ 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,
+                       .admin_perm = IPV6_TLV_PERM_NO_CHECK,
+                       .user_perm = IPV6_TLV_PERM_NONE,
+                       .class = IPV6_TLV_CLASS_FLAG_DSTOPT,
+                       .align_mult = (8 - 1), /* Align to 8n + 6 */
+                       .align_off = 6,
+                       .min_data_len = 16,
+                       .max_data_len = 16,
+               },
        },
 #endif
        {
                .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,
+                       .admin_perm = IPV6_TLV_PERM_NO_CHECK,
+                       .user_perm = IPV6_TLV_PERM_NONE,
+                       .class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+                       .align_mult = (2 - 1), /* Align to 2n */
+                       .min_data_len = 2,
+                       .max_data_len = 2,
+               },
+
        },
        {
                .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,
+                       .admin_perm = IPV6_TLV_PERM_NO_CHECK,
+                       .user_perm = IPV6_TLV_PERM_NONE,
+                       .class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+                       .align_mult = (4 - 1), /* Align to 4n + 2 */
+                       .align_off = 2,
+                       .min_data_len = 4,
+                       .max_data_len = 4,
+               },
        },
        {
                .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,
+                       .admin_perm = IPV6_TLV_PERM_NO_CHECK,
+                       .user_perm = IPV6_TLV_PERM_NONE,
+                       .class = IPV6_TLV_CLASS_FLAG_HOPOPT,
+                       .align_mult = (4 - 1), /* Align to 4n + 2 */
+                       .align_off = 2,
+                       .min_data_len = 8,
+                       .max_data_len = 252,
+                       .data_len_mult = (4 - 1),
+                                       /* Length is multiple of 4 */
+               },
        },
 };
 
-- 
2.7.4

Reply via email to