diff -NurpP --minimal linux-2.6.21.5-g-v/Documentation/vserver/debug.txt linux-2.6.21.5-g-v-ipv6/Documentation/vserver/debug.txt --- linux-2.6.21.5-g-v/Documentation/vserver/debug.txt 2007-06-20 20:54:36.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/Documentation/vserver/debug.txt 2007-07-01 20:15:38.000000000 +0200 @@ -51,9 +51,17 @@ debug_misc: debug_net: 2 4 "nx_addr_conflict(%p,%p) %d.%d,%d.%d" + "nx_addr6_conflict(%u,%u)" 3 8 "inet_bind(%p) %d.%d.%d.%d, %d.%d.%d.%d, %d.%d.%d.%d" "inet_bind(%p)* %p,%p;%lx %d.%d.%d.%d" + "inet6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL" + "inet6_bind(" NIP6_FMT ", %d): PASS" + "rawv6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL" + "rawv6_bind(" NIP6_FMT ", %d): PASS" 4 10 "ip_route_connect(%p) %p,%p;%lx" + "inet6_create(%p, %d): %d" + "tcp_v6_connect(dest ::1 redirected to: " NIP6_FMT ", %d)" + "__sock_create(%d, %d, %d, %p, %d): EAFNOSUPPORT" 5 20 "__addr_in_socket(%p,%d.%d.%d.%d) %p:%d.%d.%d.%d %p;%lx" 6 40 "sk,egf: %p [#%d] (from %d)" "sk,egn: %p [#%d] (from %d)" @@ -73,6 +81,12 @@ debug_nid: "dealloc_nx_info(%p)" 1 2 "alloc_nx_info(%d)*" "create_nx_info(%d)*" + "vc_net_add(%d, data[%d]): %d.%d.%d.%d" + "vc_net_add(%d, data[%d]): %d.%d.%d.%d EXISTS" + "vc_net_add(%d, data[%d]): %x:%x:%x:%x:%x:%x:%x:%x" + "vc_net_add(%d, data[%d]): %x:%x:%x:%x:%x:%x:%x:%x EXISTS" + "vc_net_remove(%d, data[%d]): %d.%d.%d.%d" + "vc_net_remove(%d, data[%d]): %x:%x:%x:%x:%x:%x:%x:%x" 2 4 "get_nx_info(%p[#%d.%d])" "put_nx_info(%p[#%d.%d])" 3 8 "claim_nx_info(%p[#%d.%d.%d]) %p" diff -NurpP --minimal linux-2.6.21.5-g-v/include/linux/vs_network.h linux-2.6.21.5-g-v-ipv6/include/linux/vs_network.h --- linux-2.6.21.5-g-v/include/linux/vs_network.h 2007-06-20 20:54:37.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/include/linux/vs_network.h 2007-07-01 20:15:45.000000000 +0200 @@ -164,6 +164,9 @@ static inline int addr_in_nx_info(struct return 1; n = nxi->nbipv4; + /* Special case accept anything if addr[0] == :: + * FIXME either accept this on any position or adjust address + * addition in kernel/vserver/network.c */ if (n && (nxi->ipv4[0] == 0)) return 1; for (i = 0; i < n; i++) { @@ -179,6 +182,34 @@ static inline void exit_nx_info(struct t release_nx_info(p->nx_info, p); } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +#include + +static inline int addr6_in_nx_info(struct nx_info *nxi, const struct in6_addr *addr) +{ + int n,i; + + if (!nxi) + return 1; + + n = nxi->nbipv6; + /* Special case accept anything if addr[0] == :: + * FIXME either accept this on any position or adjust address + * addition in kernel/vserver/network.c */ + if (n && nxi->ipv6[0].s6_addr32[0] == 0 && nxi->ipv6[0].s6_addr32[1] == 0 && + nxi->ipv6[0].s6_addr32[2] == 0 && nxi->ipv6[0].s6_addr32[3] == 0) + return 1; + for (i=0; iipv6[i]), addr)) + return 1; + } + return 0; +} + +extern int nx_addr6_conflict(struct nx_info *nxi, struct nx_info *nix2); + +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ #else #warning duplicate inclusion diff -NurpP --minimal linux-2.6.21.5-g-v/include/linux/vserver/network.h linux-2.6.21.5-g-v-ipv6/include/linux/vserver/network.h --- linux-2.6.21.5-g-v/include/linux/vserver/network.h 2007-06-20 20:54:37.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/include/linux/vserver/network.h 2007-07-01 20:15:45.000000000 +0200 @@ -9,7 +9,7 @@ #define NX_DYNAMIC_ID ((uint32_t)-1) /* id for dynamic context */ #define NB_IPV4ROOT 16 - +#define NB_IPV6ROOT 16 /* network flags */ @@ -42,7 +42,9 @@ #include #include #include - +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#include +#endif struct nx_info { struct hlist_node nx_hlist; /* linked list of nxinfos */ @@ -63,10 +65,29 @@ struct nx_info { /* Used to select the proper source */ /* address for sockets */ __u32 v4_bcast; /* Broadcast address to receive UDP */ - +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + int nbipv6; + struct in6_addr ipv6[NB_IPV6ROOT]; /* equivalent to ipv4, but for IPv6 */ + int prefix6[NB_IPV6ROOT]; /* IPv6 prefix length (in bits) */ +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ char nx_name[65]; /* network context name */ }; +struct net_device; + +#ifdef CONFIG_IPV6_MODULE + +struct nx_ipv6_mod { + struct module *owner; + /* Function to check if dev in network context through IPv6 address */ + int (*dev_in_nx_info6)(struct net_device *dev, struct nx_info *nxi); +}; + +extern void vc_net_register_ipv6(struct nx_ipv6_mod *modv6); + +extern void vc_net_unregister_ipv6(void); + +#endif /* status flags */ @@ -104,7 +125,6 @@ extern int nx_migrate_task(struct task_s extern long vs_net_change(struct nx_info *, unsigned int); struct in_ifaddr; -struct net_device; #ifdef CONFIG_INET int ifa_in_nx_info(struct in_ifaddr *, struct nx_info *); diff -NurpP --minimal linux-2.6.21.5-g-v/include/linux/vserver/network_cmd.h linux-2.6.21.5-g-v-ipv6/include/linux/vserver/network_cmd.h --- linux-2.6.21.5-g-v/include/linux/vserver/network_cmd.h 2007-06-20 20:54:37.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/include/linux/vserver/network_cmd.h 2007-07-01 20:15:45.000000000 +0200 @@ -35,11 +35,26 @@ struct vcmd_net_create { #define VCMD_net_add VC_CMD(NETALT, 1, 0) #define VCMD_net_remove VC_CMD(NETALT, 2, 0) +#ifdef __KERNEL__ +#include +#include +#else +#include +#endif /* __KERNEL__ */ + struct vcmd_net_addr_v0 { uint16_t type; uint16_t count; - uint32_t ip[4]; - uint32_t mask[4]; + union { + struct { + struct in_addr ip[4]; + struct in_addr mask[4]; + }; + struct { + struct in6_addr ip6; + uint32_t prefix; + }; + }; /* more to come */ }; diff -NurpP --minimal linux-2.6.21.5-g-v/include/net/addrconf.h linux-2.6.21.5-g-v-ipv6/include/net/addrconf.h --- linux-2.6.21.5-g-v/include/net/addrconf.h 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/include/net/addrconf.h 2007-07-01 20:15:45.000000000 +0200 @@ -69,10 +69,12 @@ extern struct inet6_ifaddr * ipv6_get_if int strict); extern int ipv6_get_saddr(struct dst_entry *dst, struct in6_addr *daddr, - struct in6_addr *saddr); + struct in6_addr *saddr, + struct nx_info *nxi); extern int ipv6_dev_get_saddr(struct net_device *dev, struct in6_addr *daddr, - struct in6_addr *saddr); + struct in6_addr *saddr, + struct nx_info *nxi); extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *); extern int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2); diff -NurpP --minimal linux-2.6.21.5-g-v/include/net/ipv6.h linux-2.6.21.5-g-v-ipv6/include/net/ipv6.h --- linux-2.6.21.5-g-v/include/net/ipv6.h 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/include/net/ipv6.h 2007-07-01 20:15:45.000000000 +0200 @@ -260,6 +260,7 @@ struct ipv6_txoptions *ipv6_fixup_option struct ipv6_txoptions *opt); extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb); +extern int ipv6_dev_in_nx_info6(struct net_device *dev, struct nx_info *nxi); extern int ip6_frag_nqueues; extern atomic_t ip6_frag_mem; diff -NurpP --minimal linux-2.6.21.5-g-v/kernel/vserver/network.c linux-2.6.21.5-g-v-ipv6/kernel/vserver/network.c --- linux-2.6.21.5-g-v/kernel/vserver/network.c 2007-06-20 20:54:37.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/kernel/vserver/network.c 2007-07-01 20:21:45.000000000 +0200 @@ -439,6 +439,27 @@ out: #include #include + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +#include + +int nx_addr6_conflict(struct nx_info *nxi, struct nx_info *nxi2) +{ + vxdprintk(VXD_CBIT(net, 2), "nx_addr6_conflict(%u,%u)", + nxi ? nxi->nx_id : 0, nxi2 ? nxi2->nx_id : 0); + + if (nxi && nxi2 && nxi->nbipv6 > 0 && nxi2->nbipv6 > 0) { + int i = 0; + for (i = 0; i < nxi->nbipv6; i++) + if (addr6_in_nx_info(nxi2, &(nxi->ipv6[i]))) + return 1; + } + return 0; +} + +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + int ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi) { if (!nxi) @@ -448,11 +469,86 @@ int ifa_in_nx_info(struct in_ifaddr *ifa return addr_in_nx_info(nxi, ifa->ifa_local); } +#ifdef CONFIG_IPV6_MODULE + +struct nx_ipv6_mod vc_net_ipv6 = { + .dev_in_nx_info6 = NULL, + .owner = NULL +}; + +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) +static atomic_t nx_ipv6mod_lockct = ATOMIC_INIT(0); +static DEFINE_SPINLOCK(nx_ipv6mod_lock); + +/* The strategy is: modifications of vc_net_ipv6 are short, do not + sleep and veeery rare, but read access should be free of any exclusive + locks. (copied from socket.c) + This should prevent any possible issues with module unloading! + */ + +static void nx_ipv6mod_write_lock(void) +{ + spin_lock(&nx_ipv6mod_lock); + while (atomic_read(&nx_ipv6mod_lockct) != 0) { + spin_unlock(&nx_ipv6mod_lock); + + yield(); + + spin_lock(&nx_ipv6mod_lock); + } +} + +static __inline__ void nx_ipv6mod_write_unlock(void) +{ + spin_unlock(&nx_ipv6mod_lock); +} + +static __inline__ void nx_ipv6mod_read_lock(void) +{ + atomic_inc(&nx_ipv6mod_lockct); + spin_unlock_wait(&nx_ipv6mod_lock); +} + +static __inline__ void nx_ipv6mod_read_unlock(void) +{ + atomic_dec(&nx_ipv6mod_lockct); +} + +#else +#define nx_ipv6mod_write_lock() do { } while(0) +#define nx_ipv6mod_write_unlock() do { } while(0) +#define nx_ipv6mod_read_lock() do { } while(0) +#define nx_ipv6mod_read_unlock() do { } while(0) +#endif + +void vc_net_register_ipv6(struct nx_ipv6_mod *modv6) { + nx_ipv6mod_write_lock(); + memcpy(&vc_net_ipv6, modv6, sizeof(struct nx_ipv6_mod)); + nx_ipv6mod_write_unlock(); +} + +void vc_net_unregister_ipv6() { + nx_ipv6mod_write_lock(); + memset(&vc_net_ipv6, 0, sizeof(struct nx_ipv6_mod)); + nx_ipv6mod_write_unlock(); +} + +inline int dev_in_nx_info6(struct net_device *dev, struct nx_info *nxi) { + nx_ipv6mod_read_lock(); + if (try_module_get(vc_net_ipv6.owner)) { + if (vc_net_ipv6.dev_in_nx_info6) + return vc_net_ipv6.dev_in_nx_info6(dev, nxi); + else + return 0; + module_put(vc_net_ipv6.owner); + } else + return 0; + nx_ipv6mod_read_unlock(); +} +#endif + int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) { - struct in_device *in_dev; - struct in_ifaddr **ifap; - struct in_ifaddr *ifa; int ret = 0; if (!nxi) @@ -460,18 +556,33 @@ int dev_in_nx_info(struct net_device *de if (!dev) goto out; - in_dev = in_dev_get(dev); - if (!in_dev) - goto out; - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; - ifap = &ifa->ifa_next) { - if (addr_in_nx_info(nxi, ifa->ifa_local)) { - ret = 1; - break; + if (nxi->nbipv4 > 0) { + struct in_device *in_dev; + struct in_ifaddr **ifap; + struct in_ifaddr *ifa; + + in_dev = in_dev_get(dev); + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (addr_in_nx_info(nxi, ifa->ifa_local)) { + ret = 1; + break; + } + } + in_dev_put(in_dev); } } - in_dev_put(in_dev); + +#if defined(CONFIG_IPV6_MODULE) + if (ret == 0) + ret = dev_in_nx_info6(dev, nxi); +#elif defined(CONFIG_IPV6) + if (ret == 0) + ret = ipv6_dev_in_nx_info6(dev, nxi); +#endif + out: return ret; } @@ -644,6 +755,40 @@ int vc_net_migrate(struct nx_info *nxi, return nx_migrate_task(current, nxi); } +/* + * Lookup address/mask pair in list of v4 addresses + * Returns position if found, -1 if not found + */ +int vc_net_find_v4(const struct nx_info *nxi, uint32_t addr, uint32_t mask) +{ + int ret = nxi->nbipv4 - 1; + while (ret >= 0) { + if (nxi->ipv4[ret] == addr && nxi->mask[ret] == mask) + break; + else + ret--; + } + return ret; +} + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +/* + * Lookup address/prefix pair list of v6 addresses + * Returns position if found, -1 if not found + */ +int vc_net_find_v6(const struct nx_info *nxi, const struct in6_addr *addr, int prefix) +{ + int ret = nxi->nbipv6 - 1; + while (ret >= 0) { + if (memcmp(&(nxi->ipv6[ret]), addr, sizeof(struct in6_addr)) == 0 && nxi->prefix6[ret] == prefix) + break; + else + ret--; + } + return ret; +} +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + int vc_net_add(struct nx_info *nxi, void __user *data) { struct vcmd_net_addr_v0 vc_data; @@ -658,6 +803,14 @@ int vc_net_add(struct nx_info *nxi, void return -EINVAL; break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case NXA_TYPE_IPV6: + /* Note: all 4 items of IP and MASK must be set, but its 1 IPv6 address */ + if ((vc_data.count != 1)) + return -EINVAL; + break; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + default: break; } @@ -665,21 +818,51 @@ int vc_net_add(struct nx_info *nxi, void switch (vc_data.type) { case NXA_TYPE_IPV4: index = 0; + ret = 0; while ((index < vc_data.count) && ((pos = nxi->nbipv4) < NB_IPV4ROOT)) { - nxi->ipv4[pos] = vc_data.ip[index]; - nxi->mask[pos] = vc_data.mask[index]; + if (vc_net_find_v4(nxi, vc_data.ip[index].s_addr, vc_data.mask[index].s_addr) == -1) { + /* Only add if address is new */ + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIPQUAD_FMT, + nxi->nx_id, index, NIPQUAD(vc_data.ip[index].s_addr)); + nxi->ipv4[pos] = vc_data.ip[index].s_addr; + nxi->mask[pos] = vc_data.mask[index].s_addr; + nxi->nbipv4++; + ret++; + } else + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIPQUAD_FMT " EXISTS", + nxi->nx_id, index, NIPQUAD(vc_data.ip[index].s_addr)); index++; - nxi->nbipv4++; } ret = index; break; case NXA_TYPE_IPV4|NXA_MOD_BCAST: - nxi->v4_bcast = vc_data.ip[0]; + nxi->v4_bcast = vc_data.ip[0].s_addr; ret = 1; break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case NXA_TYPE_IPV6: + index = 0; + ret = 0; + while (nxi->nbipv6 < NB_IPV6ROOT && index < vc_data.count) { + if (vc_net_find_v6(nxi, &vc_data.ip6, vc_data.prefix) == -1) { + /* Only add if address is new */ + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIP6_FMT, + nxi->nx_id, index, NIP6(vc_data.ip6)); + nxi->ipv6[nxi->nbipv6] = vc_data.ip6; + nxi->prefix6[nxi->nbipv6] = vc_data.prefix; + nxi->nbipv6++; + ret++; + } else + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIP6_FMT " EXISTS", + nxi->nx_id, index, NIP6(vc_data.ip6)); + index++; + } + break; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + default: ret = -EINVAL; break; @@ -690,19 +873,68 @@ int vc_net_add(struct nx_info *nxi, void int vc_net_remove(struct nx_info *nxi, void __user *data) { struct vcmd_net_addr_v0 vc_data; + int index, pos, ret = 0; if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) return -EFAULT; switch (vc_data.type) { case NXA_TYPE_ANY: +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + ret = nxi->nbipv6; + nxi->nbipv6 = 0; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + ret += nxi->nbipv4; nxi->nbipv4 = 0; break; + case NXA_TYPE_IPV4: + index = 0; + ret = 0; + while (index < vc_data.count) { + pos = vc_net_find_v4(nxi, vc_data.ip[index].s_addr, vc_data.mask[index].s_addr); + if (pos >= 0) { + nxi->nbipv4--; + ret++; + vxdprintk(VXD_CBIT(nid, 1), "vc_net_remove(%d, data[%d]): " NIPQUAD_FMT, + nxi->nx_id, index, NIPQUAD(vc_data.ip[index].s_addr)); + } + while (pos >= 0 && pos < nxi->nbipv4) { + nxi->ipv4[pos] = nxi->ipv4[pos+1]; + nxi->mask[pos] = nxi->mask[pos+1]; + pos++; + } + index++; + } + break; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case NXA_TYPE_IPV6: + index = 0; + ret = 0; + while (index < vc_data.count) { + pos = vc_net_find_v6(nxi, &(vc_data.ip6), vc_data.prefix); + if (pos >= 0) { + nxi->nbipv6--; + ret++; + vxdprintk(VXD_CBIT(nid, 1), "vc_net_remove(%d, data[%d]): " NIP6_FMT " EXISTS", + nxi->nx_id, index, NIP6(vc_data.ip6)); + } + while (pos >= 0 && pos < nxi->nbipv6) { + nxi->ipv6[pos] = nxi->ipv6[pos+1]; + nxi->prefix6[pos] = nxi->prefix6[pos+1]; + pos++; + } + index++; + } + break; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + default: - return -EINVAL; + ret = -EINVAL; + break; } - return 0; + return ret; } int vc_get_nflags(struct nx_info *nxi, void __user *data) @@ -769,3 +1001,10 @@ int vc_set_ncaps(struct nx_info *nxi, vo EXPORT_SYMBOL_GPL(free_nx_info); EXPORT_SYMBOL_GPL(unhash_nx_info); +#ifdef CONFIG_IPV6_MODULE +EXPORT_SYMBOL_GPL(nx_addr6_conflict); +EXPORT_SYMBOL_GPL(vc_net_register_ipv6); +EXPORT_SYMBOL_GPL(vc_net_unregister_ipv6); +#elif defined(CONFIG_IPV6) +EXPORT_SYMBOL_GPL(nx_addr6_conflict); +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ diff -NurpP --minimal linux-2.6.21.5-g-v/kernel/vserver/proc.c linux-2.6.21.5-g-v-ipv6/kernel/vserver/proc.c --- linux-2.6.21.5-g-v/kernel/vserver/proc.c 2007-06-20 20:54:37.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/kernel/vserver/proc.c 2007-07-01 20:15:45.000000000 +0200 @@ -181,6 +181,13 @@ int proc_nxi_info(struct nx_info *nxi, c "%d:\t" NIPQUAD_FMT "/" NIPQUAD_FMT "\n", i, NIPQUAD(nxi->ipv4[i]), NIPQUAD(nxi->mask[i])); } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + for (i=0; inbipv6;i++) { + length += sprintf(buffer + length, + "%d:\t" NIP6_FMT "/%d\n", i, + NIP6(nxi->ipv6[i]), nxi->prefix6[i]); + } +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ return length; } diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/addrconf.c linux-2.6.21.5-g-v-ipv6/net/ipv6/addrconf.c --- linux-2.6.21.5-g-v/net/ipv6/addrconf.c 2007-06-20 20:54:37.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/addrconf.c 2007-07-01 20:31:51.000000000 +0200 @@ -847,7 +847,7 @@ static inline int ipv6_saddr_label(const } int ipv6_dev_get_saddr(struct net_device *daddr_dev, - struct in6_addr *daddr, struct in6_addr *saddr) + struct in6_addr *daddr, struct in6_addr *saddr, struct nx_info *nxi) { struct ipv6_saddr_score hiscore; struct inet6_ifaddr *ifa_result = NULL; @@ -892,6 +892,11 @@ int ipv6_dev_get_saddr(struct net_device score.addr_type = __ipv6_addr_type(&ifa->addr); + /* Linux-VServer: only take into account addresses + available in guest context! */ + if (!addr6_in_nx_info(nxi, &ifa->addr)) + continue; + /* Rule 0: * - Tentative Address (RFC2462 section 5.4) * - A tentative address is not considered @@ -1102,9 +1107,9 @@ record_it: int ipv6_get_saddr(struct dst_entry *dst, - struct in6_addr *daddr, struct in6_addr *saddr) + struct in6_addr *daddr, struct in6_addr *saddr, struct nx_info *nxi) { - return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr); + return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr, nxi); } @@ -1207,26 +1212,48 @@ int ipv6_rcv_saddr_equal(const struct so int addr_type = ipv6_addr_type(sk_rcv_saddr6); int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; - if (!sk2_rcv_saddr && !sk_ipv6only) - return 1; - - if (addr_type2 == IPV6_ADDR_ANY && - !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) - return 1; + if (sk->sk_nid != sk2->sk_nid) { + // either socket is in host context and bound to everything + if (sk->sk_nx_info == NULL && addr_type == IPV6_ADDR_ANY && !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + return 1; + if (sk2->sk_nx_info == NULL && addr_type2 == IPV6_ADDR_ANY && !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) + return 1; + // If both addresses are equal + if (sk2_rcv_saddr6 && ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) + return 1; + // If one socket bound to everything and the addr bound by other socket is in first context + if (addr_type2 == IPV6_ADDR_ANY && !(addr_type == IPV6_ADDR_ANY || addr_type == IPV6_ADDR_MAPPED) && + addr6_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr6)) + return 1; + if (addr_type == IPV6_ADDR_ANY && !(addr_type2 == IPV6_ADDR_ANY || addr_type2 == IPV6_ADDR_MAPPED) && + sk2_rcv_saddr6 && addr6_in_nx_info(sk->sk_nx_info, sk2_rcv_saddr6)) + return 1; + // both sockets are in guests and bound to everything with addr-overlap between guests + if (sk->sk_nx_info && sk2->sk_nx_info && addr_type == IPV6_ADDR_ANY && addr_type2 == IPV6_ADDR_ANY && + nx_addr6_conflict(sk->sk_nx_info, sk2->sk_nx_info)) + return 1; + // TODO: handle the IPv4 addresses mapped in IPv6 completely... + } else { + if (!sk2_rcv_saddr && !sk_ipv6only) + return 1; - if (addr_type == IPV6_ADDR_ANY && - !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) - return 1; + if (addr_type2 == IPV6_ADDR_ANY && + !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) + return 1; - if (sk2_rcv_saddr6 && - ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) - return 1; + if (addr_type == IPV6_ADDR_ANY && + !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + return 1; - if (addr_type == IPV6_ADDR_MAPPED && - !sk2_ipv6only && - (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr)) - return 1; + if (sk2_rcv_saddr6 && + ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) + return 1; + if (addr_type == IPV6_ADDR_MAPPED && + !sk2_ipv6only && + (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr)) + return 1; + } return 0; } @@ -2682,8 +2709,9 @@ static int if6_seq_show(struct seq_file { struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; - /* no ipv6 inside a vserver for now */ - if (nx_check(0, VS_ADMIN|VS_WATCH)) + /* Only addresses visible to vserver context */ + if (nx_check(0, VS_ADMIN|VS_WATCH) || + addr6_in_nx_info(current_nx_info(), &ifp->addr)) seq_printf(seq, NIP6_SEQFMT " %02x %02x %02x %02x %8s\n", NIP6(ifp->addr), @@ -3167,8 +3195,8 @@ static int inet6_dump_addr(struct sk_buf struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; - /* no ipv6 inside a vserver for now */ - if (skb->sk && skb->sk->sk_vx_info) + /* no ipv6 inside a vserver if no addr set */ + if (skb->sk && skb->sk->sk_nx_info && skb->sk->sk_nx_info->nbipv6 == 0) return skb->len; s_idx = cb->args[0]; @@ -3191,6 +3219,8 @@ static int inet6_dump_addr(struct sk_buf ifa = ifa->if_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !addr6_in_nx_info(skb->sk->sk_nx_info, &ifa->addr)) + continue; /* Skip addresses not in nx */ if ((err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR, @@ -3204,6 +3234,8 @@ static int inet6_dump_addr(struct sk_buf ifmca = ifmca->next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !addr6_in_nx_info(skb->sk->sk_nx_info, &ifmca->mca_addr)) + continue; /* Skip addresses not in nx */ if ((err = inet6_fill_ifmcaddr(skb, ifmca, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_GETMULTICAST, @@ -3217,6 +3249,8 @@ static int inet6_dump_addr(struct sk_buf ifaca = ifaca->aca_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !addr6_in_nx_info(skb->sk->sk_nx_info, &ifaca->aca_addr)) + continue; /* Skip addresses not in nx */ if ((err = inet6_fill_ifacaddr(skb, ifaca, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_GETANYCAST, @@ -3450,14 +3484,16 @@ static int inet6_dump_ifinfo(struct sk_b struct net_device *dev; struct inet6_dev *idev; - /* no ipv6 inside a vserver for now */ - if (skb->sk && skb->sk->sk_vx_info) + /* no ipv6 inside a vserver if no addr set */ + if (skb->sk && skb->sk->sk_nx_info && skb->sk->sk_nx_info->nbipv6 == 0) return skb->len; read_lock(&dev_base_lock); for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { if (idx < s_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !ipv6_dev_in_nx_info6(dev, skb->sk->sk_nx_info)) + continue; if ((idev = in6_dev_get(dev)) == NULL) continue; err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid, diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/af_inet6.c linux-2.6.21.5-g-v-ipv6/net/ipv6/af_inet6.c --- linux-2.6.21.5-g-v/net/ipv6/af_inet6.c 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/af_inet6.c 2007-07-01 20:26:25.000000000 +0200 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -146,9 +147,11 @@ lookup_protocol: } err = -EPERM; + if ((protocol == IPPROTO_ICMPV6) && vx_ccaps(VXC_RAW_ICMP)) + goto override; if (answer->capability > 0 && !capable(answer->capability)) goto out_rcu_unlock; - +override: sock->ops = answer->ops; answer_prot = answer->prot; answer_no_check = answer->no_check; @@ -232,6 +235,8 @@ lookup_protocol: } } out: + vxdprintk(VXD_CBIT(net, 4), "inet6_create(%p, %d): %d", + sock, protocol, err); return err; out_rcu_unlock: rcu_read_unlock(); @@ -305,6 +310,18 @@ int inet6_bind(struct socket *sock, stru } } + /* VServer: Only accept if we have the address available */ + if (sk->sk_nx_info && !addr6_in_nx_info(sk->sk_nx_info, &addr->sin6_addr)) { + vxdprintk(VXD_CBIT(net, 3), "inet6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL", + NIP6(addr->sin6_addr), sk->sk_nx_info->nx_id); + err = -EADDRNOTAVAIL; + if (dev) + dev_put(dev); + goto out; + } else + vxdprintk(VXD_CBIT(net, 3), "inet6_bind(" NIP6_FMT ", %d): PASS", + NIP6(addr->sin6_addr), sk->sk_nx_info ? sk->sk_nx_info->nx_id : 0); + /* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent. */ @@ -691,6 +708,31 @@ int ipv6_opt_accepted(struct sock *sk, s EXPORT_SYMBOL_GPL(ipv6_opt_accepted); +int ipv6_dev_in_nx_info6(struct net_device *dev, struct nx_info *nxi) { + int ret = 0; + + if (nxi->nbipv6 > 0) { + struct inet6_dev *in_dev; + struct inet6_ifaddr **ifap; + struct inet6_ifaddr *ifa; + + in_dev = in6_dev_get(dev); + if (in_dev) { + for (ifap = &in_dev->addr_list; (ifa = *ifap) != NULL; + ifap = &ifa->if_next) { + if (addr6_in_nx_info(nxi, &(ifa->addr))) { + ret = 1; + break; + } + } + in6_dev_put(in_dev); + } + } + return ret; +} + +EXPORT_SYMBOL_GPL(ipv6_dev_in_nx_info6); + int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) { @@ -759,6 +801,17 @@ static void cleanup_ipv6_mibs(void) snmp6_mib_free((void **)udplite_stats_in6); } +#ifdef CONFIG_IPV6_MODULE +static void vc_net_register_init(void) +{ + struct nx_ipv6_mod mymod = { + .dev_in_nx_info6 = ipv6_dev_in_nx_info6, + .owner = THIS_MODULE + }; + vc_net_register_ipv6(&mymod); +} +#endif + static int __init inet6_init(void) { struct sk_buff *dummy_skb; @@ -876,6 +929,11 @@ static int __init inet6_init(void) tcpv6_init(); ipv6_packet_init(); + +#ifdef CONFIG_IPV6_MODULE + vc_net_register_init(); +#endif + err = 0; out: return err; @@ -938,6 +996,9 @@ static void __exit inet6_exit(void) addrconf_cleanup(); ip6_flowlabel_cleanup(); ip6_route_cleanup(); +#ifdef CONFIG_IPV6_MODULE + vc_net_unregister_ipv6(); +#endif #ifdef CONFIG_PROC_FS /* Cleanup code parts. */ diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/inet6_hashtables.c linux-2.6.21.5-g-v-ipv6/net/ipv6/inet6_hashtables.c --- linux-2.6.21.5-g-v/net/ipv6/inet6_hashtables.c 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/inet6_hashtables.c 2007-07-01 20:15:48.000000000 +0200 @@ -102,6 +102,26 @@ hit: } EXPORT_SYMBOL(__inet6_lookup_established); +/* + * Check if a given address matches for an inet socket + * + * nxi: the socket's nx_info if any + * addr: to be verified address + * saddr: socket addresses + */ +static inline int inet6_addr_match( + struct nx_info *nxi, + const struct in6_addr *addr, + const struct in6_addr *saddr) +{ + if ((addr->s6_addr32[0] || addr->s6_addr32[1] || addr->s6_addr32[2] || addr->s6_addr32[3]) && + memcmp(saddr,addr, sizeof(struct in6_addr)) == 0) + return 1; + if (!(saddr->s6_addr32[0] || saddr->s6_addr32[1] || saddr->s6_addr32[2] || saddr->s6_addr32[3])) + return addr6_in_nx_info(nxi, addr); + return 0; +} + struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, const struct in6_addr *daddr, const unsigned short hnum, const int dif) @@ -127,6 +147,10 @@ struct sock *inet6_lookup_listener(struc continue; score++; } + if (!inet6_addr_match(sk->sk_nx_info, daddr, &(np->rcv_saddr))) { + /* No, this address is not available for guest */ + continue; + } if (score == 3) { result = sk; break; diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/ip6_output.c linux-2.6.21.5-g-v-ipv6/net/ipv6/ip6_output.c --- linux-2.6.21.5-g-v/net/ipv6/ip6_output.c 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/ip6_output.c 2007-07-01 20:15:48.000000000 +0200 @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -863,7 +862,8 @@ static int ip6_dst_lookup_tail(struct so goto out_err_release; if (ipv6_addr_any(&fl->fl6_src)) { - err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); + err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src, sk->sk_nx_info); + if (err) goto out_err_release; } diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/ndisc.c linux-2.6.21.5-g-v-ipv6/net/ipv6/ndisc.c --- linux-2.6.21.5-g-v/net/ipv6/ndisc.c 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/ndisc.c 2007-07-01 20:15:48.000000000 +0200 @@ -449,7 +449,7 @@ static void ndisc_send_na(struct net_dev src_addr = solicited_addr; in6_ifa_put(ifp); } else { - if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) + if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, NULL)) return; src_addr = &tmpaddr; } diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/raw.c linux-2.6.21.5-g-v-ipv6/net/ipv6/raw.c --- linux-2.6.21.5-g-v/net/ipv6/raw.c 2007-06-20 20:37:09.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/raw.c 2007-07-01 20:24:57.000000000 +0200 @@ -102,7 +102,8 @@ struct sock *__raw_v6_lookup(struct sock continue; if (!ipv6_addr_any(&np->rcv_saddr)) { - if (ipv6_addr_equal(&np->rcv_saddr, loc_addr)) + if (ipv6_addr_equal(&np->rcv_saddr, loc_addr) && + addr6_in_nx_info(sk->sk_nx_info, loc_addr)) goto found; if (is_multicast && inet6_mc_check(sk, loc_addr, rmt_addr)) @@ -260,6 +261,17 @@ static int rawv6_bind(struct sock *sk, s goto out; } } + /* VServer: Only accept if we have the address available */ + if (sk->sk_nx_info && !addr6_in_nx_info(sk->sk_nx_info, &addr->sin6_addr)) { + vxdprintk(VXD_CBIT(net, 3), "rawv6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL", + NIP6(addr->sin6_addr), sk->sk_nx_info->nx_id); + err = -EADDRNOTAVAIL; + if (dev) + dev_put(dev); + goto out; + } else + vxdprintk(VXD_CBIT(net, 3), "rawv6_bind(" NIP6_FMT ", %d): PASS", + NIP6(addr->sin6_addr), sk->sk_nx_info ? sk->sk_nx_info->nx_id : 0); /* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent. @@ -584,6 +596,11 @@ static int rawv6_send_hdrinc(struct sock if (err) goto error_fault; + err = -EPERM; + if (!nx_check(0, VS_ADMIN) && !capable(CAP_NET_RAW) + && (!addr6_in_nx_info(sk->sk_nx_info, &iph->saddr))) + goto error_free; + IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); @@ -596,6 +613,7 @@ out: error_fault: err = -EFAULT; +error_free: kfree_skb(skb); error: IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/route.c linux-2.6.21.5-g-v-ipv6/net/ipv6/route.c --- linux-2.6.21.5-g-v/net/ipv6/route.c 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/route.c 2007-07-01 20:15:48.000000000 +0200 @@ -2118,7 +2118,7 @@ static int rt6_fill_node(struct sk_buff NLA_PUT_U32(skb, RTA_IIF, iif); else if (dst) { struct in6_addr saddr_buf; - if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) + if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf, NULL) == 0) NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/tcp_ipv6.c linux-2.6.21.5-g-v-ipv6/net/ipv6/tcp_ipv6.c --- linux-2.6.21.5-g-v/net/ipv6/tcp_ipv6.c 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/tcp_ipv6.c 2007-07-01 20:29:13.000000000 +0200 @@ -160,8 +160,20 @@ static int tcp_v6_connect(struct sock *s * connect() to INADDR_ANY means loopback (BSD'ism). */ - if(ipv6_addr_any(&usin->sin6_addr)) - usin->sin6_addr.s6_addr[15] = 0x1; + if(ipv6_addr_any(&usin->sin6_addr)) { + if (sk->sk_nx_info) { + if (sk->sk_nx_info->nbipv6) { + /* Linux-VServer: redirects to first IPv6 address set for guest + TODO: search for existing loopback address in guest context... */ + usin->sin6_addr = sk->sk_nx_info->ipv6[0]; + vxdprintk(VXD_CBIT(net, 4), "tcp_v6_connect(dest ::1 redirected to: " NIP6_FMT ", %d)", + NIP6(usin->sin6_addr), sk->sk_nx_info->nx_id); + } else + return -ENETUNREACH; + } else + usin->sin6_addr.s6_addr[15] = 0x1; + } + addr_type = ipv6_addr_type(&usin->sin6_addr); diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/udp.c linux-2.6.21.5-g-v-ipv6/net/ipv6/udp.c --- linux-2.6.21.5-g-v/net/ipv6/udp.c 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/udp.c 2007-07-01 20:15:48.000000000 +0200 @@ -57,6 +57,17 @@ static inline int udp_v6_get_port(struct return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); } +static inline int udp_v6_in_list(struct nx_info *nx_info, struct in6_addr *addr) +{ + int n = nx_info->nbipv6; + int i; + + for (i=0; iipv6[i], addr)) + return 1; + return 0; +} + static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, struct in6_addr *daddr, __be16 dport, int dif, struct hlist_head udptable[]) @@ -82,6 +93,11 @@ static struct sock *__udp6_lib_lookup(st if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) continue; score++; + } else if (sk->sk_nx_info) { + if (udp_v6_in_list(sk->sk_nx_info, daddr)) + score++; + else + continue; } if (!ipv6_addr_any(&np->daddr)) { if (!ipv6_addr_equal(&np->daddr, saddr)) diff -NurpP --minimal linux-2.6.21.5-g-v/net/ipv6/xfrm6_policy.c linux-2.6.21.5-g-v-ipv6/net/ipv6/xfrm6_policy.c --- linux-2.6.21.5-g-v/net/ipv6/xfrm6_policy.c 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/ipv6/xfrm6_policy.c 2007-07-01 20:15:48.000000000 +0200 @@ -49,7 +49,7 @@ static int xfrm6_get_saddr(xfrm_address_ if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) { ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6, - (struct in6_addr *)&saddr->a6); + (struct in6_addr *)&saddr->a6, NULL); dst_release(&rt->u.dst); return 0; } diff -NurpP --minimal linux-2.6.21.5-g-v/net/sctp/ipv6.c linux-2.6.21.5-g-v-ipv6/net/sctp/ipv6.c --- linux-2.6.21.5-g-v/net/sctp/ipv6.c 2007-06-11 20:37:06.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/sctp/ipv6.c 2007-07-01 20:15:48.000000000 +0200 @@ -305,7 +305,7 @@ static void sctp_v6_get_saddr(struct sct __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr)); if (!asoc) { - ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr); + ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr, NULL); SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", NIP6(saddr->v6.sin6_addr)); return; diff -NurpP --minimal linux-2.6.21.5-g-v/net/socket.c linux-2.6.21.5-g-v-ipv6/net/socket.c --- linux-2.6.21.5-g-v/net/socket.c 2007-06-20 20:54:37.000000000 +0200 +++ linux-2.6.21.5-g-v-ipv6/net/socket.c 2007-07-01 20:15:48.000000000 +0200 @@ -95,6 +95,7 @@ #include #include #include +#include extern void gr_attach_curr_ip(const struct sock *sk); extern int gr_handle_sock_all(const int family, const int type, @@ -1099,9 +1100,14 @@ static int __sock_create(int family, int if (type < 0 || type >= SOCK_MAX) return -EINVAL; - /* disable IPv6 inside vservers for now */ - if (family == PF_INET6 && !nx_check(0, VS_ADMIN)) +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + /* disable IPv6 inside vservers that have no IPv6 address configured */ + if (family == PF_INET6 && current_nx_info() && current_nx_info()->nbipv6 == 0) { + vxdprintk(VXD_CBIT(net, 4), "__sock_create(%d, %d, %d, %p, %d): EAFNOSUPPORT", + family, type, protocol, res, kern); return -EAFNOSUPPORT; + } +#endif /* Compatibility.