[IPV6] ADDRCONF: Mobile IPv6 Home Address support.
[sfrench/cifs-2.6.git] / net / ipv6 / addrconf.c
index adb583a2615152953bddff61037e093a97131934..c18676352397cc11a7adc0961262117681b79ab8 100644 (file)
@@ -1038,9 +1038,27 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
                                        continue;
                        }
 
-                       /* Rule 4: Prefer home address -- not implemented yet */
+                       /* Rule 4: Prefer home address */
+#ifdef CONFIG_IPV6_MIP6
+                       if (hiscore.rule < 4) {
+                               if (ifa_result->flags & IFA_F_HOMEADDRESS)
+                                       hiscore.attrs |= IPV6_SADDR_SCORE_HOA;
+                               hiscore.rule++;
+                       }
+                       if (ifa->flags & IFA_F_HOMEADDRESS) {
+                               score.attrs |= IPV6_SADDR_SCORE_HOA;
+                               if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) {
+                                       score.rule = 4;
+                                       goto record_it;
+                               }
+                       } else {
+                               if (hiscore.attrs & IPV6_SADDR_SCORE_HOA)
+                                       continue;
+                       }
+#else
                        if (hiscore.rule < 4)
                                hiscore.rule++;
+#endif
 
                        /* Rule 5: Prefer outgoing interface */
                        if (hiscore.rule < 5) {
@@ -2759,6 +2777,26 @@ void if6_proc_exit(void)
 }
 #endif /* CONFIG_PROC_FS */
 
+#ifdef CONFIG_IPV6_MIP6
+/* Check if address is a home address configured on any interface. */
+int ipv6_chk_home_addr(struct in6_addr *addr)
+{
+       int ret = 0;
+       struct inet6_ifaddr * ifp;
+       u8 hash = ipv6_addr_hash(addr);
+       read_lock_bh(&addrconf_hash_lock);
+       for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) {
+               if (ipv6_addr_cmp(&ifp->addr, addr) == 0 &&
+                   (ifp->flags & IFA_F_HOMEADDRESS)) {
+                       ret = 1;
+                       break;
+               }
+       }
+       read_unlock_bh(&addrconf_hash_lock);
+       return ret;
+}
+#endif
+
 /*
  *     Periodic address status verification
  */
@@ -2930,7 +2968,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
                prefered_lft = 0x7FFFFFFF/HZ;
 
        spin_lock_bh(&ifp->lock);
-       ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD)) | ifa_flags;
+       ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags;
        ifp->tstamp = jiffies;
        ifp->valid_lft = valid_lft;
        ifp->prefered_lft = prefered_lft;
@@ -2981,7 +3019,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                return -ENODEV;
 
        /* We ignore other flags so far. */
-       ifa_flags = ifm->ifa_flags & IFA_F_NODAD;
+       ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS);
 
        ifa = ipv6_get_ifaddr(pfx, dev, 1);
        if (ifa == NULL) {