]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blobdiff - fs/afs/addr_list.c
afs: Make use of the YFS service upgrade to fully support IPv6
[mirror_ubuntu-kernels.git] / fs / afs / addr_list.c
index b91e59a77f0e13275c8f5648ae0f91bf440ddba3..a537368ba0db9a9df6afb9e800578b4fe966ded6 100644 (file)
 #include "internal.h"
 #include "afs_fs.h"
 
-#define AFS_MAX_ADDRESSES                                              \
-       ((unsigned int)((PAGE_SIZE - sizeof(struct afs_addr_list)) /    \
-                       sizeof(struct sockaddr_rxrpc)))
+//#define AFS_MAX_ADDRESSES
+//     ((unsigned int)((PAGE_SIZE - sizeof(struct afs_addr_list)) /
+//                     sizeof(struct sockaddr_rxrpc)))
+#define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8))
 
 /*
  * Release an address list.
@@ -230,15 +231,20 @@ struct afs_addr_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry)
 /*
  * Merge an IPv4 entry into a fileserver address list.
  */
-void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr)
+void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)
 {
        struct sockaddr_in6 *a;
+       __be16 xport = htons(port);
        int i;
 
        for (i = 0; i < alist->nr_ipv4; i++) {
                a = &alist->addrs[i].transport.sin6;
-               if (xdr == a->sin6_addr.s6_addr32[3])
+               if (xdr == a->sin6_addr.s6_addr32[3] &&
+                   xport == a->sin6_port)
                        return;
+               if (xdr == a->sin6_addr.s6_addr32[3] &&
+                   xport < a->sin6_port)
+                       break;
                if (xdr < a->sin6_addr.s6_addr32[3])
                        break;
        }
@@ -249,7 +255,7 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr)
                        sizeof(alist->addrs[0]) * (alist->nr_addrs - i));
 
        a = &alist->addrs[i].transport.sin6;
-       a->sin6_port              = htons(AFS_FS_PORT);
+       a->sin6_port              = xport;
        a->sin6_addr.s6_addr32[0] = 0;
        a->sin6_addr.s6_addr32[1] = 0;
        a->sin6_addr.s6_addr32[2] = htonl(0xffff);
@@ -258,6 +264,42 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr)
        alist->nr_addrs++;
 }
 
+/*
+ * Merge an IPv6 entry into a fileserver address list.
+ */
+void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)
+{
+       struct sockaddr_in6 *a;
+       __be16 xport = htons(port);
+       int i, diff;
+
+       for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
+               a = &alist->addrs[i].transport.sin6;
+               diff = memcmp(xdr, &a->sin6_addr, 16);
+               if (diff == 0 &&
+                   xport == a->sin6_port)
+                       return;
+               if (diff == 0 &&
+                   xport < a->sin6_port)
+                       break;
+               if (diff < 0)
+                       break;
+       }
+
+       if (i < alist->nr_addrs)
+               memmove(alist->addrs + i + 1,
+                       alist->addrs + i,
+                       sizeof(alist->addrs[0]) * (alist->nr_addrs - i));
+
+       a = &alist->addrs[i].transport.sin6;
+       a->sin6_port              = xport;
+       a->sin6_addr.s6_addr32[0] = xdr[0];
+       a->sin6_addr.s6_addr32[1] = xdr[1];
+       a->sin6_addr.s6_addr32[2] = xdr[2];
+       a->sin6_addr.s6_addr32[3] = xdr[3];
+       alist->nr_addrs++;
+}
+
 /*
  * Get an address to try.
  */