libnl: add more helpers to align attributes on 64-bit
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Thu, 21 Apr 2016 16:58:24 +0000 (18:58 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 21 Apr 2016 18:22:12 +0000 (14:22 -0400)
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/netlink.h
lib/nlattr.c

index 3c1fd92a52c8274174f7e2057f36bfa3626eddb0..6f51a8a06498c9d38342bbab56d8019590d59d06 100644 (file)
@@ -244,13 +244,21 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count);
 int nla_memcmp(const struct nlattr *nla, const void *data, size_t size);
 int nla_strcmp(const struct nlattr *nla, const char *str);
 struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen);
+struct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype,
+                                  int attrlen, int padattr);
 void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
 struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen);
+struct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype,
+                                int attrlen, int padattr);
 void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen);
 void __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
               const void *data);
+void __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
+                    const void *data, int padattr);
 void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data);
 int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data);
+int nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
+                 const void *data, int padattr);
 int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data);
 int nla_append(struct sk_buff *skb, int attrlen, const void *data);
 
@@ -1230,6 +1238,27 @@ static inline int nla_validate_nested(const struct nlattr *start, int maxtype,
        return nla_validate(nla_data(start), nla_len(start), maxtype, policy);
 }
 
+/**
+ * nla_need_padding_for_64bit - test 64-bit alignment of the next attribute
+ * @skb: socket buffer the message is stored in
+ *
+ * Return true if padding is needed to align the next attribute (nla_data()) to
+ * a 64-bit aligned area.
+ */
+static inline bool nla_need_padding_for_64bit(struct sk_buff *skb)
+{
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+       /* The nlattr header is 4 bytes in size, that's why we test
+        * if the skb->data _is_ aligned.  A NOP attribute, plus
+        * nlattr header for next attribute, will make nla_data()
+        * 8-byte aligned.
+        */
+       if (IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8))
+               return true;
+#endif
+       return false;
+}
+
 /**
  * nla_align_64bit - 64-bit align the nla_data() of next attribute
  * @skb: socket buffer the message is stored in
@@ -1244,16 +1273,10 @@ static inline int nla_validate_nested(const struct nlattr *start, int maxtype,
  */
 static inline int nla_align_64bit(struct sk_buff *skb, int padattr)
 {
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-       /* The nlattr header is 4 bytes in size, that's why we test
-        * if the skb->data _is_ aligned.  This NOP attribute, plus
-        * nlattr header for next attribute, will make nla_data()
-        * 8-byte aligned.
-        */
-       if (IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8) &&
+       if (nla_need_padding_for_64bit(skb) &&
            !nla_reserve(skb, padattr, 0))
                return -EMSGSIZE;
-#endif
+
        return 0;
 }
 
index f5907d23272d48562c69b911e5a0a619e3f4c180..2b82f1e2ebc2cc185fdf126e04392302b46065f9 100644 (file)
@@ -354,6 +354,29 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
 }
 EXPORT_SYMBOL(__nla_reserve);
 
+/**
+ * __nla_reserve_64bit - reserve room for attribute on the skb and align it
+ * @skb: socket buffer to reserve room on
+ * @attrtype: attribute type
+ * @attrlen: length of attribute payload
+ *
+ * Adds a netlink attribute header to a socket buffer and reserves
+ * room for the payload but does not copy it. It also ensure that this
+ * attribute will be 64-bit aign.
+ *
+ * The caller is responsible to ensure that the skb provides enough
+ * tailroom for the attribute header and payload.
+ */
+struct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype,
+                                  int attrlen, int padattr)
+{
+       if (nla_need_padding_for_64bit(skb))
+               nla_align_64bit(skb, padattr);
+
+       return __nla_reserve(skb, attrtype, attrlen);
+}
+EXPORT_SYMBOL(__nla_reserve_64bit);
+
 /**
  * __nla_reserve_nohdr - reserve room for attribute without header
  * @skb: socket buffer to reserve room on
@@ -396,6 +419,35 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
 }
 EXPORT_SYMBOL(nla_reserve);
 
+/**
+ * nla_reserve_64bit - reserve room for attribute on the skb and align it
+ * @skb: socket buffer to reserve room on
+ * @attrtype: attribute type
+ * @attrlen: length of attribute payload
+ *
+ * Adds a netlink attribute header to a socket buffer and reserves
+ * room for the payload but does not copy it. It also ensure that this
+ * attribute will be 64-bit aign.
+ *
+ * Returns NULL if the tailroom of the skb is insufficient to store
+ * the attribute header and payload.
+ */
+struct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype, int attrlen,
+                                int padattr)
+{
+       size_t len;
+
+       if (nla_need_padding_for_64bit(skb))
+               len = nla_total_size_64bit(attrlen);
+       else
+               len = nla_total_size(attrlen);
+       if (unlikely(skb_tailroom(skb) < len))
+               return NULL;
+
+       return __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
+}
+EXPORT_SYMBOL(nla_reserve_64bit);
+
 /**
  * nla_reserve_nohdr - reserve room for attribute without header
  * @skb: socket buffer to reserve room on
@@ -435,6 +487,26 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
 }
 EXPORT_SYMBOL(__nla_put);
 
+/**
+ * __nla_put_64bit - Add a netlink attribute to a socket buffer and align it
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @attrlen: length of attribute payload
+ * @data: head of attribute payload
+ *
+ * The caller is responsible to ensure that the skb provides enough
+ * tailroom for the attribute header and payload.
+ */
+void __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
+                    const void *data, int padattr)
+{
+       struct nlattr *nla;
+
+       nla = __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
+       memcpy(nla_data(nla), data, attrlen);
+}
+EXPORT_SYMBOL(__nla_put_64bit);
+
 /**
  * __nla_put_nohdr - Add a netlink attribute without header
  * @skb: socket buffer to add attribute to
@@ -473,6 +545,33 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
 }
 EXPORT_SYMBOL(nla_put);
 
+/**
+ * nla_put_64bit - Add a netlink attribute to a socket buffer and align it
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @attrlen: length of attribute payload
+ * @data: head of attribute payload
+ *
+ * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
+ * the attribute header and payload.
+ */
+int nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
+                 const void *data, int padattr)
+{
+       size_t len;
+
+       if (nla_need_padding_for_64bit(skb))
+               len = nla_total_size_64bit(attrlen);
+       else
+               len = nla_total_size(attrlen);
+       if (unlikely(skb_tailroom(skb) < len))
+               return -EMSGSIZE;
+
+       __nla_put_64bit(skb, attrtype, attrlen, data, padattr);
+       return 0;
+}
+EXPORT_SYMBOL(nla_put_64bit);
+
 /**
  * nla_put_nohdr - Add a netlink attribute without header
  * @skb: socket buffer to add attribute to