libnl: add nla_put_u64_64bit() helper
[cascardo/linux.git] / include / net / netlink.h
index 0e31727..e589cb3 100644 (file)
  *   nla_put_s8(skb, type, value)      add s8 attribute to skb
  *   nla_put_s16(skb, type, value)     add s16 attribute to skb
  *   nla_put_s32(skb, type, value)     add s32 attribute to skb
- *   nla_put_s64(skb, type, value)     add s64 attribute to skb
+ *   nla_put_s64(skb, type, value,
+ *               padattr)              add s64 attribute to skb
  *   nla_put_string(skb, type, str)    add string attribute to skb
  *   nla_put_flag(skb, type)           add flag attribute to skb
- *   nla_put_msecs(skb, type, jiffies) add msecs attribute to skb
+ *   nla_put_msecs(skb, type, jiffies,
+ *                 padattr)            add msecs attribute to skb
  *   nla_put_in_addr(skb, type, addr)  add IPv4 address attribute to skb
  *   nla_put_in6_addr(skb, type, addr) add IPv6 address attribute to skb
  *
@@ -244,13 +246,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);
 
@@ -848,36 +858,56 @@ static inline int nla_put_u64(struct sk_buff *skb, int attrtype, u64 value)
 }
 
 /**
- * nla_put_be64 - Add a __be64 netlink attribute to a socket buffer
+ * nla_put_u64_64bit - Add a u64 netlink attribute to a skb and align it
  * @skb: socket buffer to add attribute to
  * @attrtype: attribute type
  * @value: numeric value
+ * @padattr: attribute type for the padding
  */
-static inline int nla_put_be64(struct sk_buff *skb, int attrtype, __be64 value)
+static inline int nla_put_u64_64bit(struct sk_buff *skb, int attrtype,
+                                   u64 value, int padattr)
 {
-       return nla_put(skb, attrtype, sizeof(__be64), &value);
+       return nla_put_64bit(skb, attrtype, sizeof(u64), &value, padattr);
 }
 
 /**
- * nla_put_net64 - Add 64-bit network byte order netlink attribute to a socket buffer
+ * nla_put_be64 - Add a __be64 netlink attribute to a socket buffer and align it
  * @skb: socket buffer to add attribute to
  * @attrtype: attribute type
  * @value: numeric value
+ * @padattr: attribute type for the padding
  */
-static inline int nla_put_net64(struct sk_buff *skb, int attrtype, __be64 value)
+static inline int nla_put_be64(struct sk_buff *skb, int attrtype, __be64 value,
+                              int padattr)
 {
-       return nla_put_be64(skb, attrtype | NLA_F_NET_BYTEORDER, value);
+       return nla_put_64bit(skb, attrtype, sizeof(__be64), &value, padattr);
 }
 
 /**
- * nla_put_le64 - Add a __le64 netlink attribute to a socket buffer
+ * nla_put_net64 - Add 64-bit network byte order nlattr to a skb and align it
  * @skb: socket buffer to add attribute to
  * @attrtype: attribute type
  * @value: numeric value
+ * @padattr: attribute type for the padding
  */
-static inline int nla_put_le64(struct sk_buff *skb, int attrtype, __le64 value)
+static inline int nla_put_net64(struct sk_buff *skb, int attrtype, __be64 value,
+                               int padattr)
 {
-       return nla_put(skb, attrtype, sizeof(__le64), &value);
+       return nla_put_be64(skb, attrtype | NLA_F_NET_BYTEORDER, value,
+                           padattr);
+}
+
+/**
+ * nla_put_le64 - Add a __le64 netlink attribute to a socket buffer and align it
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ * @padattr: attribute type for the padding
+ */
+static inline int nla_put_le64(struct sk_buff *skb, int attrtype, __le64 value,
+                              int padattr)
+{
+       return nla_put_64bit(skb, attrtype, sizeof(__le64), &value, padattr);
 }
 
 /**
@@ -914,14 +944,16 @@ static inline int nla_put_s32(struct sk_buff *skb, int attrtype, s32 value)
 }
 
 /**
- * nla_put_s64 - Add a s64 netlink attribute to a socket buffer
+ * nla_put_s64 - Add a s64 netlink attribute to a socket buffer and align it
  * @skb: socket buffer to add attribute to
  * @attrtype: attribute type
  * @value: numeric value
+ * @padattr: attribute type for the padding
  */
-static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value)
+static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value,
+                             int padattr)
 {
-       return nla_put(skb, attrtype, sizeof(s64), &value);
+       return nla_put_64bit(skb, attrtype, sizeof(s64), &value, padattr);
 }
 
 /**
@@ -947,16 +979,18 @@ static inline int nla_put_flag(struct sk_buff *skb, int attrtype)
 }
 
 /**
- * nla_put_msecs - Add a msecs netlink attribute to a socket buffer
+ * nla_put_msecs - Add a msecs netlink attribute to a skb and align it
  * @skb: socket buffer to add attribute to
  * @attrtype: attribute type
  * @njiffies: number of jiffies to convert to msecs
+ * @padattr: attribute type for the padding
  */
 static inline int nla_put_msecs(struct sk_buff *skb, int attrtype,
-                               unsigned long njiffies)
+                               unsigned long njiffies, int padattr)
 {
        u64 tmp = jiffies_to_msecs(njiffies);
-       return nla_put(skb, attrtype, sizeof(u64), &tmp);
+
+       return nla_put_64bit(skb, attrtype, sizeof(u64), &tmp, padattr);
 }
 
 /**
@@ -1230,6 +1264,61 @@ 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
+ * @padattr: attribute type for the padding
+ *
+ * Conditionally emit a padding netlink attribute in order to make
+ * the next attribute we emit have a 64-bit aligned nla_data() area.
+ * This will only be done in architectures which do not have
+ * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS defined.
+ *
+ * Returns zero on success or a negative error code.
+ */
+static inline int nla_align_64bit(struct sk_buff *skb, int padattr)
+{
+       if (nla_need_padding_for_64bit(skb) &&
+           !nla_reserve(skb, padattr, 0))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+/**
+ * nla_total_size_64bit - total length of attribute including padding
+ * @payload: length of payload
+ */
+static inline int nla_total_size_64bit(int payload)
+{
+       return NLA_ALIGN(nla_attr_size(payload))
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+               + NLA_ALIGN(nla_attr_size(0))
+#endif
+               ;
+}
+
 /**
  * nla_for_each_attr - iterate over a stream of attributes
  * @pos: loop counter, set to current attribute