ipv6 addrconf: extend ifa_flags to u32
authorJiri Pirko <jiri@resnulli.us>
Fri, 6 Dec 2013 08:45:21 +0000 (09:45 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 6 Dec 2013 21:34:43 +0000 (16:34 -0500)
There is no more space in u8 ifa_flags. So do what davem suffested and
add another netlink attr called IFA_FLAGS for carry more flags.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Thomas Haller <thaller@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/addrconf.h
include/net/if_inet6.h
include/uapi/linux/if_addr.h
net/ipv6/addrconf.c

index 86505bfa5d2c4829698d21ce81ba47575b504941..e70278eef12a79da44b5b5ebf1f50489406ce1c1 100644 (file)
@@ -81,9 +81,9 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dev,
                       const struct in6_addr *daddr, unsigned int srcprefs,
                       struct in6_addr *saddr);
 int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
-                     unsigned char banned_flags);
+                     u32 banned_flags);
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
-                   unsigned char banned_flags);
+                   u32 banned_flags);
 int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2);
 void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr);
 void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr);
index 76d54270f2e27c175836b137f363014381e91687..b58c36c1c3f6bfc820ca0988d91064b0a0a39af8 100644 (file)
@@ -50,8 +50,8 @@ struct inet6_ifaddr {
 
        int                     state;
 
+       __u32                   flags;
        __u8                    dad_probes;
-       __u8                    flags;
 
        __u16                   scope;
 
index 23357ab81a7743942766c4ebb701b71cd9e99a84..8ab0c2cc9b7307d9434a9b546cee49e4c017d315 100644 (file)
@@ -18,6 +18,9 @@ struct ifaddrmsg {
  * It makes no difference for normally configured broadcast interfaces,
  * but for point-to-point IFA_ADDRESS is DESTINATION address,
  * local address is supplied in IFA_LOCAL attribute.
+ *
+ * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
+ * If present, the value from struct ifaddrmsg will be ignored.
  */
 enum {
        IFA_UNSPEC,
@@ -28,6 +31,7 @@ enum {
        IFA_ANYCAST,
        IFA_CACHEINFO,
        IFA_MULTICAST,
+       IFA_FLAGS,
        __IFA_MAX,
 };
 
index d5fa5b8c443ecbbcb0ed09a10db19b06730b7d8b..334a7e114e1dbf397ab35b3f5c0d4d1d5bce3767 100644 (file)
@@ -1407,7 +1407,7 @@ try_nextdev:
 EXPORT_SYMBOL(ipv6_dev_get_saddr);
 
 int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
-                     unsigned char banned_flags)
+                     u32 banned_flags)
 {
        struct inet6_ifaddr *ifp;
        int err = -EADDRNOTAVAIL;
@@ -1424,7 +1424,7 @@ int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
 }
 
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
-                   unsigned char banned_flags)
+                   u32 banned_flags)
 {
        struct inet6_dev *idev;
        int err = -EADDRNOTAVAIL;
@@ -2178,7 +2178,7 @@ ok:
                }
 
                if (ifp) {
-                       int flags;
+                       u32 flags;
                        unsigned long now;
                        struct inet6_ifaddr *ift;
                        u32 stored_lft;
@@ -2363,10 +2363,11 @@ err_exit:
 /*
  *     Manual configuration of address on an interface
  */
-static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx,
+static int inet6_addr_add(struct net *net, int ifindex,
+                         const struct in6_addr *pfx,
                          const struct in6_addr *peer_pfx,
-                         unsigned int plen, __u8 ifa_flags, __u32 prefered_lft,
-                         __u32 valid_lft)
+                         unsigned int plen, __u32 ifa_flags,
+                         __u32 prefered_lft, __u32 valid_lft)
 {
        struct inet6_ifaddr *ifp;
        struct inet6_dev *idev;
@@ -3351,7 +3352,7 @@ static void if6_seq_stop(struct seq_file *seq, void *v)
 static int if6_seq_show(struct seq_file *seq, void *v)
 {
        struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v;
-       seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n",
+       seq_printf(seq, "%pi6 %02x %02x %02x %03x %8s\n",
                   &ifp->addr,
                   ifp->idev->dev->ifindex,
                   ifp->prefix_len,
@@ -3572,6 +3573,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
        [IFA_ADDRESS]           = { .len = sizeof(struct in6_addr) },
        [IFA_LOCAL]             = { .len = sizeof(struct in6_addr) },
        [IFA_CACHEINFO]         = { .len = sizeof(struct ifa_cacheinfo) },
+       [IFA_FLAGS]             = { .len = sizeof(u32) },
 };
 
 static int
@@ -3595,7 +3597,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
        return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen);
 }
 
-static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
+static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
                             u32 prefered_lft, u32 valid_lft)
 {
        u32 flags;
@@ -3650,7 +3652,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
        struct inet6_ifaddr *ifa;
        struct net_device *dev;
        u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME;
-       u8 ifa_flags;
+       u32 ifa_flags;
        int err;
 
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
@@ -3677,8 +3679,10 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (dev == NULL)
                return -ENODEV;
 
+       ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags;
+
        /* We ignore other flags so far. */
-       ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS);
+       ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS;
 
        ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
        if (ifa == NULL) {
@@ -3702,7 +3706,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
        return err;
 }
 
-static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags,
+static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u32 flags,
                          u8 scope, int ifindex)
 {
        struct ifaddrmsg *ifm;
@@ -3745,7 +3749,8 @@ static inline int inet6_ifaddr_msgsize(void)
        return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
               + nla_total_size(16) /* IFA_LOCAL */
               + nla_total_size(16) /* IFA_ADDRESS */
-              + nla_total_size(sizeof(struct ifa_cacheinfo));
+              + nla_total_size(sizeof(struct ifa_cacheinfo))
+              + nla_total_size(4)  /* IFA_FLAGS */;
 }
 
 static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
@@ -3793,6 +3798,9 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
        if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0)
                goto error;
 
+       if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0)
+               goto error;
+
        return nlmsg_end(skb, nlh);
 
 error: