Subject: [PATCH] nethost: refactored From: Eric W. Biederman Date: 1136848674 -0700 - Network devices and not ip address are tagged. This is much more powerful but unfortunately a little more intrusive. - The initialization and cleanup paths in the ipv4 and ipv6 stacks still need to be fixed to work for the right reasons but everything should work from the user space perspective. --- drivers/net/Space.c | 2 drivers/net/loopback.c | 5 - include/linux/in_route.h | 1 include/linux/inetdevice.h | 14 +-- include/linux/net.h | 6 + include/linux/netdevice.h | 24 +++-- include/linux/nethost.h | 38 +++---- include/linux/netlink.h | 8 +- include/linux/rtnetlink.h | 2 include/linux/sched.h | 1 include/net/addrconf.h | 3 - include/net/flow.h | 2 include/net/if_inet6.h | 2 include/net/ip.h | 12 +- include/net/ip6_fib.h | 6 + include/net/ip6_host.h | 16 +++ include/net/ip6_route.h | 19 ++-- include/net/ip_fib.h | 47 ++++----- include/net/ip_host.h | 29 ++++++ include/net/neighbour.h | 1 include/net/protocol.h | 6 + include/net/route.h | 22 +--- include/net/tcp.h | 2 include/net/udp.h | 2 include/net/xfrm.h | 10 +- kernel/fork.c | 2 lib/kobject_uevent.c | 3 - net/802/tr.c | 2 net/8021q/vlan.c | 4 - net/8021q/vlan_dev.c | 15 ++- net/atm/clip.c | 3 - net/bridge/br_if.c | 2 net/bridge/br_ioctl.c | 2 net/bridge/br_netfilter.c | 2 net/core/dev.c | 191 +++++++++++++++++++++++++++++++++---- net/core/dst.c | 9 +- net/core/ethtool.c | 2 net/core/host.c | 115 ++++++++++++++++++++-- net/core/neighbour.c | 28 ++++- net/core/net-sysfs.c | 81 +++++++++++++++- net/core/netpoll.c | 2 net/core/rtnetlink.c | 18 ++-- net/core/sock.c | 8 +- net/core/wireless.c | 4 - net/dccp/ipv4.c | 2 net/decnet/dn_neigh.c | 2 net/ethernet/eth.c | 2 net/ipv4/af_inet.c | 60 +++++++++--- net/ipv4/ah4.c | 3 - net/ipv4/arp.c | 28 +++-- net/ipv4/devinet.c | 200 ++++++++------------------------------- net/ipv4/esp4.c | 3 - net/ipv4/fib_frontend.c | 94 ++++++++++-------- net/ipv4/fib_hash.c | 19 ++-- net/ipv4/fib_lookup.h | 5 + net/ipv4/fib_rules.c | 21 +++- net/ipv4/fib_semantics.c | 66 +++++++------ net/ipv4/fib_trie.c | 11 +- net/ipv4/icmp.c | 24 ++--- net/ipv4/igmp.c | 27 +++-- net/ipv4/inet_connection_sock.c | 2 net/ipv4/inet_diag.c | 6 + net/ipv4/ip_fragment.c | 18 ++-- net/ipv4/ip_gre.c | 21 ++-- net/ipv4/ip_input.c | 2 net/ipv4/ip_options.c | 36 ++++--- net/ipv4/ip_output.c | 6 + net/ipv4/ip_sockglue.c | 13 +-- net/ipv4/ipcomp.c | 5 + net/ipv4/ipip.c | 15 ++- net/ipv4/ipmr.c | 20 ++-- net/ipv4/ipvs/ip_vs_xmit.c | 6 + net/ipv4/netfilter.c | 7 + net/ipv4/netfilter/ipt_REJECT.c | 4 - net/ipv4/raw.c | 15 +-- net/ipv4/route.c | 185 ++++++++++++++---------------------- net/ipv4/syncookies.c | 4 - net/ipv4/tcp_ipv4.c | 8 +- net/ipv4/udp.c | 10 +- net/ipv4/xfrm4_input.c | 3 - net/ipv4/xfrm4_policy.c | 2 net/ipv4/xfrm4_state.c | 5 + net/ipv6/addrconf.c | 154 ++++++++++-------------------- net/ipv6/af_inet6.c | 45 +++++++-- net/ipv6/ah6.c | 3 - net/ipv6/anycast.c | 12 +- net/ipv6/datagram.c | 6 + net/ipv6/esp6.c | 3 - net/ipv6/icmp.c | 6 + net/ipv6/ip6_fib.c | 16 ++- net/ipv6/ip6_output.c | 3 - net/ipv6/ip6_tunnel.c | 11 +- net/ipv6/ipcomp6.c | 5 + net/ipv6/ipv6_sockglue.c | 2 net/ipv6/mcast.c | 17 ++- net/ipv6/ndisc.c | 4 - net/ipv6/raw.c | 6 + net/ipv6/reassembly.c | 16 ++- net/ipv6/route.c | 78 ++++++++------- net/ipv6/sit.c | 10 +- net/ipv6/tcp_ipv6.c | 16 ++- net/ipv6/xfrm6_input.c | 3 - net/ipv6/xfrm6_policy.c | 2 net/ipv6/xfrm6_state.c | 5 + net/key/af_key.c | 21 ++-- net/netlink/af_netlink.c | 52 +++++----- net/packet/af_packet.c | 34 +++++-- net/sched/cls_api.c | 11 +- net/sched/sch_api.c | 22 +++- net/sctp/protocol.c | 3 - net/socket.c | 41 ++++++++ net/unix/af_unix.c | 16 ++- net/xfrm/xfrm_policy.c | 16 ++- net/xfrm/xfrm_state.c | 21 +++- net/xfrm/xfrm_user.c | 39 ++++---- 115 files changed, 1400 insertions(+), 1032 deletions(-) create mode 100644 include/net/ip6_host.h create mode 100644 include/net/ip_host.h 84b0638de34bf3512cb03ce4cfef2c504a3df4a3 diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 9fc460a..27c2139 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -362,9 +362,11 @@ static int __init net_olddevs_init(void) { int num; +#if 0 if (nethost_init()) { printk(KERN_ERR "Network loopback device setup failed\n"); } +#endif #ifdef CONFIG_SBNI diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 1a427a4..40e83fb 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -243,12 +243,7 @@ static int loopback_init(struct net_devi int loopback_setup(struct net_device *dev) { - static int instance; - strcpy(dev->name, "lo"); - if (instance++) { - snprintf(dev->name, sizeof(dev->name), "lo%d", instance); - } dev->init = loopback_init; return register_netdevice(dev); } diff --git a/include/linux/in_route.h b/include/linux/in_route.h index 16b796c..61f25c3 100644 --- a/include/linux/in_route.h +++ b/include/linux/in_route.h @@ -14,7 +14,6 @@ #define RTCF_REDIRECTED 0x00040000 #define RTCF_TPROXY 0x00080000 -#define RTCF_OUTPUT 0x00100000 /* This is a cached output route */ #define RTCF_FAST 0x00200000 #define RTCF_MASQ 0x00400000 #define RTCF_SNAT 0x00800000 diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 2b22334..31cc895 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -35,9 +35,11 @@ struct ipv4_devconf extern struct ipv4_devconf ipv4_devconf; +struct ip_host; struct in_device { struct net_device *dev; + struct ip_host *ihost; atomic_t refcnt; int dead; struct in_ifaddr *ifa_list; /* IP ifaddr chain */ @@ -89,7 +91,6 @@ struct in_ifaddr { struct in_ifaddr *ifa_next; struct in_device *ifa_dev; - struct nethost *ifa_host; /* Which host am I for? */ struct rcu_head rcu_head; u32 ifa_local; u32 ifa_address; @@ -105,19 +106,16 @@ struct in_ifaddr extern int register_inetaddr_notifier(struct notifier_block *nb); extern int unregister_inetaddr_notifier(struct notifier_block *nb); -extern struct net_device *ip_dev_find(u32 addr); +extern struct net_device *ip_dev_find(struct nethost *host, u32 addr); extern int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b); extern int devinet_ioctl(unsigned int cmd, void __user *); extern void devinet_init(void); extern struct in_device *inetdev_init(struct net_device *dev); -extern struct in_device *inetdev_by_index(int); -extern u32 inet_select_addr(struct nethost *host, - const struct net_device *dev, u32 dst, +extern struct in_device *inetdev_by_index(struct nethost *host, int); +extern u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope); -extern u32 inet_confirm_addr(struct nethost *host, - const struct net_device *dev, u32 dst, +extern u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope); -extern struct nethost * inet_host(struct net_device *dev, u32 addr); extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask); extern void inet_forward_change(void); diff --git a/include/linux/net.h b/include/linux/net.h index 5994caa..da9d702 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -120,6 +120,7 @@ struct kiocb; struct sockaddr; struct msghdr; struct module; +struct nethost; struct proto_ops { int family; @@ -161,13 +162,14 @@ struct proto_ops { struct net_proto_family { int family; + int (*host_init)(struct nethost *host); + void (*host_fini)(struct nethost *host); int (*create)(struct socket *sock, int protocol); /* These are counters for the number of different methods of each we support */ short authentication; short encryption; short encrypt_net; - unsigned multi_host : 1; /* Flag indicating multiple host support */ struct module *owner; }; @@ -177,6 +179,8 @@ struct kvec; extern int sock_wake_async(struct socket *sk, int how, int band); extern int sock_register(struct net_proto_family *fam); extern int sock_unregister(int family); +extern int sock_host_init(struct nethost *host); +extern void sock_host_fini(struct nethost *host); extern int sock_create(int family, int type, int proto, struct socket **res); extern int sock_create_kern(int family, int type, int proto, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3b3d5aa..6613c60 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -245,6 +245,7 @@ struct netdev_boot_setup { #define NETDEV_BOOT_SETUP_MAX 8 extern int __init netdev_boot_setup(char *str); +struct nethost; /* * The DEVICE structure. @@ -491,6 +492,9 @@ struct net_device void (*poll_controller)(struct net_device *dev); #endif + /* owning nethost */ + struct nethost *host; + /* bridge stuff */ struct net_bridge_port *br_port; @@ -538,16 +542,21 @@ extern rwlock_t dev_base_lock; /* De extern int netdev_boot_setup_check(struct net_device *dev); extern unsigned long netdev_boot_base(const char *prefix, int unit); -extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr); -extern struct net_device *dev_getfirstbyhwtype(unsigned short type); +extern struct net_device *dev_getbyhwaddr(struct nethost *host, + unsigned short type, char *hwaddr); +extern struct net_device *dev_getfirstbyhwtype(struct nethost *host, + unsigned short type); extern void dev_add_pack(struct packet_type *pt); extern void dev_remove_pack(struct packet_type *pt); extern void __dev_remove_pack(struct packet_type *pt); -extern struct net_device *dev_get_by_flags(unsigned short flags, +extern struct net_device *dev_get_by_flags(struct nethost *host, + unsigned short flags, unsigned short mask); -extern struct net_device *dev_get_by_name(const char *name); -extern struct net_device *__dev_get_by_name(const char *name); +extern struct net_device *dev_get_by_name(struct nethost *host, + const char *name); +extern struct net_device *__dev_get_by_name(struct nethost *host, + const char *name); extern int dev_alloc_name(struct net_device *dev, const char *name); extern int dev_open(struct net_device *dev); extern int dev_close(struct net_device *dev); @@ -559,8 +568,8 @@ extern void synchronize_net(void); extern int register_netdevice_notifier(struct notifier_block *nb); extern int unregister_netdevice_notifier(struct notifier_block *nb); extern int call_netdevice_notifiers(unsigned long val, void *v); -extern struct net_device *dev_get_by_index(int ifindex); -extern struct net_device *__dev_get_by_index(int ifindex); +extern struct net_device *dev_get_by_index(struct nethost *host, int ifindex); +extern struct net_device *__dev_get_by_index(struct nethost *host, int ifindex); extern int dev_restart(struct net_device *dev); #ifdef CONFIG_NETPOLL_TRAP extern int netpoll_trap(void); @@ -690,6 +699,7 @@ extern int dev_change_name(struct net_d extern int dev_set_mtu(struct net_device *, int); extern int dev_set_mac_address(struct net_device *, struct sockaddr *); +extern int dev_change_nethost(struct net_device *, struct nethost *host); extern void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev); extern void dev_init(void); diff --git a/include/linux/nethost.h b/include/linux/nethost.h index 1105826..a968712 100644 --- a/include/linux/nethost.h +++ b/include/linux/nethost.h @@ -8,17 +8,24 @@ #include #include +struct ip_host; +struct ip6_host; + struct nethost { atomic_t count; struct new_utsname utsname; #ifdef CONFIG_NET - struct net_device loopback_dev; - struct work_struct work; + struct class net_class; + struct net_device loopback_dev; + struct work_struct work; + /* Protocol specific pointers */ + struct ip_host *ip_host; /* IPv4 specific data */ + struct ip6_host *ip6_host; /* IPv6 specific data */ #endif }; extern struct nethost init_host; -extern int loopback_init(struct net_device *loopback_dev); +extern int loopback_setup(struct net_device *loopback_dev); #ifdef CONFIG_NET @@ -42,6 +49,10 @@ static inline void __copy_host(int flags down_read(&uts_sem); memcpy(&host->utsname, &p->host->utsname, sizeof(host->utsname)); up_read(&uts_sem); + /* Revert nodename and domainname their default values */ + strncpy(host->utsname.nodename, UTS_NODENAME, sizeof(host->utsname.nodename)); + strncpy(host->utsname.domainname, UTS_DOMAINNAME, sizeof(host->utsname.domainname)); + p->host = host; } @@ -76,25 +87,4 @@ static inline void exit_host(struct task put_host(host); } -static inline struct nethost *loopback_host(struct net_device *dev) -{ - struct nethost *host = NULL; - if (dev && (dev->flags & IFF_LOOPBACK)) - host = container_of(dev, struct nethost, loopback_dev); - return host; -} - -static inline struct nethost *ifindex_host(int ifindex) -{ - struct nethost *host = NULL; - if (ifindex) { - struct net_device *dev = dev_get_by_index(ifindex); - if (dev) { - host = loopback_host(dev); - dev_put(dev); - } - } - return host; -} - #endif /* _LINUX_NETHOST_H */ diff --git a/include/linux/netlink.h b/include/linux/netlink.h index a0812dd..fe655ae 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -130,11 +130,9 @@ struct netlink_skb_parms extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module); extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); -extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, - __u32 group, gfp_t allocation); -extern int netlink_host_broadcast(struct sock *ssk, struct sk_buff *skb, - struct nethost *host, __u32 pid, - __u32 group, gfp_t allocation); +extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, + struct nethost *host, __u32 pid, __u32 group, + gfp_t allocation); extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); extern int netlink_register_notifier(struct notifier_block *nb); extern int netlink_unregister_notifier(struct notifier_block *nb); diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index c231e9a..ece2439 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -923,7 +923,7 @@ struct rtnetlink_link }; extern struct rtnetlink_link * rtnetlink_links[NPROTO]; -extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo); +extern int rtnetlink_send(struct sk_buff *skb, struct nethost *host, u32 pid, u32 group, int echo); extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics); extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data); diff --git a/include/linux/sched.h b/include/linux/sched.h index daed38c..0196362 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -372,6 +372,7 @@ struct signal_struct { pid_t pgrp; pid_t tty_old_pgrp; pid_t session; + /* boolean value for session group leader */ int leader; diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 67abfe8..b3a92fc 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -59,8 +59,7 @@ extern int addrconf_add_ifaddr(void __ extern int addrconf_del_ifaddr(void __user *arg); extern int addrconf_set_dstaddr(void __user *arg); -extern int ipv6_chk_addr(struct nethost *host, - struct in6_addr *addr, +extern int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int strict); extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, diff --git a/include/net/flow.h b/include/net/flow.h index 9a5c94b..f3bf1be 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -10,7 +10,9 @@ #include #include +struct nethost; struct flowi { + struct nethost *host; int oif; int iif; diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index e349724..5ec3823 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -58,8 +58,6 @@ struct inet6_ifaddr struct inet6_ifaddr *lst_next; /* next addr in addr_lst */ struct inet6_ifaddr *if_next; /* next addr in inet6_dev */ - struct nethost *host; /* Which host am I for? */ - #ifdef CONFIG_IPV6_PRIVACY struct inet6_ifaddr *tmp_next; /* next addr in tempaddr_lst */ struct inet6_ifaddr *ifpub; diff --git a/include/net/ip.h b/include/net/ip.h index e4563bb..eba0ee8 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -332,13 +332,15 @@ extern int ip_net_unreachable(struct sk_ */ extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, u32 daddr, struct rtable *rt, int is_frag); -extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb); +extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb, struct nethost *host); extern void ip_options_fragment(struct sk_buff *skb); -extern int ip_options_compile(struct ip_options *opt, struct sk_buff *skb); +extern int ip_options_compile(struct ip_options *opt, struct sk_buff *skb, struct nethost *host); extern int ip_options_get(struct ip_options **optp, - unsigned char *data, int optlen); + unsigned char *data, int optlen, + struct nethost *host); extern int ip_options_get_from_user(struct ip_options **optp, - unsigned char __user *data, int optlen); + unsigned char __user *data, int optlen, + struct nethost *host); extern void ip_options_undo(struct ip_options * opt); extern void ip_forward_options(struct sk_buff *skb); extern int ip_options_rcv_srr(struct sk_buff *skb); @@ -348,7 +350,7 @@ extern int ip_options_rcv_srr(struct sk_ */ extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb); -extern int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc); +extern int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc, struct nethost *host); extern int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen); extern int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)); diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index a66e9de..fecda49 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -168,16 +168,16 @@ extern int fib6_add(struct fib6_node * struct rt6_info *rt, struct nlmsghdr *nlh, void *rtattr, - struct netlink_skb_parms *req); + struct sk_buff *in_skb); extern int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *rtattr, - struct netlink_skb_parms *req); + struct sk_buff *in_skb); extern void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh, - struct netlink_skb_parms *req); + struct sk_buff *in_skb); extern void fib6_run_gc(unsigned long dummy); diff --git a/include/net/ip6_host.h b/include/net/ip6_host.h new file mode 100644 index 0000000..15b94f0 --- /dev/null +++ b/include/net/ip6_host.h @@ -0,0 +1,16 @@ +#ifndef _NET_IP6_HOST_H +#define _NET_IP6_HOST_H + +#include + +struct ip6_host +{ + struct nethost *host; +}; + +static inline struct ip_host *in6_host_get(struct nethost *host) +{ + return host->ip_host; +} + +#endif /* _NET_IP6_HOST_H */ diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 86cc097..248e920 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -39,18 +39,19 @@ extern void ip6_route_cleanup(void); extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg); -extern int ip6_route_add(struct in6_rtmsg *rtmsg, +extern int ip6_route_add(struct nethost *host, + struct in6_rtmsg *rtmsg, struct nlmsghdr *, void *rtattr, - struct netlink_skb_parms *req); + struct sk_buff *in_skb); extern int ip6_ins_rt(struct rt6_info *, struct nlmsghdr *, void *rtattr, - struct netlink_skb_parms *req); + struct sk_buff *in_skb); extern int ip6_del_rt(struct rt6_info *, struct nlmsghdr *, void *rtattr, - struct netlink_skb_parms *req); + struct sk_buff *in_skb); extern int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev, @@ -78,8 +79,8 @@ extern int ndisc_dst_gc(int *more); extern void fib6_force_start_gc(void); extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, - struct nethost *host, - const struct in6_addr *addr); + const struct in6_addr *addr, + int anycast); /* * support functions for ND @@ -142,11 +143,7 @@ static inline int ipv6_unicast_destinati static inline struct nethost *ipv6_host(struct sk_buff *skb) { - struct nethost *host = NULL; - if (ipv6_unicast_destination(skb)) { - host = loopback_host(skb->dst->dev); - } - return host; + return skb->dst->dev->host; } #endif #endif diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index e3d5a36..f525b63 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -19,6 +19,7 @@ #include #include #include +#include /* WARNING: The ordering of these elements must match ordering * of RTA_* rtnetlink attribute numbers. @@ -136,7 +137,7 @@ struct fib_result_nl { #endif /* CONFIG_IP_ROUTE_MULTIPATH */ -#define FIB_RES_PREFSRC(host, res) (fib_res_prefsrc(host, &res)) +#define FIB_RES_PREFSRC(res) ((res).fi->fib_prefsrc ? : __fib_res_prefsrc(&res)) #define FIB_RES_GW(res) (FIB_RES_NH(res).nh_gw) #define FIB_RES_DEV(res) (FIB_RES_NH(res).nh_dev) #define FIB_RES_OIF(res) (FIB_RES_NH(res).nh_oif) @@ -155,10 +156,10 @@ struct fib_table { int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res); int (*tb_insert)(struct fib_table *table, struct rtmsg *r, struct kern_rta *rta, struct nlmsghdr *n, - struct netlink_skb_parms *req); + struct sk_buff *in_skb); int (*tb_delete)(struct fib_table *table, struct rtmsg *r, struct kern_rta *rta, struct nlmsghdr *n, - struct netlink_skb_parms *req); + struct sk_buff *in_skb); int (*tb_dump)(struct fib_table *table, struct sk_buff *skb, struct netlink_callback *cb); int (*tb_flush)(struct fib_table *table); @@ -170,58 +171,55 @@ struct fib_table { #ifndef CONFIG_IP_MULTIPLE_TABLES -extern struct fib_table *ip_fib_local_table; -extern struct fib_table *ip_fib_main_table; - -static inline struct fib_table *fib_get_table(int id) +static inline struct fib_table *fib_get_table(struct ip_host *ihost, int id) { if (id != RT_TABLE_LOCAL) - return ip_fib_main_table; - return ip_fib_local_table; + return ihost->ip_fib_main_table; + return ihost->ip_fib_local_table; } -static inline struct fib_table *fib_new_table(int id) +static inline struct fib_table *fib_new_table(struct ip_host *ihost, int id) { - return fib_get_table(id); + return fib_get_table(ihost, id); } static inline int fib_lookup(const struct flowi *flp, struct fib_result *res) { - if (ip_fib_local_table->tb_lookup(ip_fib_local_table, flp, res) && - ip_fib_main_table->tb_lookup(ip_fib_main_table, flp, res)) + struct ip_host *ihost = in_host_get(flp->fl.host); + if (ihost->ip_fib_local_table->tb_lookup(ip_fib_local_table, flp, res) && + ihost->ip_fib_main_table->tb_lookup(ip_fib_main_table, flp, res)) return -ENETUNREACH; return 0; } static inline void fib_select_default(const struct flowi *flp, struct fib_result *res) { + struct ip_host *ihost = in_host_get(flp->fl.host); + struct fib_table *main_table = ihost->ip_fib_table_main_table; if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) - ip_fib_main_table->tb_select_default(ip_fib_main_table, flp, res); + main_table->tb_select_default(main_table, flp, res); } #else /* CONFIG_IP_MULTIPLE_TABLES */ -#define ip_fib_local_table (fib_tables[RT_TABLE_LOCAL]) -#define ip_fib_main_table (fib_tables[RT_TABLE_MAIN]) -extern struct fib_table * fib_tables[RT_TABLE_MAX+1]; extern int fib_lookup(const struct flowi *flp, struct fib_result *res); -extern struct fib_table *__fib_new_table(int id); +extern struct fib_table *__fib_new_table(struct ip_host *ihost, int id); extern void fib_rule_put(struct fib_rule *r); -static inline struct fib_table *fib_get_table(int id) +static inline struct fib_table *fib_get_table(struct ip_host *ihost, int id) { if (id == 0) id = RT_TABLE_MAIN; - return fib_tables[id]; + return ihost->fib_tables[id]; } -static inline struct fib_table *fib_new_table(int id) +static inline struct fib_table *fib_new_table(struct ip_host *ihost, int id) { if (id == 0) id = RT_TABLE_MAIN; - return fib_tables[id] ? : __fib_new_table(id); + return ihost->fib_tables[id] ? : __fib_new_table(ihost, id); } extern void fib_select_default(const struct flowi *flp, struct fib_result *res); @@ -242,9 +240,10 @@ extern void fib_select_multipath(const s extern int ip_fib_check_default(u32 gw, struct net_device *dev); extern int fib_sync_down(u32 local, struct net_device *dev, int force); extern int fib_sync_up(struct net_device *dev); -extern int fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, +extern int fib_convert_rtentry(struct nethost *host, + int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, struct kern_rta *rta, struct rtentry *r); -extern u32 fib_res_prefsrc(struct nethost *host, struct fib_result *res); +extern u32 __fib_res_prefsrc(struct fib_result *res); /* Exported by fib_hash.c */ extern struct fib_table *fib_hash_init(int id); diff --git a/include/net/ip_host.h b/include/net/ip_host.h new file mode 100644 index 0000000..4b3c2ce --- /dev/null +++ b/include/net/ip_host.h @@ -0,0 +1,29 @@ +#ifndef _NET_IP_HOST_H +#define _NET_IP_HOST_H + +#include + +struct fib_table; + +struct ip_host +{ + struct nethost *host; +#ifndef CONFIG_IP_MULTIPLE_TABLES + struct fib_table *ip_fib_local_table; + struct fib_table *ip_fib_main_table; +#else + struct fib_table *fib_tables[RT_TABLE_MAX+1]; +#define ip_fib_local_table fib_tables[RT_TABLE_LOCAL] +#define ip_fib_main_table fib_tables[RT_TABLE_MAIN] +#endif /* CONFIG_IP_MULTIPLE_TABLES */ +}; + +static inline struct ip_host *in_host_get(struct nethost *host) +{ + return host->ip_host; +} + +extern int inet_host_init(struct nethost *host); +extern void inet_host_fini(struct nethost *host); + +#endif /* _NET_IP_HOST_H */ diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 34c0773..6c52b81 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -258,6 +258,7 @@ extern void __neigh_for_each_release(str extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *)); struct neigh_seq_state { + struct nethost *host; struct neigh_table *tbl; void *(*neigh_sub_iter)(struct neigh_seq_state *state, struct neighbour *n, loff_t *pos); diff --git a/include/net/protocol.h b/include/net/protocol.h index 889b561..0aac2c3 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -35,9 +35,9 @@ /* This is used to register protocols. */ struct net_protocol { - int (*handler)(struct sk_buff *skb); - void (*err_handler)(struct sk_buff *skb, struct nethost *host, u32 info); - int no_policy; + int (*handler)(struct sk_buff *skb); + void (*err_handler)(struct sk_buff *skb, u32 info); + int no_policy; }; #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) diff --git a/include/net/route.h b/include/net/route.h index e826eae..871b683 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -121,10 +121,10 @@ extern int ip_route_input(struct sk_buf extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu); extern void ip_rt_send_redirect(struct sk_buff *skb); -extern unsigned inet_addr_type(u32 addr); +extern unsigned inet_addr_type(struct nethost *host, u32 addr); extern void ip_rt_multicast_event(struct in_device *); extern int ip_rt_ioctl(unsigned int cmd, void __user *arg); -extern void ip_rt_get_source(struct nethost *host, u8 *src, struct rtable *rt); +extern void ip_rt_get_source(u8 *src, struct rtable *rt); extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb); static inline void ip_rt_put(struct rtable * rt) @@ -146,8 +146,8 @@ static inline int ip_route_connect(struc u32 src, u32 tos, int oif, u8 protocol, u16 sport, u16 dport, struct sock *sk) { - struct flowi fl = { .oif = oif, - .iif = sk->sk_host->loopback_dev.ifindex, + struct flowi fl = { .host = sk->sk_host, + .oif = oif, .nl_u = { .ip4_u = { .daddr = dst, .saddr = src, .tos = tos } }, @@ -197,20 +197,6 @@ static inline struct inet_peer *rt_get_p return rt->peer; } -static inline int rt_output(struct rtable *rt) -{ - return (rt->rt_flags & RTCF_OUTPUT); -} - -static inline struct nethost *rt_dhost(struct rtable *rt) -{ - struct net_device *dev = rt->u.dst.dev; - struct nethost *host = NULL; - if (!(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) - host = loopback_host(dev); - return host; -} - extern ctl_table ipv4_route_table[]; #endif /* _ROUTE_H */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 99d2609..8fe81b1 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -302,7 +302,7 @@ DECLARE_SNMP_STAT(struct tcp_mib, tcp_st #define TCP_ADD_STATS_BH(field, val) SNMP_ADD_STATS_BH(tcp_statistics, field, val) #define TCP_ADD_STATS_USER(field, val) SNMP_ADD_STATS_USER(tcp_statistics, field, val) -extern void tcp_v4_err(struct sk_buff *skb, struct nethost *host, u32); +extern void tcp_v4_err(struct sk_buff *skb, u32); extern void tcp_shutdown (struct sock *sk, int how); diff --git a/include/net/udp.h b/include/net/udp.h index cd961f8..fe3f11a 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -63,7 +63,7 @@ static inline int udp_lport_inuse(u16 nu extern struct proto udp_prot; -extern void udp_err(struct sk_buff *, struct nethost *host, u32); +extern void udp_err(struct sk_buff *, u32); extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 5beae1c..2b32426 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -92,6 +92,7 @@ struct xfrm_state atomic_t refcnt; spinlock_t lock; + struct nethost *host; struct xfrm_id id; struct xfrm_selector sel; @@ -208,7 +209,7 @@ struct xfrm_state_afinfo { void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl, struct xfrm_tmpl *tmpl, xfrm_address_t *daddr, xfrm_address_t *saddr); - struct xfrm_state *(*state_lookup)(xfrm_address_t *daddr, u32 spi, u8 proto); + struct xfrm_state *(*state_lookup)(struct nethost *host, xfrm_address_t *daddr, u32 spi, u8 proto); struct xfrm_state *(*find_acq)(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create); @@ -293,6 +294,7 @@ struct xfrm_policy struct xfrm_lifetime_cfg lft; struct xfrm_lifetime_cur curlft; struct dst_entry *bundles; + struct nethost *host; __u16 family; __u8 action; __u8 flags; @@ -309,7 +311,7 @@ struct xfrm_mgr char *id; int (*notify)(struct xfrm_state *x, struct km_event *c); int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); - struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir); + struct xfrm_policy *(*compile_policy)(struct nethost *host, u16 family, int opt, u8 *data, int len, int *dir); int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); }; @@ -831,7 +833,7 @@ extern int xfrm_state_check_expire(struc extern void xfrm_state_insert(struct xfrm_state *x); extern int xfrm_state_add(struct xfrm_state *x); extern int xfrm_state_update(struct xfrm_state *x); -extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); +extern struct xfrm_state *xfrm_state_lookup(struct nethost *host, xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); extern int xfrm_state_delete(struct xfrm_state *x); extern void xfrm_state_flush(u8 proto); @@ -875,7 +877,7 @@ static inline int xfrm_dst_lookup(struct } #endif -struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); +struct xfrm_policy *xfrm_policy_alloc(struct nethost *host, gfp_t gfp); extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, diff --git a/kernel/fork.c b/kernel/fork.c index 5b83c07..8883c56 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -886,7 +886,7 @@ static task_t *copy_process(unsigned lon if ((clone_flags & CLONE_NSYSVIPC) && (clone_flags & (CLONE_SYSVSEM))) return ERR_PTR(-EINVAL); - + /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 04ca442..66a296a 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #define BUFFER_SIZE 1024 /* buffer for the hotplug env */ @@ -94,7 +95,7 @@ static int send_uevent(const char *signa } NETLINK_CB(skb).dst_group = 1; - return netlink_broadcast(uevent_sock, skb, 0, 1, gfp_mask); + return netlink_broadcast(uevent_sock, skb, &init_host, 0, 1, gfp_mask); } static int do_kobject_uevent(struct kobject *kobj, enum kobject_action action, diff --git a/net/802/tr.c b/net/802/tr.c index 1eaa3d1..6d6b7cc 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -530,7 +530,7 @@ static int rif_seq_show(struct seq_file seq_puts(seq, "if TR address TTL rcf routing segments\n"); else { - struct net_device *dev = dev_get_by_index(entry->iface); + struct net_device *dev = dev_get_by_index(current->host, entry->iface); long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout) - (long) jiffies; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 91e412b..1fbf066 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -281,7 +281,7 @@ static int unregister_vlan_device(const int ret; - dev = dev_get_by_name(vlan_IF_name); + dev = dev_get_by_name(current->host, vlan_IF_name); ret = -EINVAL; if (dev) { if (dev->priv_flags & IFF_802_1Q_VLAN) { @@ -364,7 +364,7 @@ static struct net_device *register_vlan_ goto out_ret_null; /* find the device relating to eth_IF_name. */ - real_dev = dev_get_by_name(eth_IF_name); + real_dev = dev_get_by_name(current->host, eth_IF_name); if (!real_dev) goto out_ret_null; diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index b748648..5d57842 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -532,7 +532,8 @@ int vlan_dev_change_mtu(struct net_devic int vlan_dev_set_ingress_priority(char *dev_name, __u32 skb_prio, short vlan_prio) { - struct net_device *dev = dev_get_by_name(dev_name); + /* I'm in an ioctl */ + struct net_device *dev = dev_get_by_name(current->host, dev_name); if (dev) { if (dev->priv_flags & IFF_802_1Q_VLAN) { @@ -549,7 +550,8 @@ int vlan_dev_set_ingress_priority(char * int vlan_dev_set_egress_priority(char *dev_name, __u32 skb_prio, short vlan_prio) { - struct net_device *dev = dev_get_by_name(dev_name); + /* I'm in an ioctl */ + struct net_device *dev = dev_get_by_name(current->host, dev_name); struct vlan_priority_tci_mapping *mp = NULL; struct vlan_priority_tci_mapping *np; @@ -589,7 +591,8 @@ int vlan_dev_set_egress_priority(char *d /* Flags are defined in the vlan_dev_info class in include/linux/if_vlan.h file. */ int vlan_dev_set_vlan_flag(char *dev_name, __u32 flag, short flag_val) { - struct net_device *dev = dev_get_by_name(dev_name); + /* I'm in an ioctl */ + struct net_device *dev = dev_get_by_name(current->host, dev_name); if (dev) { if (dev->priv_flags & IFF_802_1Q_VLAN) { @@ -625,7 +628,8 @@ int vlan_dev_set_vlan_flag(char *dev_nam int vlan_dev_get_realdev_name(const char *dev_name, char* result) { - struct net_device *dev = dev_get_by_name(dev_name); + /* I'm in an ioctl */ + struct net_device *dev = dev_get_by_name(current->host, dev_name); int rv = 0; if (dev) { if (dev->priv_flags & IFF_802_1Q_VLAN) { @@ -643,7 +647,8 @@ int vlan_dev_get_realdev_name(const char int vlan_dev_get_vid(const char *dev_name, unsigned short* result) { - struct net_device *dev = dev_get_by_name(dev_name); + /* I'm in an ioctl */ + struct net_device *dev = dev_get_by_name(current->host, dev_name); int rv = 0; if (dev) { if (dev->priv_flags & IFF_802_1Q_VLAN) { diff --git a/net/atm/clip.c b/net/atm/clip.c index 87263d5..6386118 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -306,7 +306,7 @@ static int clip_constructor(struct neigh struct neigh_parms *parms; DPRINTK("clip_constructor (neigh %p, entry %p)\n",neigh,entry); - neigh->type = inet_addr_type(entry->ip); + neigh->type = inet_addr_type(dev->host, entry->ip); if (neigh->type != RTN_UNICAST) return -EINVAL; rcu_read_lock(); @@ -961,6 +961,7 @@ static int arp_seq_open(struct inode *in } memset(state, 0, sizeof(*state)); state->ns.neigh_sub_iter = clip_seq_sub_iter; + state->ns.host = current->host; rc = seq_open(file, &arp_seq_ops); if (rc) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 91bb895..fcce762 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -274,7 +274,7 @@ int br_del_bridge(const char *name) int ret = 0; rtnl_lock(); - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(current->host, name); if (dev == NULL) ret = -ENXIO; /* Could not find device */ diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index b8ce14b..6bab636 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -86,7 +86,7 @@ static int add_del_if(struct net_bridge if (!capable(CAP_NET_ADMIN)) return -EPERM; - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(current->host, ifindex); if (dev == NULL) return -EINVAL; diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 15790db..c22fbc3 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -209,7 +209,7 @@ static int br_nf_pre_routing_finish(stru if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev)) { struct rtable *rt; - struct flowi fl = { .iff = 0, .nl_u = + struct flowi fl = { .host = dev->host, .nl_u = { .ip4_u = { .daddr = iph->daddr, .saddr = 0 , .tos = RT_TOS(iph->tos)} }, .proto = 0}; diff --git a/net/core/dev.c b/net/core/dev.c index a44eeef..972a6a1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -109,6 +109,7 @@ #include #include #include +#include #ifdef CONFIG_NET_RADIO #include /* Note : will define WIRELESS_EXT */ #include @@ -204,10 +205,12 @@ DEFINE_PER_CPU(struct softnet_data, soft extern int netdev_sysfs_init(void); extern int netdev_register_sysfs(struct net_device *); extern void netdev_unregister_sysfs(struct net_device *); +extern void netdev_move_sysfs(struct net_device *); #else #define netdev_sysfs_init() (0) #define netdev_register_sysfs(dev) (0) #define netdev_unregister_sysfs(dev) do { } while(0) +#define netdev_move_sysfs(dev) do { } while(0) #endif @@ -409,7 +412,7 @@ unsigned long netdev_boot_base(const cha * If device already registered then return base of 1 * to indicate not to probe for this interface */ - if (__dev_get_by_name(name)) + if (__dev_get_by_name(&init_host, name)) return 1; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) @@ -464,13 +467,15 @@ __setup("netdev=", netdev_boot_setup); * careful with locks. */ -struct net_device *__dev_get_by_name(const char *name) +struct net_device *__dev_get_by_name(struct nethost *host, const char *name) { struct hlist_node *p; hlist_for_each(p, dev_name_hash(name)) { struct net_device *dev = hlist_entry(p, struct net_device, name_hlist); + if (dev->host != host) + continue; if (!strncmp(dev->name, name, IFNAMSIZ)) return dev; } @@ -488,12 +493,12 @@ struct net_device *__dev_get_by_name(con * matching device is found. */ -struct net_device *dev_get_by_name(const char *name) +struct net_device *dev_get_by_name(struct nethost *host, const char *name) { struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(host, name); if (dev) dev_hold(dev); read_unlock(&dev_base_lock); @@ -501,7 +506,7 @@ struct net_device *dev_get_by_name(const } /** - * __dev_get_by_index - find a device by its ifindex + * ___dev_get_by_index - find a device by its ifindex * @ifindex: index of device * * Search for an interface by index. Returns %NULL if the device @@ -511,7 +516,7 @@ struct net_device *dev_get_by_name(const * or @dev_base_lock. */ -struct net_device *__dev_get_by_index(int ifindex) +static struct net_device *___dev_get_by_index(int ifindex) { struct hlist_node *p; @@ -524,6 +529,27 @@ struct net_device *__dev_get_by_index(in return NULL; } +/** + * __dev_get_by_index - find a device by its ifindex + * @host: nethost of device + * @ifindex: index of device + * + * Search for an interface by index. Returns %NULL if the device + * with the specified index and host is not found or a pointer to + * the device. The device has not had its reference counter + * increased so the caller must be careful about locking. The + * caller must hold either the RTNL semaphore or @dev_base_lock. + */ + +struct net_device *__dev_get_by_index(struct nethost *host, int ifindex) +{ + struct net_device *dev; + dev = ___dev_get_by_index(ifindex); + if (dev && (dev->host != host)) + dev = NULL; + return dev; +} + /** * dev_get_by_index - find a device by its ifindex @@ -535,12 +561,12 @@ struct net_device *__dev_get_by_index(in * dev_put to indicate they have finished with it. */ -struct net_device *dev_get_by_index(int ifindex) +struct net_device *dev_get_by_index(struct nethost *host, int ifindex) { struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_index(ifindex); + dev = __dev_get_by_index(host, ifindex); if (dev) dev_hold(dev); read_unlock(&dev_base_lock); @@ -561,14 +587,15 @@ struct net_device *dev_get_by_index(int * If the API was consistent this would be __dev_get_by_hwaddr */ -struct net_device *dev_getbyhwaddr(unsigned short type, char *ha) +struct net_device *dev_getbyhwaddr(struct nethost *host, unsigned short type, char *ha) { struct net_device *dev; ASSERT_RTNL(); for (dev = dev_base; dev; dev = dev->next) - if (dev->type == type && + if (dev->host == host && + dev->type == type && !memcmp(dev->dev_addr, ha, dev->addr_len)) break; return dev; @@ -576,12 +603,14 @@ struct net_device *dev_getbyhwaddr(unsig EXPORT_SYMBOL(dev_getbyhwaddr); -struct net_device *dev_getfirstbyhwtype(unsigned short type) +struct net_device *dev_getfirstbyhwtype(struct nethost *host, unsigned short type) { struct net_device *dev; rtnl_lock(); for (dev = dev_base; dev; dev = dev->next) { + if (dev->host != host) + continue; if (dev->type == type) { dev_hold(dev); break; @@ -604,12 +633,15 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype); * dev_put to indicate they have finished with it. */ -struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask) +struct net_device * dev_get_by_flags(struct nethost *host, + unsigned short if_flags, unsigned short mask) { struct net_device *dev; read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { + if (dev->host != host) + continue; if (((dev->flags ^ if_flags) & mask) == 0) { dev_hold(dev); break; @@ -671,6 +703,8 @@ int dev_alloc_name(struct net_device *de return -ENOMEM; for (d = dev_base; d; d = d->next) { + if (d->host != dev->host) + continue; if (!sscanf(d->name, name, &i)) continue; if (i < 0 || i >= max_netdevices) @@ -687,7 +721,7 @@ int dev_alloc_name(struct net_device *de } snprintf(buf, sizeof(buf), name, i); - if (!__dev_get_by_name(buf)) { + if (!__dev_get_by_name(dev->host, buf)) { strlcpy(dev->name, buf, IFNAMSIZ); return i; } @@ -726,7 +760,7 @@ int dev_change_name(struct net_device *d return err; strcpy(newname, dev->name); } - else if (__dev_get_by_name(newname)) + else if (__dev_get_by_name(dev->host, newname)) return -EEXIST; else strlcpy(dev->name, newname, IFNAMSIZ); @@ -783,7 +817,7 @@ void dev_load(const char *name) struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_name(name); + dev = __dev_get_by_name(current->host, name); read_unlock(&dev_base_lock); if (!dev && capable(CAP_SYS_MODULE)) @@ -1792,7 +1826,7 @@ static int dev_ifname(struct ifreq __use return -EFAULT; read_lock(&dev_base_lock); - dev = __dev_get_by_index(ifr.ifr_ifindex); + dev = __dev_get_by_index(current->host, ifr.ifr_ifindex); if (!dev) { read_unlock(&dev_base_lock); return -ENODEV; @@ -1820,6 +1854,7 @@ static int dev_ifconf(char __user *arg) int len; int total; int i; + struct nethost *host = current->host; /* * Fetch the caller's info block. @@ -1837,6 +1872,8 @@ static int dev_ifconf(char __user *arg) total = 0; for (dev = dev_base; dev; dev = dev->next) { + if (dev->host != host) + continue; for (i = 0; i < NPROTO; i++) { if (gifconf_list[i]) { int done; @@ -1868,12 +1905,20 @@ static int dev_ifconf(char __user *arg) * This is invoked by the /proc filesystem handler to display a device * in detail. */ -static __inline__ struct net_device *dev_get_idx(loff_t pos) +static __inline__ struct net_device *dev_get_idx(struct seq_file *seq, loff_t pos) { + struct nethost *host = seq->private; struct net_device *dev; loff_t i; - for (i = 0, dev = dev_base; dev && i < pos; ++i, dev = dev->next); + dev = dev_base; + while (dev && (dev->host != host)) + dev = dev->next; + for (i = 0; dev && i < pos; i++) { + do { + dev = dev->next; + } while (dev && (dev->host != host)); + } return i == pos ? dev : NULL; } @@ -1881,13 +1926,18 @@ static __inline__ struct net_device *dev void *dev_seq_start(struct seq_file *seq, loff_t *pos) { read_lock(&dev_base_lock); - return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN; + return *pos ? dev_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; } void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { + struct nethost *host = seq->private; + struct net_device *dev; ++*pos; - return v == SEQ_START_TOKEN ? dev_base : ((struct net_device *)v)->next; + dev = (v == SEQ_START_TOKEN)? dev_base : ((struct net_device *)v)->next; + while (dev && dev->host != host) + dev = dev->next; + return dev; } void dev_seq_stop(struct seq_file *seq, void *v) @@ -1986,7 +2036,14 @@ static struct seq_operations dev_seq_ops static int dev_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &dev_seq_ops); + struct seq_file *seq; + int rc; + rc = seq_open(file, &dev_seq_ops); + if (rc == 0) { + seq = file->private_data; + seq->private = current->host; + } + return rc; } static struct file_operations dev_seq_fops = { @@ -2260,7 +2317,7 @@ int dev_set_mac_address(struct net_devic static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) { int err; - struct net_device *dev = __dev_get_by_name(ifr->ifr_name); + struct net_device *dev = __dev_get_by_name(current->host, ifr->ifr_name); if (!dev) return -ENODEV; @@ -2610,7 +2667,7 @@ static int dev_new_index(void) for (;;) { if (++ifindex <= 0) ifindex = 1; - if (!__dev_get_by_index(ifindex)) + if (!___dev_get_by_index(ifindex)) return ifindex; } } @@ -2656,6 +2713,7 @@ int register_netdevice(struct net_device /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); + BUG_ON(!dev->host); spin_lock_init(&dev->queue_lock); spin_lock_init(&dev->xmit_lock); @@ -2694,6 +2752,8 @@ int register_netdevice(struct net_device hlist_for_each(p, head) { struct net_device *d = hlist_entry(p, struct net_device, name_hlist); + if (d->host != dev->host) + continue; if (!strncmp(d->name, dev->name, IFNAMSIZ)) { ret = -EEXIST; goto out_err; @@ -2974,6 +3034,7 @@ struct net_device *alloc_netdev(int size dev = (struct net_device *) (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); dev->padded = (char *)dev - (char *)p; + dev->host = current->host; if (sizeof_priv) dev->priv = netdev_priv(dev); @@ -3125,6 +3186,83 @@ void unregister_netdev(struct net_device EXPORT_SYMBOL(unregister_netdev); +/** + * dev_change_nethost - move device to different nethost namespace + * @dev: device + * @host: nethost namespace + * + * This function shuts down a device interface and moves it + * to a new nethost namespace. On success 0 is returned, on + * a failure a netagive errno code is returned. + * + * Callers must hold the rtnl semaphore. + */ + +int dev_change_nethost(struct net_device *dev, struct nethost *host) +{ + int err; + + ASSERT_RTNL(); + + /* Don't allow the loopback interface to be moved. */ + err = -EINVAL; + if (dev->flags & IFF_LOOPBACK) + goto out; + + /* Ensure the device has been registrered */ + err = -EINVAL; + if (dev->reg_state != NETREG_REGISTERED) + goto out; + + /* Get out if there is nothing todo */ + err = 0; + if (host == dev->host) + goto out; + + /* Check for existence of name in the other host */ + err = -EEXIST; + if (__dev_get_by_name(host, dev->name)) + goto out; + + /* + * And now a mini version of register_netdevice unregister_netdevice. + */ + + /* If device is running clost it first. */ + if (dev->flags & IFF_UP) + dev_close(dev); + + synchronize_net(); + + /* Shutdown queueing discipline. */ + dev_shutdown(dev); + + /* Notify protocols, that we are about to destroy + this device. They should clean all the things. + */ + notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); + + /* + * Flush the multicast chain + */ + dev_mc_discard(dev); + + + /* Actually switch the host */ + dev->host = host; + + /* Fixup sysfs */ + netdev_move_sysfs(dev); + + /* Notify protocols, that a new device appeared. */ + notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); + + synchronize_net(); + err = 0; + out: + return err; +} + #ifdef CONFIG_HOTPLUG_CPU static int dev_cpu_callback(struct notifier_block *nfb, unsigned long action, @@ -3194,8 +3332,10 @@ static int __init net_dev_init(void) if (dev_proc_init()) goto out; +#if 0 if (netdev_sysfs_init()) goto out; +#endif INIT_LIST_HEAD(&ptype_all); for (i = 0; i < 16; i++) @@ -3229,6 +3369,11 @@ static int __init net_dev_init(void) open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL); open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL); +#if 1 + rc = nethost_init(); + if (rc) + goto out; +#endif hotcpu_notifier(dev_cpu_callback, 0); dst_init(); dev_mcast_init(); diff --git a/net/core/dst.c b/net/core/dst.c index 5a8e753..eccfd3f 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -242,13 +242,14 @@ static inline void dst_ifdown(struct dst dst->input = dst_discard_in; dst->output = dst_discard_out; } else { - dst->dev = &init_host.loopback_dev; - dev_hold(&init_host.loopback_dev); + struct net_device *lo = &dev->host->loopback_dev; + dst->dev = lo; + dev_hold(lo); dev_put(dev); if (dst->neighbour && dst->neighbour->dev == dev) { - dst->neighbour->dev = &init_host.loopback_dev; + dst->neighbour->dev = lo; dev_put(dev); - dev_hold(&init_host.loopback_dev); + dev_hold(lo); } } } diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 404b761..5fbc04a 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -732,7 +732,7 @@ static int ethtool_get_perm_addr(struct int dev_ethtool(struct ifreq *ifr) { - struct net_device *dev = __dev_get_by_name(ifr->ifr_name); + struct net_device *dev = __dev_get_by_name(current->host, ifr->ifr_name); void __user *useraddr = ifr->ifr_data; u32 ethcmd; int rc; diff --git a/net/core/host.c b/net/core/host.c index 72e3ceb..2fc77e6 100644 --- a/net/core/host.c +++ b/net/core/host.c @@ -1,14 +1,71 @@ +#include #include +#include +#include #include #include #include #include +#include #include +#if 1 +extern int netdev_sysfs_init(struct nethost *host); +extern void netdev_sysfs_fini(struct nethost *host); +#endif + static void do_put_host(void *arg) { struct nethost *host = arg; - unregister_netdev(&host->loopback_dev); + struct net_device *lo, *dev; + + /* Remember my host's loopback device */ + lo = &host->loopback_dev; + + /* Push all of the other devices back to init_host */ + rtnl_lock(); + for (dev = dev_base; dev; dev = dev->next) { + int err, i; + if (dev->host != host) + continue; + if (dev == lo) + continue; +#if 1 + /* Bring down the network device */ + dev_close(dev); +#endif + /* Push remaining network devices to init_host */ + err = dev_change_nethost(dev, &init_host); +#if 1 + /* If a simple push failed attempt to rename and push the device */ + for(i = 0; (err == -EEXIST) && (i < 100); i++) { + char new_name[sizeof(dev->name)]; + snprintf(new_name, sizeof(new_name), "dev%d", i); + if (dev_change_name(dev, new_name) == 0) { + err = dev_change_nethost(dev, &init_host); + } + } +#endif + if (err) { + printk(KERN_WARNING "%s: failed to move %s to init_host: %d\n", + __func__, dev->name, err); + unregister_netdevice(dev); + } + } + + /* Unregister my hosts loopback device */ + unregister_netdevice(lo); + rtnl_unlock(); + + /* Cleanup any remaning protocol state */ + rtnl_lock(); + sock_host_fini(host); + rtnl_unlock(); + + /* Now free the sysfs class */ + netdev_sysfs_fini(host); + + /* Now it is safe to free my host */ kfree(host); } @@ -19,34 +76,67 @@ void __put_host(struct nethost *host) schedule_work(&host->work); } +static int nethost_setup(struct nethost *host) +{ + struct net_device *lo; + int err; + + err = netdev_sysfs_init(host); + if (err) + return err; + + rtnl_lock(); + + lo = &host->loopback_dev; + lo->host = host; + err = loopback_setup(lo); + if (err) + goto out; + + err = sock_host_init(host); + if (err) + goto out_undo; + + err = 0; +out: + rtnl_unlock(); + return err; + +out_undo: + sock_host_fini(host); + unregister_netdevice(lo); + goto out; + +} + int __copy_host(int flags, struct task_struct *p) { - struct net_device *dev; struct nethost *host; int err; + + err = -EINVAL; + if (!thread_group_leader(p)) + goto out; + err = -ENOMEM; host = kzalloc(sizeof(*host), GFP_KERNEL); if (!host) goto out; atomic_set(&host->count, 1); + /* Initialize utsname with the current contents */ down_read(&uts_sem); memcpy(&host->utsname, &p->host->utsname, sizeof(host->utsname)); up_read(&uts_sem); + /* Revert nodename and domainname their default values */ + strncpy(host->utsname.nodename, UTS_NODENAME, sizeof(host->utsname.nodename)); + strncpy(host->utsname.domainname, UTS_DOMAINNAME, sizeof(host->utsname.domainname)); - dev = &host->loopback_dev; - dev->init = loopback_init; - err = register_netdev(dev); + err = nethost_setup(host); if (err) goto out_free_host; - rtnl_shlock(); - if (dev_change_flags(dev, dev->flags | IFF_UP) < 0) - printk(KERN_WARNING "clone: Failed to bring up %s\n", dev->name); - rtnl_shunlock(); - p->host = host; - err = 0; out: return err; @@ -57,6 +147,5 @@ out_free_host: __init int nethost_init(void) { - init_host.loopback_dev.init = loopback_init; - return register_netdev(&init_host.loopback_dev); + return nethost_setup(&init_host); } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 4128fc7..d41c3ee 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1438,10 +1438,11 @@ int neigh_delete(struct sk_buff *skb, st struct rtattr **nda = arg; struct neigh_table *tbl; struct net_device *dev = NULL; + struct nethost *host = skb->sk->sk_host; int err = -ENODEV; if (ndm->ndm_ifindex && - (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) + (dev = dev_get_by_index(host, ndm->ndm_ifindex)) == NULL) goto out; read_lock(&neigh_tbl_lock); @@ -1489,10 +1490,11 @@ int neigh_add(struct sk_buff *skb, struc struct rtattr **nda = arg; struct neigh_table *tbl; struct net_device *dev = NULL; + struct nethost *host = skb->sk->sk_host; int err = -ENODEV; if (ndm->ndm_ifindex && - (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) + (dev = dev_get_by_index(host, ndm->ndm_ifindex)) == NULL) goto out; read_lock(&neigh_tbl_lock); @@ -1929,8 +1931,12 @@ static int neigh_dump_table(struct neigh if (h > s_h) s_idx = 0; read_lock_bh(&tbl->lock); - for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) { - if (idx < s_idx) + for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) { + int lidx; + if (n->dev->host != skb->sk->sk_host) + continue; + lidx = idx++; + if (lidx < s_idx) continue; if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, @@ -2031,6 +2037,9 @@ static struct neighbour *neigh_get_first n = tbl->hash_buckets[bucket]; while (n) { + if (n->dev->host != state->host) + goto next; + if (state->neigh_sub_iter) { loff_t fakep = 0; void *v; @@ -2071,6 +2080,9 @@ static struct neighbour *neigh_get_next( while (1) { while (n) { + if (n->dev->host != state->host) + goto next; + if (state->neigh_sub_iter) { void *v = state->neigh_sub_iter(state, n, pos); if (v) @@ -2124,6 +2136,8 @@ static struct pneigh_entry *pneigh_get_f state->flags |= NEIGH_SEQ_IS_PNEIGH; for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { pn = tbl->phash_buckets[bucket]; + while(pn && (pn->dev->host != state->host)) + pn = pn->next; if (pn) break; } @@ -2144,6 +2158,8 @@ static struct pneigh_entry *pneigh_get_n if (++state->bucket > PNEIGH_HASHMASK) break; pn = tbl->phash_buckets[state->bucket]; + while(pn && (pn->dev->host != state->host)) + pn = pn->next; if (pn) break; } @@ -2351,7 +2367,7 @@ void neigh_app_ns(struct neighbour *n) nlh = (struct nlmsghdr *)skb->data; nlh->nlmsg_flags = NLM_F_REQUEST; NETLINK_CB(skb).dst_group = RTNLGRP_NEIGH; - netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC); + netlink_broadcast(rtnl, skb, n->dev->host, 0, RTNLGRP_NEIGH, GFP_ATOMIC); } static void neigh_app_notify(struct neighbour *n) @@ -2369,7 +2385,7 @@ static void neigh_app_notify(struct neig } nlh = (struct nlmsghdr *)skb->data; NETLINK_CB(skb).dst_group = RTNLGRP_NEIGH; - netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC); + netlink_broadcast(rtnl, skb, n->dev->host, 0, RTNLGRP_NEIGH, GFP_ATOMIC); } #endif /* CONFIG_ARPD */ diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index e2137f3..aaf0f48 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #define to_class_dev(obj) container_of(obj,struct class_device,kobj) #define to_net_dev(class) container_of(class, struct net_device, class_dev) @@ -27,7 +29,8 @@ static const char fmt_ulong[] = "%lu\n"; static inline int dev_isalive(const struct net_device *dev) { - return dev->reg_state == NETREG_REGISTERED; + return (dev->reg_state == NETREG_REGISTERED) && + (dev->host == current->host); } /* use same locking rules as GIF* ioctl's */ @@ -155,6 +158,30 @@ static ssize_t store_mtu(struct class_de static CLASS_DEVICE_ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu); +static ssize_t show_new_host_pid(struct class_device *cd, char *buf) +{ + return -EPERM; +} +static int change_new_host_pid(struct net_device *net, unsigned long new_host_pid) +{ + struct task_struct *tsk; + int err; + /* Find the hostid for this... */ + err = -ESRCH; + read_lock(&tasklist_lock); + tsk = find_task_by_pid(current->pspace, new_host_pid); + if (tsk) { + err = dev_change_nethost(net, tsk->host); + } + read_unlock(&tasklist_lock); + return err; +} +static ssize_t store_new_host_pid(struct class_device *dev, const char *buf, size_t len) +{ + return netdev_store(dev, buf, len, change_new_host_pid); +} +static CLASS_DEVICE_ATTR(new_host_pid, S_IWUSR, show_new_host_pid, store_new_host_pid); + NETDEVICE_SHOW(flags, fmt_hex); static int change_flags(struct net_device *net, unsigned long new_flags) @@ -215,6 +242,7 @@ static struct class_device_attribute *ne &class_device_attr_address, &class_device_attr_broadcast, &class_device_attr_carrier, + &class_device_attr_new_host_pid, NULL }; @@ -404,6 +432,7 @@ static void netdev_release(struct class_ kfree((char *)dev - dev->padded); } +#if 0 static struct class net_class = { .name = "net", .release = netdev_release, @@ -411,6 +440,7 @@ static struct class net_class = { .hotplug = netdev_hotplug, #endif }; +#endif void netdev_unregister_sysfs(struct net_device * net) { @@ -435,7 +465,7 @@ int netdev_register_sysfs(struct net_dev struct class_device_attribute *attr; int ret; - class_dev->class = &net_class; + class_dev->class = &(net->host->net_class); class_dev->class_data = net; strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE); @@ -473,7 +503,50 @@ out: return ret; } -int netdev_sysfs_init(void) +void netdev_move_sysfs(struct net_device *net) +{ + struct class_device *class_dev = &(net->class_dev); + struct class *parent; + struct kobject *kobj_parent; + + parent = class_dev->class; + kobj_parent = class_dev->kobj.parent; + + class_dev->class = &net->host->net_class; + class_get(class_dev->class); + class_dev->kobj.parent = &class_dev->class->subsys.kset.kobj; + kobject_get(class_dev->kobj.parent); + + class_put(parent); + kobject_put(kobj_parent); +} + +int netdev_sysfs_init(struct nethost *host) +{ + struct class *net_class = &(host->net_class); +#if 1 + /* FIXME there should be a better way of dealing with sysfs + * than this. + */ + static int instance; + if (instance++) { + char buf[20]; + snprintf(buf, sizeof(buf), "net%d", instance); + net_class->name = kstrdup(buf, GFP_KERNEL); + if (!net_class->name) + return -ENOMEM; + } else +#endif + net_class->name = "net"; + net_class->release = netdev_release; +#ifdef CONFIG_HOTPLUG + net_class->hotplug = netdev_hotplug; +#endif + return class_register(net_class); +} + +void netdev_sysfs_fini(struct nethost *host) { - return class_register(&net_class); + struct class *net_class = &(host->net_class); + return class_unregister(net_class); } diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 802fe11..db150d1 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -630,7 +630,7 @@ int netpoll_setup(struct netpoll *np) unsigned long flags; if (np->dev_name) - ndev = dev_get_by_name(np->dev_name); + ndev = dev_get_by_name(&init_host, np->dev_name); if (!ndev) { printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", np->name, np->dev_name); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index d772360..9a9b6d4 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -144,14 +144,14 @@ size_t rtattr_strlcpy(char *dest, const return ret; } -int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) +int rtnetlink_send(struct sk_buff *skb, struct nethost *host, u32 pid, unsigned group, int echo) { int err = 0; NETLINK_CB(skb).dst_group = group; if (echo) atomic_inc(&skb->users); - netlink_broadcast(rtnl, skb, pid, group, GFP_KERNEL); + netlink_broadcast(rtnl, skb, host, pid, group, GFP_KERNEL); if (echo) err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); return err; @@ -271,11 +271,14 @@ static int rtnetlink_dump_ifinfo(struct { int idx; int s_idx = cb->args[0]; + struct nethost *host = skb->sk->sk_host; struct net_device *dev; read_lock(&dev_base_lock); - for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { - if (idx < s_idx) + for (dev=dev_base, idx=0; dev; dev = dev->next) { + if (dev->host != host) + continue; + if (idx++ < s_idx) continue; if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, @@ -295,16 +298,17 @@ static int do_setlink(struct sk_buff *sk struct rtattr **ida = arg; struct net_device *dev; int err, send_addr_notify = 0; + struct nethost *host = skb->sk->sk_host; if (ifm->ifi_index >= 0) - dev = dev_get_by_index(ifm->ifi_index); + dev = dev_get_by_index(host, ifm->ifi_index); else if (ida[IFLA_IFNAME - 1]) { char ifname[IFNAMSIZ]; if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1], IFNAMSIZ) >= IFNAMSIZ) return -EINVAL; - dev = dev_get_by_name(ifname); + dev = dev_get_by_name(host, ifname); } else return -EINVAL; @@ -459,7 +463,7 @@ void rtmsg_ifinfo(int type, struct net_d return; } NETLINK_CB(skb).dst_group = RTNLGRP_LINK; - netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_KERNEL); + netlink_broadcast(rtnl, skb, dev->host, 0, RTNLGRP_LINK, GFP_KERNEL); } static int rtnetlink_done(struct netlink_callback *cb) diff --git a/net/core/sock.c b/net/core/sock.c index 1ded9c3..9fe5e4f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -417,7 +417,8 @@ set_rcvbuf: if (devname[0] == '\0') { sk->sk_bound_dev_if = 0; } else { - struct net_device *dev = dev_get_by_name(devname); + struct net_device *dev; + dev = dev_get_by_name(current->host, devname); if (!dev) { ret = -ENODEV; break; @@ -659,6 +660,8 @@ struct sock *sk_alloc(int family, gfp_t */ sk->sk_prot = sk->sk_prot_creator = prot; sock_lock_init(sk); + sk->sk_host = current->host; + get_host(sk->sk_host); } if (security_sk_alloc(sk, family, priority)) @@ -775,8 +778,7 @@ struct sock *sk_clone(const struct sock if (newsk->sk_prot->sockets_allocated) atomic_inc(newsk->sk_prot->sockets_allocated); - if (sk->sk_host) - get_host(sk->sk_host); + get_host(newsk->sk_host); } out: return newsk; diff --git a/net/core/wireless.c b/net/core/wireless.c index d17f158..ea0ba9d 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c @@ -1032,7 +1032,7 @@ int wireless_process_ioctl(struct ifreq * The copy_to/from_user() of ifr is also dealt with in there */ /* Make sure the device exist */ - if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) + if ((dev = __dev_get_by_name(current->host, ifr->ifr_name)) == NULL) return -ENODEV; /* A bunch of special cases, then the generic case... @@ -1155,7 +1155,7 @@ static inline void rtmsg_iwinfo(struct n return; } NETLINK_CB(skb).dst_group = RTNLGRP_LINK; - netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC); + netlink_broadcast(rtnl, skb, dev->host, 0, RTNLGRP_LINK, GFP_ATOMIC); } #endif /* WE_EVENT_NETLINK */ diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 1fcd5ab..3fad647 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -888,7 +888,7 @@ static struct dst_entry* dccp_v4_route_s struct sk_buff *skb) { struct rtable *rt; - struct flowi fl = { .iif = sk->skhost->loopback_dev.ifindex, + struct flowi fl = { .host = sk->skhost, .oif = ((struct rtable *)skb->dst)->rt_iif, .nl_u = { .ip4_u = { .daddr = skb->nh.iph->saddr, diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 8d0cc3c..fc615fe 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -589,6 +589,8 @@ static int dn_neigh_seq_open(struct inod goto out; memset(s, 0, sizeof(*s)); + s->host = current->host; + rc = seq_open(file, &dn_neigh_seq_ops); if (rc) goto out_kfree; diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 68a5ca8..19aa533 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -98,7 +98,7 @@ int eth_header(struct sk_buff *skb, stru * Anyway, the loopback-device should never use this function... */ - if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)) + if (dev->flags & (IFF_NOARP)) { memset(eth->h_dest, 0, dev->addr_len); return ETH_HLEN; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index e577a3f..af952b5 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -110,6 +110,7 @@ #include #include #include +#include #ifdef CONFIG_IP_MROUTE #include #endif @@ -217,6 +218,36 @@ out: } /* + * Initialize the per host ipv4 state. + */ +int inet_host_init(struct nethost *host) +{ + /* FIXME flesh me out */ + /* FIXME init_host_init calling race */ + if (!host->ip_host) { + struct ip_host *ihost; + ihost = kzalloc(sizeof(*ihost), GFP_KERNEL); + if (!ihost) + return -ENOMEM; + ihost->host = host; + host->ip_host = ihost; + } + return 0; +} + +/* + * Cleanup the per host ipv4 state. + */ + +void inet_host_fini(struct nethost *host) +{ + struct ip_host *ihost; + ihost = host->ip_host; + host->ip_host = NULL; + kfree(ihost); +} + +/* * Create an inet socket. */ @@ -303,8 +334,6 @@ lookup_protocol: goto out; err = 0; - sk->sk_host = current->host; - get_host(sk->sk_host); sk->sk_no_check = answer_no_check; if (INET_PROTOSW_REUSE & answer_flags) sk->sk_reuse = 1; @@ -418,7 +447,7 @@ int inet_bind(struct socket *sock, struc if (addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); + chk_addr_ret = inet_addr_type(sk->sk_host, addr->sin_addr.s_addr); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since @@ -436,14 +465,6 @@ int inet_bind(struct socket *sock, struc chk_addr_ret != RTN_BROADCAST) goto out; - /* Verify local addresses are for the current host */ - if (!sysctl_ip_nonlocal_bind && - !inet->freebind && - chk_addr_ret == RTN_LOCAL && - !inet_confirm_addr(sk->sk_host, NULL, 0, addr->sin_addr.s_addr, - RT_SCOPE_NOWHERE)) - goto out; - snum = ntohs(addr->sin_port); err = -EACCES; if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) @@ -870,10 +891,11 @@ static struct proto_ops inet_sockraw_ops }; static struct net_proto_family inet_family_ops = { - .family = PF_INET, - .create = inet_create, - .multi_host = 1, - .owner = THIS_MODULE, + .family = PF_INET, + .host_init = inet_host_init, + .host_fini = inet_host_fini, + .create = inet_create, + .owner = THIS_MODULE, }; /* Upon startup we insert all the elements in inetsw_array[] into @@ -1059,7 +1081,7 @@ int inet_sk_rebuild_header(struct sock * daddr = inet->opt->faddr; { struct flowi fl = { - .iif = sk->sk_host->loopback_dev.ifindex, + .host = sk->sk_host, .oif = sk->sk_bound_dev_if, .nl_u = { .ip4_u = { @@ -1168,6 +1190,12 @@ static int __init inet_init(void) goto out; } +#if 0 + rc = inet_host_init(current->host); + if (rc) + goto out; +#endif + rc = proto_register(&tcp_prot, 1); if (rc) goto out; diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 035ad2c..5bc5a3a 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -184,6 +184,7 @@ out: static void ah4_err(struct sk_buff *skb, u32 info) { + struct nethost *host = skb->dev->host; struct iphdr *iph = (struct iphdr*)skb->data; struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2)); struct xfrm_state *x; @@ -192,7 +193,7 @@ static void ah4_err(struct sk_buff *skb, skb->h.icmph->code != ICMP_FRAG_NEEDED) return; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); + x = xfrm_state_lookup(host, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); if (!x) return; printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n", diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index d4cbd03..4eab7c5 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -238,7 +238,7 @@ static int arp_constructor(struct neighb struct in_device *in_dev; struct neigh_parms *parms; - neigh->type = inet_addr_type(addr); + neigh->type = inet_addr_type(dev->host, addr); rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); @@ -342,14 +342,14 @@ static void arp_solicit(struct neighbour switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { default: case 0: /* By default announce any local IP */ - if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL) + if (skb && inet_addr_type(dev->host, skb->nh.iph->saddr) == RTN_LOCAL) saddr = skb->nh.iph->saddr; break; case 1: /* Restrict announcements of saddr in same subnet */ if (!skb) break; saddr = skb->nh.iph->saddr; - if (inet_addr_type(saddr) == RTN_LOCAL) { + if (inet_addr_type(dev->host, saddr) == RTN_LOCAL) { /* saddr should be known to target */ if (inet_addr_onlink(in_dev, target, saddr)) break; @@ -363,7 +363,7 @@ static void arp_solicit(struct neighbour if (in_dev) in_dev_put(in_dev); if (!saddr) - saddr = inet_select_addr(NULL, dev, target, RT_SCOPE_LINK); + saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); if ((probes -= neigh->parms->ucast_probes) < 0) { if (!(neigh->nud_state&NUD_VALID)) @@ -416,12 +416,12 @@ static int arp_ignore(struct in_device * default: return 0; } - return !inet_confirm_addr(NULL, dev, sip, tip, scope); + return !inet_confirm_addr(dev, sip, tip, scope); } static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev) { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .nl_u = { .ip4_u = { .daddr = sip, .saddr = tip } } }; struct rtable *rt; @@ -481,7 +481,7 @@ int arp_find(unsigned char *haddr, struc paddr = ((struct rtable*)skb->dst)->rt_gateway; - if (arp_set_predefined(inet_addr_type(paddr), haddr, paddr, dev)) + if (arp_set_predefined(inet_addr_type(dev->host, paddr), haddr, paddr, dev)) return 0; n = __neigh_lookup(&arp_tbl, &paddr, dev, 1); @@ -825,7 +825,7 @@ static int arp_process(struct sk_buff *s /* Special case: IPv4 duplicate address detection packet (RFC2131) */ if (sip == 0) { if (arp->ar_op == htons(ARPOP_REQUEST) && - inet_addr_type(tip) == RTN_LOCAL && + inet_addr_type(dev->host, tip) == RTN_LOCAL && !arp_ignore(in_dev,dev,sip,tip)) arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr); goto out; @@ -885,7 +885,7 @@ static int arp_process(struct sk_buff *s */ if (n == NULL && arp->ar_op == htons(ARPOP_REPLY) && - inet_addr_type(sip) == RTN_UNICAST) + inet_addr_type(dev->host, sip) == RTN_UNICAST) n = __neigh_lookup(&arp_tbl, &sip, dev, -1); #endif @@ -977,7 +977,7 @@ static int arp_req_set(struct arpreq *r, if (mask && mask != 0xFFFFFFFF) return -EINVAL; if (!dev && (r->arp_flags & ATF_COM)) { - dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data); + dev = dev_getbyhwaddr(current->host, r->arp_ha.sa_family, r->arp_ha.sa_data); if (!dev) return -ENODEV; } @@ -1000,7 +1000,7 @@ static int arp_req_set(struct arpreq *r, if (r->arp_flags & ATF_PERM) r->arp_flags |= ATF_COM; if (dev == NULL) { - struct flowi fl = { .iif = current->host->loopback_dev.ifindex, + struct flowi fl = { .host = current->host, .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; @@ -1107,7 +1107,7 @@ static int arp_req_delete(struct arpreq } if (dev == NULL) { - struct flowi fl = { .iif = current->host->loopback_dev.ifindex, + struct flowi fl = { .host = current->host, .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; @@ -1166,7 +1166,7 @@ int arp_ioctl(unsigned int cmd, void __u rtnl_lock(); if (r.arp_dev[0]) { err = -ENODEV; - if ((dev = __dev_get_by_name(r.arp_dev)) == NULL) + if ((dev = __dev_get_by_name(current->host, r.arp_dev)) == NULL) goto out; /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ @@ -1379,6 +1379,8 @@ static int arp_seq_open(struct inode *in goto out; memset(s, 0, sizeof(*s)); + s->host = current->host; + rc = seq_open(file, &arp_seq_ops); if (rc) goto out_kfree; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e3345bc..90e38b3 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -181,37 +181,6 @@ static void in_dev_rcu_put(struct rcu_he in_dev_put(idev); } -static void inethost_destroy(struct nethost *host) -{ - struct net_device *dev; - ASSERT_RTNL(); - - if (!host) - return; - read_lock(&dev_base_lock); - rcu_read_lock(); - for (dev = dev_base; dev; dev = dev->next) { - struct in_device *in_dev; - struct in_ifaddr *ifa, **ifap; - if ((in_dev = __in_dev_get_rcu(dev)) == NULL) - continue; - - ifap = &in_dev->ifa_list; - while ((ifa = *ifap) != NULL) { - - if (ifa->ifa_host != host) { - ifap = &ifa->ifa_next; - continue; - } - - inet_del_ifa(in_dev, ifap, 0); - inet_free_ifa(ifa); - } - } - rcu_read_unlock(); - read_unlock(&dev_base_lock); -} - static void inetdev_destroy(struct in_device *in_dev) { struct in_ifaddr *ifa; @@ -286,8 +255,7 @@ static void inet_del_ifa(struct in_devic continue; } - if (!IN_DEV_PROMOTE_SECONDARIES(in_dev) && - (ifa1->ifa_host == ifa->ifa_host)) { + if (!IN_DEV_PROMOTE_SECONDARIES(in_dev)) { *ifap1 = ifa->ifa_next; rtmsg_ifa(RTM_DELADDR, ifa); @@ -331,34 +299,6 @@ static void inet_del_ifa(struct in_devic } } -static int inet_chk_same_host_addr(u32 addr, struct in_device *adev, - struct nethost *host) -{ - struct net_device *dev; - struct in_ifaddr *ifa = NULL; - - read_lock(&dev_base_lock); - rcu_read_lock(); - for (dev = dev_base; dev; dev = dev->next) { - struct in_device *idev; - if ((idev = __in_dev_get_rcu(dev)) == NULL) - continue; - for(ifa = idev->ifa_list; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_local == addr) { - if (adev == NULL || ifa->ifa_dev == adev) - goto out; - if (host && (ifa->ifa_host != host) && - (ifa->ifa_scope < RT_SCOPE_LINK)) - goto out; - } - } - } - out: - rcu_read_unlock(); - read_unlock(&dev_base_lock); - return ifa != NULL; -} - static int inet_insert_ifa(struct in_ifaddr *ifa) { struct in_device *in_dev = ifa->ifa_dev; @@ -371,20 +311,6 @@ static int inet_insert_ifa(struct in_ifa return 0; } - /* Deny adding duplicate address on a interface */ - /* Deny adding global addresses already used by another host */ - if (inet_chk_same_host_addr(ifa->ifa_local, ifa->ifa_dev, ifa->ifa_host)) { - inet_free_ifa(ifa); - return -EEXIST; - } - - /* Deny adding addresses owned by other hosts to the loopback device */ - if ((ifa->ifa_dev->dev->flags & IFF_LOOPBACK) && - (ifa->ifa_dev->dev != &ifa->ifa_host->loopback_dev)) { - inet_free_ifa(ifa); - return -EINVAL; - } - ifa->ifa_flags &= ~IFA_F_SECONDARY; last_primary = &in_dev->ifa_list; @@ -447,12 +373,12 @@ static int inet_set_ifa(struct net_devic return inet_insert_ifa(ifa); } -struct in_device *inetdev_by_index(int ifindex) +struct in_device *inetdev_by_index(struct nethost *host, int ifindex) { struct net_device *dev; struct in_device *in_dev = NULL; read_lock(&dev_base_lock); - dev = __dev_get_by_index(ifindex); + dev = __dev_get_by_index(host, ifindex); if (dev) in_dev = in_dev_get(dev); read_unlock(&dev_base_lock); @@ -479,18 +405,17 @@ static int inet_rtm_deladdr(struct sk_bu struct in_device *in_dev; struct ifaddrmsg *ifm = NLMSG_DATA(nlh); struct in_ifaddr *ifa, **ifap; + struct nethost *host = skb->sk->sk_host; ASSERT_RTNL(); - if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL) + if ((in_dev = inetdev_by_index(host, ifm->ifa_index)) == NULL) goto out; __in_dev_put(in_dev); for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) { - if ((ifa->ifa_host && - skb->sk->sk_host != ifa->ifa_host) || - (rta[IFA_LOCAL - 1] && + if ((rta[IFA_LOCAL - 1] && memcmp(RTA_DATA(rta[IFA_LOCAL - 1]), &ifa->ifa_local, 4)) || (rta[IFA_LABEL - 1] && @@ -514,6 +439,7 @@ static int inet_rtm_newaddr(struct sk_bu struct in_device *in_dev; struct ifaddrmsg *ifm = NLMSG_DATA(nlh); struct in_ifaddr *ifa; + struct nethost *host = skb->sk->sk_host; int rc = -EINVAL; ASSERT_RTNL(); @@ -522,7 +448,7 @@ static int inet_rtm_newaddr(struct sk_bu goto out; rc = -ENODEV; - if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) + if ((dev = __dev_get_by_index(host, ifm->ifa_index)) == NULL) goto out; rc = -ENOBUFS; @@ -535,7 +461,6 @@ static int inet_rtm_newaddr(struct sk_bu if ((ifa = inet_alloc_ifa()) == NULL) goto out; - ifa->ifa_host = skb->sk->sk_host; if (!rta[IFA_ADDRESS - 1]) rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1]; memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4); @@ -656,7 +581,7 @@ int devinet_ioctl(unsigned int cmd, void rtnl_lock(); ret = -ENODEV; - if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) + if ((dev = __dev_get_by_name(current->host, ifr.ifr_name)) == NULL) goto done; if (colon) @@ -672,8 +597,6 @@ int devinet_ioctl(unsigned int cmd, void for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) { if (!strcmp(ifr.ifr_name, ifa->ifa_label) && - (!ifa->ifa_host || - ifa->ifa_host == current->host) && sin_orig.sin_addr.s_addr == ifa->ifa_address) { break; /* found */ @@ -686,9 +609,7 @@ int devinet_ioctl(unsigned int cmd, void if (!ifa) { for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) - if (!strcmp(ifr.ifr_name, ifa->ifa_label) && - (!ifa->ifa_host || - ifa->ifa_host == current->host)) + if (!strcmp(ifr.ifr_name, ifa->ifa_label)) break; } } @@ -736,7 +657,6 @@ int devinet_ioctl(unsigned int cmd, void ret = -ENOBUFS; if ((ifa = inet_alloc_ifa()) == NULL) break; - ifa->ifa_host = current->host; if (colon) memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ); else @@ -868,7 +788,7 @@ out: return done; } -u32 inet_select_addr(struct nethost *host, const struct net_device *dev, u32 dst, int scope) +u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) { u32 addr = 0; struct in_device *in_dev; @@ -878,9 +798,7 @@ u32 inet_select_addr(struct nethost *hos if (!in_dev) goto no_in_dev; - for_ifa(in_dev) { - if (ifa->ifa_host && host && ifa->ifa_host != host) - continue; + for_primary_ifa(in_dev) { if (ifa->ifa_scope > scope) continue; if (!dst || inet_ifa_match(dst, ifa)) { @@ -906,9 +824,7 @@ no_in_dev: if ((in_dev = __in_dev_get_rcu(dev)) == NULL) continue; - for_ifa(in_dev) { - if (ifa->ifa_host && host && ifa->ifa_host != host) - continue; + for_primary_ifa(in_dev) { if (ifa->ifa_scope != RT_SCOPE_LINK && ifa->ifa_scope <= scope) { addr = ifa->ifa_local; @@ -923,15 +839,13 @@ out: return addr; } -static u32 confirm_addr_indev(struct nethost *host, struct in_device *in_dev, +static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst, u32 local, int scope) { int same = 0; u32 addr = 0; for_ifa(in_dev) { - if (ifa->ifa_host && host && ifa->ifa_host != host) - continue; if (!addr && (local == ifa->ifa_local || !local) && ifa->ifa_scope <= scope) { @@ -964,15 +878,12 @@ static u32 confirm_addr_indev(struct net /* * Confirm that local IP address exists using wildcards: - * - host: logical host, NULL for any host * - dev: only on this interface, NULL=any interface * - dst: only in the same subnet as dst, 0=any dst * - local: address, 0=autoselect the local address * - scope: maximum allowed scope value for the local address */ -u32 inet_confirm_addr(struct nethost *host, const struct net_device *dev, - u32 dst, u32 local, int scope) - +u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope) { u32 addr = 0; struct in_device *in_dev; @@ -980,7 +891,7 @@ u32 inet_confirm_addr(struct nethost *ho if (dev) { rcu_read_lock(); if ((in_dev = __in_dev_get_rcu(dev))) - addr = confirm_addr_indev(host, in_dev, dst, local, scope); + addr = confirm_addr_indev(in_dev, dst, local, scope); rcu_read_unlock(); return addr; @@ -990,7 +901,7 @@ u32 inet_confirm_addr(struct nethost *ho rcu_read_lock(); for (dev = dev_base; dev; dev = dev->next) { if ((in_dev = __in_dev_get_rcu(dev))) { - addr = confirm_addr_indev(host, in_dev, dst, local, scope); + addr = confirm_addr_indev(in_dev, dst, local, scope); if (addr) break; } @@ -1001,44 +912,6 @@ u32 inet_confirm_addr(struct nethost *ho return addr; } -/** - * inet_host - Attempt to find the host for an incoming ipaddress - * @dev: Network device we saw the address on - * @addr: ip address whose host we are seeking - */ -struct nethost *inet_host(struct net_device *dev, u32 addr) -{ - struct net_device *odev; - struct in_device *in_dev; - struct nethost *host = NULL; - rcu_read_lock(); - if ((in_dev = __in_dev_get_rcu(dev))) { - for_ifa(in_dev) { - if (ifa->ifa_address == addr) { - host = ifa->ifa_host; - goto found; - } - } endfor_ifa(in_dev); - } - - for (odev = dev_base ; odev ; odev = dev->next) { - if (odev == dev) - continue; - if ((in_dev = __in_dev_get_rcu(odev))) { - for_ifa(in_dev) { - if (ifa->ifa_address == addr) { - host = ifa->ifa_host; - goto found; - } - } endfor_ifa(in_dev); - } - } - host = loopback_host(dev); -found: - rcu_read_unlock(); - return host; -} - /* * Device notifier */ @@ -1087,10 +960,23 @@ static int inetdev_event(struct notifier void *ptr) { struct net_device *dev = ptr; - struct in_device *in_dev = __in_dev_get_rtnl(dev); + struct nethost *host = dev->host; + struct ip_host *ihost; + struct in_device *in_dev; ASSERT_RTNL(); + ihost = in_host_get(host); + if (!ihost) { + inet_host_init(host); + ihost = in_host_get(host); + if (!ihost) + panic("devinet: Failed to create ihost\n"); + if (!ihost) + goto out; + } + + in_dev = __in_dev_get_rtnl(dev); if (!in_dev) { if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { in_dev = inetdev_init(dev); @@ -1113,7 +999,6 @@ static int inetdev_event(struct notifier if (dev->flags & IFF_LOOPBACK) { struct in_ifaddr *ifa; if ((ifa = inet_alloc_ifa()) != NULL) { - ifa->ifa_host = loopback_host(dev); ifa->ifa_local = ifa->ifa_address = htonl(INADDR_LOOPBACK); ifa->ifa_prefixlen = 8; @@ -1134,10 +1019,7 @@ static int inetdev_event(struct notifier if (dev->mtu >= 68) break; /* MTU falled under 68, disable IP */ - inetdev_destroy(in_dev); - break; case NETDEV_UNREGISTER: - inethost_destroy(loopback_host(dev)); inetdev_destroy(in_dev); break; case NETDEV_CHANGENAME: @@ -1206,10 +1088,14 @@ static int inet_dump_ifaddr(struct sk_bu s_ip_idx = ip_idx = cb->args[1]; read_lock(&dev_base_lock); - for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { - if (idx < s_idx) + for (dev = dev_base, idx = 0; dev; dev = dev->next) { + int lidx; + if (dev->host != skb->sk->sk_host) continue; - if (idx > s_idx) + lidx = idx++; + if (lidx < s_idx) + continue; + if (lidx > s_idx) s_ip_idx = 0; rcu_read_lock(); if ((in_dev = __in_dev_get_rcu(dev)) == NULL) { @@ -1218,10 +1104,8 @@ static int inet_dump_ifaddr(struct sk_bu } for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; - ifa = ifa->ifa_next) { - if (ifa->ifa_host && ifa->ifa_host != skb->sk->sk_host) - continue; - if (ip_idx++ < s_ip_idx) + ifa = ifa->ifa_next, ip_idx++) { + if (ip_idx < s_ip_idx) continue; if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, @@ -1252,8 +1136,8 @@ static void rtmsg_ifa(int event, struct kfree_skb(skb); netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, EINVAL); } else { - netlink_host_broadcast(rtnl, skb, ifa->ifa_host, 0, - RTNLGRP_IPV4_IFADDR, GFP_KERNEL); + netlink_broadcast(rtnl, skb, ifa->ifa_dev->dev->host, 0, + RTNLGRP_IPV4_IFADDR, GFP_KERNEL); } } diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 1b5a09d..a03a3af 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -320,6 +320,7 @@ static u32 esp4_get_max_size(struct xfrm static void esp4_err(struct sk_buff *skb, u32 info) { + struct nethost *host = skb->dev->host; struct iphdr *iph = (struct iphdr*)skb->data; struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2)); struct xfrm_state *x; @@ -328,7 +329,7 @@ static void esp4_err(struct sk_buff *skb skb->h.icmph->code != ICMP_FRAG_NEEDED) return; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); + x = xfrm_state_lookup(host, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); if (!x) return; NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n", diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index f9a2db0..1caf7ba 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -51,23 +51,18 @@ #define RT_TABLE_MIN RT_TABLE_MAIN -struct fib_table *ip_fib_local_table; -struct fib_table *ip_fib_main_table; - #else #define RT_TABLE_MIN 1 -struct fib_table *fib_tables[RT_TABLE_MAX+1]; - -struct fib_table *__fib_new_table(int id) +struct fib_table *__fib_new_table(struct ip_host *ihost, int id) { struct fib_table *tb; tb = fib_hash_init(id); if (!tb) return NULL; - fib_tables[id] = tb; + ihost->fib_tables[id] = tb; return tb; } @@ -75,7 +70,7 @@ struct fib_table *__fib_new_table(int id #endif /* CONFIG_IP_MULTIPLE_TABLES */ -static void fib_flush(void) +static void fib_flush(struct ip_host *ihost) { int flushed = 0; #ifdef CONFIG_IP_MULTIPLE_TABLES @@ -83,13 +78,13 @@ static void fib_flush(void) int id; for (id = RT_TABLE_MAX; id>0; id--) { - if ((tb = fib_get_table(id))==NULL) + if ((tb = fib_get_table(ihost, id))==NULL) continue; flushed += tb->tb_flush(tb); } #else /* CONFIG_IP_MULTIPLE_TABLES */ - flushed += ip_fib_main_table->tb_flush(ip_fib_main_table); - flushed += ip_fib_local_table->tb_flush(ip_fib_local_table); + flushed += ihost->ip_fib_main_table->tb_flush(ip_fib_main_table); + flushed += ihost->ip_fib_local_table->tb_flush(ip_fib_local_table); #endif /* CONFIG_IP_MULTIPLE_TABLES */ if (flushed) @@ -100,18 +95,21 @@ static void fib_flush(void) * Find the first device with a given source address. */ -struct net_device * ip_dev_find(u32 addr) +struct net_device * ip_dev_find(struct nethost *host, u32 addr) { - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; + struct flowi fl = { .host = host, + .nl_u = { .ip4_u = { .daddr = addr } } }; struct fib_result res; struct net_device *dev = NULL; + struct fib_table *local_table; + struct ip_host *ihost = in_host_get(host); #ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL; #endif - if (!ip_fib_local_table || - ip_fib_local_table->tb_lookup(ip_fib_local_table, &fl, &res)) + local_table = ihost->ip_fib_local_table; + if (!local_table || local_table->tb_lookup(local_table, &fl, &res)) return NULL; if (res.type != RTN_LOCAL) goto out; @@ -124,10 +122,12 @@ out: return dev; } -unsigned inet_addr_type(u32 addr) +unsigned inet_addr_type(struct nethost *host, u32 addr) { - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; + struct flowi fl = { .host = host, + .nl_u = { .ip4_u = { .daddr = addr } } }; struct fib_result res; + struct fib_table *local_table; unsigned ret = RTN_BROADCAST; if (ZERONET(addr) || BADCLASS(addr)) @@ -139,10 +139,10 @@ unsigned inet_addr_type(u32 addr) res.r = NULL; #endif - if (ip_fib_local_table) { + local_table = in_host_get(host)->ip_fib_local_table; + if (local_table) { ret = RTN_UNICAST; - if (!ip_fib_local_table->tb_lookup(ip_fib_local_table, - &fl, &res)) { + if (!local_table->tb_lookup(local_table, &fl, &res)) { ret = res.type; fib_res_put(&res); } @@ -162,7 +162,8 @@ int fib_validate_source(u32 src, u32 dst struct net_device *dev, u32 *spec_dst, u32 *itag) { struct in_device *in_dev; - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .host = dev->host, + .nl_u = { .ip4_u = { .daddr = src, .saddr = dst, .tos = tos } }, @@ -187,7 +188,7 @@ int fib_validate_source(u32 src, u32 dst goto last_resort; if (res.type != RTN_UNICAST) goto e_inval_res; - *spec_dst = FIB_RES_PREFSRC(NULL, res); + *spec_dst = FIB_RES_PREFSRC(res); fib_combine_itag(itag, &res); #ifdef CONFIG_IP_ROUTE_MULTIPATH if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1) @@ -209,7 +210,7 @@ int fib_validate_source(u32 src, u32 dst ret = 0; if (fib_lookup(&fl, &res) == 0) { if (res.type == RTN_UNICAST) { - *spec_dst = FIB_RES_PREFSRC(NULL, res); + *spec_dst = FIB_RES_PREFSRC(res); ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; } fib_res_put(&res); @@ -219,7 +220,7 @@ int fib_validate_source(u32 src, u32 dst last_resort: if (rpf) goto e_inval; - *spec_dst = inet_select_addr(NULL, dev, 0, RT_SCOPE_UNIVERSE); + *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); *itag = 0; return 0; @@ -237,6 +238,7 @@ e_inval: int ip_rt_ioctl(unsigned int cmd, void __user *arg) { + struct ip_host *ihost = in_host_get(current->host); int err; struct kern_rta rta; struct rtentry r; @@ -253,15 +255,15 @@ int ip_rt_ioctl(unsigned int cmd, void _ if (copy_from_user(&r, arg, sizeof(struct rtentry))) return -EFAULT; rtnl_lock(); - err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r); + err = fib_convert_rtentry(current->host, cmd, &req.nlh, &req.rtm, &rta, &r); if (err == 0) { if (cmd == SIOCDELRT) { - struct fib_table *tb = fib_get_table(req.rtm.rtm_table); + struct fib_table *tb = fib_get_table(ihost, req.rtm.rtm_table); err = -ESRCH; if (tb) err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL); } else { - struct fib_table *tb = fib_new_table(req.rtm.rtm_table); + struct fib_table *tb = fib_new_table(ihost, req.rtm.rtm_table); err = -ENOBUFS; if (tb) err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL); @@ -305,13 +307,14 @@ int inet_rtm_delroute(struct sk_buff *sk struct fib_table * tb; struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); + struct ip_host *ihost = in_host_get(skb->sk->sk_host); if (inet_check_attr(r, rta)) return -EINVAL; - tb = fib_get_table(r->rtm_table); + tb = fib_get_table(ihost, r->rtm_table); if (tb) - return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb)); + return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, skb); return -ESRCH; } @@ -320,13 +323,14 @@ int inet_rtm_newroute(struct sk_buff *sk struct fib_table * tb; struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); + struct ip_host *ihost = in_host_get(skb->sk->sk_host); if (inet_check_attr(r, rta)) return -EINVAL; - tb = fib_new_table(r->rtm_table); + tb = fib_new_table(ihost, r->rtm_table); if (tb) - return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb)); + return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, skb); return -ENOBUFS; } @@ -335,6 +339,7 @@ int inet_dump_fib(struct sk_buff *skb, s int t; int s_t; struct fib_table *tb; + struct ip_host *ihost = in_host_get(skb->sk->sk_host); if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) && ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED) @@ -348,7 +353,7 @@ int inet_dump_fib(struct sk_buff *skb, s if (t < s_t) continue; if (t > s_t) memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); - if ((tb = fib_get_table(t))==NULL) + if ((tb = fib_get_table(ihost, t))==NULL) continue; if (tb->tb_dump(tb, skb, cb) < 0) break; @@ -374,14 +379,15 @@ static void fib_magic(int cmd, int type, struct rtmsg rtm; } req; struct kern_rta rta; + struct ip_host *ihost = in_host_get(ifa->ifa_dev->dev->host); memset(&req.rtm, 0, sizeof(req.rtm)); memset(&rta, 0, sizeof(rta)); if (type == RTN_UNICAST) - tb = fib_new_table(RT_TABLE_MAIN); + tb = fib_new_table(ihost, RT_TABLE_MAIN); else - tb = fib_new_table(RT_TABLE_LOCAL); + tb = fib_new_table(ihost, RT_TABLE_LOCAL); if (tb == NULL) return; @@ -453,6 +459,8 @@ static void fib_del_ifaddr(struct in_ifa struct net_device *dev = in_dev->dev; struct in_ifaddr *ifa1; struct in_ifaddr *prim = ifa; + struct nethost *host = dev->host; + struct ip_host *ihost = in_host_get(host); u32 brd = ifa->ifa_address|~ifa->ifa_mask; u32 any = ifa->ifa_address&ifa->ifa_mask; #define LOCAL_OK 1 @@ -499,7 +507,7 @@ static void fib_del_ifaddr(struct in_ifa fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); /* Check, that this local address finally disappeared. */ - if (inet_addr_type(ifa->ifa_local) != RTN_LOCAL) { + if (inet_addr_type(host, ifa->ifa_local) != RTN_LOCAL) { /* And the last, but not the least thing. We must flush stray FIB entries. @@ -507,7 +515,7 @@ static void fib_del_ifaddr(struct in_ifa for stray nexthop entries, then ignite fib_flush. */ if (fib_sync_down(ifa->ifa_local, NULL, 0)) - fib_flush(); + fib_flush(ihost); } } #undef LOCAL_OK @@ -516,11 +524,13 @@ static void fib_del_ifaddr(struct in_ifa #undef BRD1_OK } -static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb ) +static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb, + struct nethost *host) { struct fib_result res; - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = frn->fl_addr, + struct flowi fl = { .host = host, + .nl_u = { .ip4_u = { .daddr = frn->fl_addr, .fwmark = frn->fl_fwmark, .tos = frn->fl_tos, .scope = frn->fl_scope } } }; @@ -548,14 +558,15 @@ static void nl_fib_input(struct sock *sk int err; u32 pid; struct fib_table *tb; + struct ip_host *ihost = in_host_get(sk->sk_host); skb = skb_recv_datagram(sk, 0, 0, &err); nlh = (struct nlmsghdr *)skb->data; frn = (struct fib_result_nl *) NLMSG_DATA(nlh); - tb = fib_get_table(frn->tb_id_in); + tb = fib_get_table(ihost, frn->tb_id_in); - nl_fib_lookup(frn, tb); + nl_fib_lookup(frn, tb, sk->sk_host); pid = NETLINK_CB(skb).pid; /*pid of sending process */ NETLINK_CB(skb).pid = 0; /* from kernel */ @@ -571,8 +582,9 @@ static void nl_fib_lookup_init(void) static void fib_disable_ip(struct net_device *dev, int force) { + struct ip_host *ihost = in_host_get(dev->host); if (fib_sync_down(0, dev, force)) - fib_flush(); + fib_flush(ihost); rt_cache_flush(0); arp_ifdown(dev); } diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 2a8c9af..e42f412 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -382,8 +382,9 @@ static struct fib_node *fib_find_node(st static int fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, - struct nlmsghdr *n, struct netlink_skb_parms *req) + struct nlmsghdr *n, struct sk_buff *in_skb) { + struct nethost *host = in_skb ? in_skb->sk->sk_host : current->host; struct fn_hash *table = (struct fn_hash *) tb->tb_data; struct fib_node *new_f, *f; struct fib_alias *fa, *new_fa; @@ -410,7 +411,7 @@ fn_hash_insert(struct fib_table *tb, str key = fz_key(dst, fz); } - if ((fi = fib_create_info(r, rta, n, &err)) == NULL) + if ((fi = fib_create_info(host, r, rta, n, &err)) == NULL) return err; if (fz->fz_nent > (fz->fz_divisor<<1) && @@ -527,7 +528,7 @@ fn_hash_insert(struct fib_table *tb, str fz->fz_nent++; rt_cache_flush(-1); - rtmsg_fib(RTM_NEWROUTE, key, new_fa, z, tb->tb_id, n, req); + rtmsg_fib(RTM_NEWROUTE, key, new_fa, z, tb->tb_id, n, in_skb); return 0; out_free_new_fa: @@ -540,7 +541,7 @@ out: static int fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, - struct nlmsghdr *n, struct netlink_skb_parms *req) + struct nlmsghdr *n, struct sk_buff *in_skb) { struct fn_hash *table = (struct fn_hash*)tb->tb_data; struct fib_node *f; @@ -597,7 +598,7 @@ fn_hash_delete(struct fib_table *tb, str int kill_fn; fa = fa_to_delete; - rtmsg_fib(RTM_DELROUTE, key, fa, z, tb->tb_id, n, req); + rtmsg_fib(RTM_DELROUTE, key, fa, z, tb->tb_id, n, in_skb); kill_fn = 0; write_lock_bh(&fib_hash_lock); @@ -805,6 +806,7 @@ struct fib_table * __init fib_hash_init( #ifdef CONFIG_PROC_FS struct fib_iter_state { + struct ip_host *ihost; struct fn_zone *zone; int bucket; struct hlist_head *hash_head; @@ -818,7 +820,8 @@ struct fib_iter_state { static struct fib_alias *fib_get_first(struct seq_file *seq) { struct fib_iter_state *iter = seq->private; - struct fn_hash *table = (struct fn_hash *) ip_fib_main_table->tb_data; + struct fib_table *tb = iter->ihost->ip_fib_main_table; + struct fn_hash *table = (struct fn_hash *) tb->tb_data; iter->bucket = 0; iter->hash_head = NULL; @@ -954,10 +957,11 @@ static struct fib_alias *fib_get_idx(str static void *fib_seq_start(struct seq_file *seq, loff_t *pos) { + struct fib_iter_state *iter = seq->private; void *v = NULL; read_lock(&fib_hash_lock); - if (ip_fib_main_table) + if (iter->ihost->ip_fib_main_table) v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; return v; } @@ -1058,6 +1062,7 @@ static int fib_seq_open(struct inode *in seq = file->private_data; seq->private = s; memset(s, 0, sizeof(*s)); + s->ihost = in_host_get(current->host); out: return rc; out_kfree: diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h index ef6609e..e6a33f6 100644 --- a/net/ipv4/fib_lookup.h +++ b/net/ipv4/fib_lookup.h @@ -23,7 +23,8 @@ extern int fib_semantic_match(struct lis struct fib_result *res, __u32 zone, __u32 mask, int prefixlen); extern void fib_release_info(struct fib_info *); -extern struct fib_info *fib_create_info(const struct rtmsg *r, +extern struct fib_info *fib_create_info(struct nethost *host, + const struct rtmsg *r, struct kern_rta *rta, const struct nlmsghdr *, int *err); @@ -35,7 +36,7 @@ extern int fib_dump_info(struct sk_buff unsigned int); extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa, int z, int tb_id, - struct nlmsghdr *n, struct netlink_skb_parms *req); + struct nlmsghdr *n, struct sk_buff *in_skb); extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio); extern int fib_detect_death(struct fib_info *fi, int order, diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 0b298bb..bee9bfa 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -139,13 +139,13 @@ int inet_rtm_delrule(struct sk_buff *skb /* Allocate new unique table id */ -static struct fib_table *fib_empty_table(void) +static struct fib_table *fib_empty_table(struct ip_host *ihost) { int id; for (id = 1; id <= RT_TABLE_MAX; id++) - if (fib_tables[id] == NULL) - return __fib_new_table(id); + if (ihost->fib_tables[id] == NULL) + return __fib_new_table(ihost, id); return NULL; } @@ -165,6 +165,7 @@ int inet_rtm_newrule(struct sk_buff *skb struct rtmsg *rtm = NLMSG_DATA(nlh); struct fib_rule *r, *new_r, **rp; unsigned char table_id; + struct ip_host *ihost = in_host_get(skb->sk->sk_host); if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 || (rtm->rtm_tos & ~IPTOS_TOS_MASK)) @@ -177,7 +178,7 @@ int inet_rtm_newrule(struct sk_buff *skb if (table_id == RT_TABLE_UNSPEC) { struct fib_table *table; if (rtm->rtm_type == RTN_UNICAST) { - if ((table = fib_empty_table()) == NULL) + if ((table = fib_empty_table(ihost)) == NULL) return -ENOBUFS; table_id = table->tb_id; } @@ -211,7 +212,7 @@ int inet_rtm_newrule(struct sk_buff *skb struct net_device *dev; rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ); new_r->r_ifindex = -1; - dev = __dev_get_by_name(new_r->r_ifname); + dev = __dev_get_by_name(ihost->host, new_r->r_ifname); if (dev) new_r->r_ifindex = dev->ifindex; } @@ -285,6 +286,10 @@ int fib_lookup(const struct flowi *flp, int err; struct fib_rule *r, *policy; struct fib_table *tb; + struct ip_host *ihost; + + BUG_ON(!flp->host); + ihost = in_host_get(flp->host); u32 daddr = flp->fl4_dst; u32 saddr = flp->fl4_src; @@ -319,7 +324,7 @@ FRprintk("tb %d r %d ", r->r_table, r->r return -EACCES; } - if ((tb = fib_get_table(r->r_table)) == NULL) + if ((tb = fib_get_table(ihost, r->r_table)) == NULL) continue; err = tb->tb_lookup(tb, flp, res); if (err == 0) { @@ -341,10 +346,12 @@ FRprintk("FAILURE\n"); void fib_select_default(const struct flowi *flp, struct fib_result *res) { + BUG_ON(!flp->host); if (res->r && res->r->r_action == RTN_UNICAST && FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) { struct fib_table *tb; - if ((tb = fib_get_table(res->r->r_table)) != NULL) + struct ip_host *ihost = in_host_get(flp->host); + if ((tb = fib_get_table(ihost, res->r->r_table)) != NULL) tb->tb_select_default(tb, flp, res); } } diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index cd68986..9ef6a64 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -83,7 +83,7 @@ for (nhsel=0; nhsel < 1; nhsel++) #define endfor_nexthops(fi) } -static struct +static const struct { int error; u8 scope; @@ -273,17 +273,29 @@ int ip_fib_check_default(u32 gw, struct void rtmsg_fib(int event, u32 key, struct fib_alias *fa, int z, int tb_id, - struct nlmsghdr *n, struct netlink_skb_parms *req) + struct nlmsghdr *n, struct sk_buff *in_skb) { + struct nethost *host; struct sk_buff *skb; - u32 pid = req ? req->pid : n->nlmsg_pid; + u32 nl_port, sender; int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); + if (in_skb) { + host = in_skb->sk->sk_host; + sender = NETLINK_CB(in_skb).pid; + nl_port = NETLINK_CB(in_skb).pid; + } else { + n->nlmsg_flags &= ~NLM_F_ECHO; + host = current->host; + sender = current->tid; + nl_port = 0; /* Port to suppress broadcasts to */ + } + skb = alloc_skb(size, GFP_KERNEL); if (!skb) return; - if (fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id, + if (fib_dump_info(skb, sender, n->nlmsg_seq, event, tb_id, fa->fa_type, fa->fa_scope, &key, z, fa->fa_tos, fa->fa_info, 0) < 0) { @@ -293,9 +305,9 @@ void rtmsg_fib(int event, u32 key, struc NETLINK_CB(skb).dst_group = RTNLGRP_IPV4_ROUTE; if (n->nlmsg_flags&NLM_F_ECHO) atomic_inc(&skb->users); - netlink_broadcast(rtnl, skb, pid, RTNLGRP_IPV4_ROUTE, GFP_KERNEL); + netlink_broadcast(rtnl, skb, host, nl_port, RTNLGRP_IPV4_ROUTE, GFP_KERNEL); if (n->nlmsg_flags&NLM_F_ECHO) - netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); + netlink_unicast(in_skb->sk, skb, nl_port, MSG_DONTWAIT); } /* Return the first fib alias matching TOS with @@ -487,7 +499,8 @@ int fib_nh_match(struct rtmsg *r, struct |-> {local prefix} (terminal node) */ -static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_nh *nh) +static int fib_check_nh(struct nethost *host, const struct rtmsg *r, + struct fib_info *fi, struct fib_nh *nh) { int err; @@ -503,9 +516,9 @@ static int fib_check_nh(const struct rtm if (r->rtm_scope >= RT_SCOPE_LINK) return -EINVAL; - if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) + if (inet_addr_type(host, nh->nh_gw) != RTN_UNICAST) return -EINVAL; - if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL) + if ((dev = __dev_get_by_index(host, nh->nh_oif)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) return -ENETDOWN; @@ -515,7 +528,8 @@ static int fib_check_nh(const struct rtm return 0; } { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .host = host, + .nl_u = { .ip4_u = { .daddr = nh->nh_gw, .scope = r->rtm_scope + 1 } }, .oif = nh->nh_oif }; @@ -547,7 +561,7 @@ out: if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK)) return -EINVAL; - in_dev = inetdev_by_index(nh->nh_oif); + in_dev = inetdev_by_index(host, nh->nh_oif); if (in_dev == NULL) return -ENODEV; if (!(in_dev->dev->flags&IFF_UP)) { @@ -646,7 +660,8 @@ static void fib_hash_move(struct hlist_h } struct fib_info * -fib_create_info(const struct rtmsg *r, struct kern_rta *rta, +fib_create_info(struct nethost *host, + const struct rtmsg *r, struct kern_rta *rta, const struct nlmsghdr *nlh, int *errp) { int err; @@ -792,13 +807,13 @@ fib_create_info(const struct rtmsg *r, s if (nhs != 1 || nh->nh_gw) goto err_inval; nh->nh_scope = RT_SCOPE_NOWHERE; - nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif); + nh->nh_dev = dev_get_by_index(host, fi->fib_nh->nh_oif); err = -ENODEV; if (nh->nh_dev == NULL) goto failure; } else { change_nexthops(fi) { - if ((err = fib_check_nh(r, fi, nh)) != 0) + if ((err = fib_check_nh(host, r, fi, nh)) != 0) goto failure; } endfor_nexthops(fi) } @@ -806,7 +821,7 @@ fib_create_info(const struct rtmsg *r, s if (fi->fib_prefsrc) { if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || memcmp(&fi->fib_prefsrc, rta->rta_dst, 4)) - if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) + if (inet_addr_type(host, fi->fib_prefsrc) != RTN_LOCAL) goto err_inval; } @@ -932,17 +947,9 @@ out_fill_res: /* Find appropriate source address to this destination */ -u32 fib_res_prefsrc(struct nethost *host, struct fib_result *res) +u32 __fib_res_prefsrc(struct fib_result *res) { - u32 addr = 0; - if (res->fi->fib_prefsrc) { - addr = res->fi->fib_prefsrc; - if (host && host != inet_host(FIB_RES_DEV(*res), addr)) - addr = 0; - } - if (!addr) - addr = inet_select_addr(host, FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope); - return addr; + return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope); } int @@ -1018,7 +1025,8 @@ rtattr_failure: #ifndef CONFIG_IP_NOSIOCRT int -fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, +fib_convert_rtentry(struct nethost *host, + int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, struct kern_rta *rta, struct rtentry *r) { int plen; @@ -1051,7 +1059,7 @@ fib_convert_rtentry(int cmd, struct nlms } nl->nlmsg_flags = NLM_F_REQUEST; - nl->nlmsg_pid = current->tid; + nl->nlmsg_pid = 0; /* This is a netlink port number not a pid! */ nl->nlmsg_seq = 0; nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm)); if (cmd == SIOCDELRT) { @@ -1089,7 +1097,7 @@ fib_convert_rtentry(int cmd, struct nlms colon = strchr(devname, ':'); if (colon) *colon = 0; - dev = __dev_get_by_name(devname); + dev = __dev_get_by_name(host, devname); if (!dev) return -ENODEV; rta->rta_oif = &dev->ifindex; @@ -1111,7 +1119,7 @@ fib_convert_rtentry(int cmd, struct nlms ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr; if (r->rt_gateway.sa_family == AF_INET && *ptr) { rta->rta_gw = ptr; - if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST) + if (r->rt_flags&RTF_GATEWAY && inet_addr_type(host, *ptr) == RTN_UNICAST) rtm->rtm_scope = RT_SCOPE_UNIVERSE; } diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 0093ea0..6c33fb8 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1119,8 +1119,9 @@ err: static int fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, - struct nlmsghdr *nlhdr, struct netlink_skb_parms *req) + struct nlmsghdr *nlhdr, struct sk_buff *in_skb) { + struct nethost *host = in_skb ? in_skb->sk->sk_host : current->host; struct trie *t = (struct trie *) tb->tb_data; struct fib_alias *fa, *new_fa; struct list_head *fa_head = NULL; @@ -1150,7 +1151,7 @@ fn_trie_insert(struct fib_table *tb, str key = key & mask; - fi = fib_create_info(r, rta, nlhdr, &err); + fi = fib_create_info(host, r, rta, nlhdr, &err); if (!fi) goto err; @@ -1255,7 +1256,7 @@ fn_trie_insert(struct fib_table *tb, str (fa ? &fa->fa_list : fa_head)); rt_cache_flush(-1); - rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req); + rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, in_skb); succeeded: return 0; @@ -1543,7 +1544,7 @@ static int trie_leaf_remove(struct trie static int fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, - struct nlmsghdr *nlhdr, struct netlink_skb_parms *req) + struct nlmsghdr *nlhdr, struct sk_buff *in_skb) { struct trie *t = (struct trie *) tb->tb_data; u32 key, mask; @@ -1607,7 +1608,7 @@ fn_trie_delete(struct fib_table *tb, str return -ESRCH; fa = fa_to_delete; - rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req); + rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, in_skb); l = fib_find_node(t, key); li = find_leaf_info(l, plen); diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 8ffcf39..35b0c8c 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -383,12 +383,13 @@ static void icmp_reply(struct icmp_bxm * struct rtable *rt = (struct rtable *)skb->dst; u32 daddr; - if (ip_options_echo(&icmp_param->replyopts, skb)) + if (ip_options_echo(&icmp_param->replyopts, skb, rt->fl.host)) goto out; if (icmp_xmit_lock()) return; + BUG_ON(!rt->fl.host); icmp_param->data.icmph.checksum = 0; icmp_out_count(icmp_param->data.icmph.type); @@ -401,7 +402,7 @@ static void icmp_reply(struct icmp_bxm * daddr = icmp_param->replyopts.faddr; } { - struct flowi fl = { .iif = skb->dst->dev->ifindex, + struct flowi fl = { .host = rt->fl.host, .nl_u = { .ip4_u = { .daddr = daddr, .saddr = rt->rt_spec_dst, @@ -514,11 +515,8 @@ void icmp_send(struct sk_buff *skb_in, i saddr = iph->daddr; if (!(rt->rt_flags & RTCF_LOCAL)) { - if (sysctl_icmp_errors_use_inbound_ifaddr) { - struct nethost *host; - host = inet_host(skb_in->dev, iph->saddr); - saddr = inet_select_addr(host, skb_in->dev, 0, RT_SCOPE_LINK); - } + if (sysctl_icmp_errors_use_inbound_ifaddr) + saddr = inet_select_addr(skb_in->dev, 0, RT_SCOPE_LINK); else saddr = 0; } @@ -527,7 +525,7 @@ void icmp_send(struct sk_buff *skb_in, i IPTOS_PREC_INTERNETCONTROL) : iph->tos; - if (ip_options_echo(&icmp_param.replyopts, skb_in)) + if (ip_options_echo(&icmp_param.replyopts, skb_in, rt->fl.host)) goto ende; @@ -548,7 +546,7 @@ void icmp_send(struct sk_buff *skb_in, i { struct flowi fl = { - .iif = skb_in->dst->dev->ifindex, + .host = rt->fl.host, .nl_u = { .ip4_u = { .daddr = icmp_param.replyopts.srr ? @@ -608,6 +606,7 @@ static void icmp_unreach(struct sk_buff struct sock *raw_sk; struct nethost *host; u32 info = 0; + host = skb->dev->host; /* * Incomplete header ? @@ -676,7 +675,7 @@ static void icmp_unreach(struct sk_buff */ if (!sysctl_icmp_ignore_bogus_error_responses && - inet_addr_type(iph->daddr) == RTN_BROADCAST) { + inet_addr_type(host, iph->daddr) == RTN_BROADCAST) { if (net_ratelimit()) printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP " "type %u, code %u " @@ -696,7 +695,6 @@ static void icmp_unreach(struct sk_buff iph = (struct iphdr *)skb->data; protocol = iph->protocol; - host = inet_host(skb->dev, iph->saddr); /* * Deliver ICMP message to raw sockets. Pretty useless feature? @@ -719,7 +717,7 @@ static void icmp_unreach(struct sk_buff rcu_read_lock(); ipprot = rcu_dereference(inet_protos[hash]); if (ipprot && ipprot->err_handler) - ipprot->err_handler(skb, host, info); + ipprot->err_handler(skb, info); rcu_read_unlock(); out: @@ -935,6 +933,8 @@ int icmp_rcv(struct sk_buff *skb) struct icmphdr *icmph; struct rtable *rt = (struct rtable *)skb->dst; + BUG_ON(!rt->fl.host); + ICMP_INC_STATS_BH(ICMP_MIB_INMSGS); switch (skb->ip_summed) { diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index cd8488a..8915e73 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -282,7 +282,7 @@ static struct sk_buff *igmpv3_newpack(st return NULL; { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .oif = dev->ifindex, .nl_u = { .ip4_u = { .daddr = IGMPV3_ALL_MCR } }, @@ -628,7 +628,7 @@ static int igmp_send_report(struct in_de dst = group; { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .oif = dev->ifindex, .nl_u = { .ip4_u = { .daddr = dst } }, .proto = IPPROTO_IGMP }; @@ -890,7 +890,7 @@ int igmp_rcv(struct sk_buff *skb) case IGMPV2_HOST_MEMBERSHIP_REPORT: case IGMPV3_HOST_MEMBERSHIP_REPORT: /* Is it our report looped back? */ - if (rt_output((struct rtable *)skb->dst)) + if (((struct rtable*)skb->dst)->fl.iif == 0) break; igmp_heard_report(in_dev, ih->group); break; @@ -1298,9 +1298,9 @@ void ip_mc_destroy_dev(struct in_device write_unlock_bh(&in_dev->mc_list_lock); } -static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr) +static struct in_device * ip_mc_find_dev(struct sock *sk, struct ip_mreqn *imr) { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = sk->sk_host, .nl_u = { .ip4_u = { .daddr = imr->imr_multiaddr.s_addr } } }; struct rtable *rt; @@ -1308,13 +1308,13 @@ static struct in_device * ip_mc_find_dev struct in_device *idev = NULL; if (imr->imr_ifindex) { - idev = inetdev_by_index(imr->imr_ifindex); + idev = inetdev_by_index(fl.host, imr->imr_ifindex); if (idev) __in_dev_put(idev); return idev; } if (imr->imr_address.s_addr) { - dev = ip_dev_find(imr->imr_address.s_addr); + dev = ip_dev_find(sk->sk_host, imr->imr_address.s_addr); if (!dev) return NULL; __dev_put(dev); @@ -1629,7 +1629,7 @@ int ip_mc_join_group(struct sock *sk , s rtnl_shlock(); - in_dev = ip_mc_find_dev(imr); + in_dev = ip_mc_find_dev(sk, imr); if (!in_dev) { iml = NULL; @@ -1695,7 +1695,7 @@ int ip_mc_leave_group(struct sock *sk, s u32 ifindex; rtnl_lock(); - in_dev = ip_mc_find_dev(imr); + in_dev = ip_mc_find_dev(sk, imr); if (!in_dev) { rtnl_unlock(); return -ENODEV; @@ -1739,7 +1739,7 @@ int ip_mc_source(int add, int omode, str imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr; imr.imr_address.s_addr = mreqs->imr_interface; imr.imr_ifindex = ifindex; - in_dev = ip_mc_find_dev(&imr); + in_dev = ip_mc_find_dev(sk, &imr); if (!in_dev) { err = -ENODEV; @@ -1873,7 +1873,7 @@ int ip_mc_msfilter(struct sock *sk, stru imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; imr.imr_address.s_addr = msf->imsf_interface; imr.imr_ifindex = ifindex; - in_dev = ip_mc_find_dev(&imr); + in_dev = ip_mc_find_dev(sk, &imr); if (!in_dev) { err = -ENODEV; @@ -1950,7 +1950,7 @@ int ip_mc_msfget(struct sock *sk, struct imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; imr.imr_address.s_addr = msf->imsf_interface; imr.imr_ifindex = 0; - in_dev = ip_mc_find_dev(&imr); + in_dev = ip_mc_find_dev(sk, &imr); if (!in_dev) { err = -ENODEV; @@ -2088,6 +2088,7 @@ void ip_mc_drop_socket(struct sock *sk) { struct inet_sock *inet = inet_sk(sk); struct ip_mc_socklist *iml; + struct nethost *host = sk->sk_host; if (inet->mc_list == NULL) return; @@ -2097,7 +2098,7 @@ void ip_mc_drop_socket(struct sock *sk) struct in_device *in_dev; inet->mc_list = iml->next; - if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != NULL) { + if ((in_dev = inetdev_by_index(host, iml->multi.imr_ifindex)) != NULL) { (void) ip_mc_leave_src(sk, iml, in_dev); ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); in_dev_put(in_dev); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index be02492..96976ad 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -320,7 +320,7 @@ struct dst_entry* inet_csk_route_req(str struct rtable *rt; const struct inet_request_sock *ireq = inet_rsk(req); struct ip_options *opt = inet_rsk(req)->opt; - struct flowi fl = { .iif = sk->sk_host->loopback_dev.ifindex, + struct flowi fl = { .host = sk->sk_host, .oif = sk->sk_bound_dev_if, .nl_u = { .ip4_u = { .daddr = ((opt && opt->srr) ? diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index da8cc37..c28268a 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -201,7 +201,8 @@ static int inet_diag_get_exact(struct sk if (req->idiag_family == AF_INET) { sk = inet_lookup(hashinfo, req->id.idiag_dst[0], req->id.idiag_dport, req->id.idiag_src[0], - req->id.idiag_sport, req->id.idiag_if); + req->id.idiag_sport, req->id.idiag_if, + in_skb->sk->sk_host); } #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) else if (req->idiag_family == AF_INET6) { @@ -210,7 +211,8 @@ static int inet_diag_get_exact(struct sk req->id.idiag_dport, (struct in6_addr *)req->id.idiag_src, req->id.idiag_sport, - req->id.idiag_if); + req->id.idiag_if, + in_skb->sk->sk_host); } #endif else { diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index e7d26d9..4bd96e9 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -90,7 +90,7 @@ struct ipq { atomic_t refcnt; struct timer_list timer; /* when will this queue expire? */ struct ipq **pprev; - int iif; + struct net_device *dev; struct timeval stamp; }; @@ -180,6 +180,9 @@ static __inline__ void frag_kfree_skb(st static __inline__ void frag_free_queue(struct ipq *qp, int *work) { + if (qp->dev) + dev_put(qp->dev); + qp->dev = NULL; if (work) *work -= sizeof(struct ipq); atomic_sub(sizeof(struct ipq), &ip_frag_mem); @@ -295,9 +298,8 @@ static void ip_expire(unsigned long arg) if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) { struct sk_buff *head = qp->fragments; /* Send an ICMP "Fragment Reassembly Timeout" message. */ - if ((head->dev = dev_get_by_index(qp->iif)) != NULL) { + if ((head->dev = qp->dev) != NULL) { icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); - dev_put(head->dev); } } out: @@ -365,7 +367,7 @@ static struct ipq *ip_frag_create(unsign qp->len = 0; qp->meat = 0; qp->fragments = NULL; - qp->iif = 0; + qp->dev = NULL; /* Initialize a timer for this entry. */ init_timer(&qp->timer); @@ -530,8 +532,12 @@ static void ip_frag_queue(struct ipq *qp else qp->fragments = skb; - if (skb->dev) - qp->iif = skb->dev->ifindex; + if (skb->dev) { + if (qp->dev) + dev_put(qp->dev); + qp->dev = skb->dev; + dev_hold(qp->dev); + } skb->dev = NULL; skb_get_timestamp(skb, &qp->stamp); qp->meat += skb->len; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 8b92963..c0614d8 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -251,7 +251,8 @@ static struct ip_tunnel * ipgre_tunnel_l h ^= HASH(remote); } for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) { - if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { + if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr + && t->dev->host == current->host) { if (key == t->parms.i_key) return t; } @@ -265,7 +266,7 @@ static struct ip_tunnel * ipgre_tunnel_l int i; for (i=1; i<100; i++) { sprintf(name, "gre%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(current->host, name) == NULL) break; } if (i==100) @@ -477,7 +478,7 @@ out: /* Try to guess incoming interface */ memset(&fl, 0, sizeof(fl)); - fl.iif = 0; + fl.host = skb->dev->host; fl.fl4_dst = eiph->saddr; fl.fl4_tos = RT_TOS(eiph->tos); fl.proto = IPPROTO_GRE; @@ -491,7 +492,7 @@ out: if (rt->rt_flags&RTCF_LOCAL) { ip_rt_put(rt); rt = NULL; - fl.iif = 0; + fl.host = skb2->dev->host; fl.fl4_dst = eiph->daddr; fl.fl4_src = eiph->saddr; fl.fl4_tos = eiph->tos; @@ -625,7 +626,7 @@ static int ipgre_rcv(struct sk_buff *skb #ifdef CONFIG_NET_IPGRE_BROADCAST if (MULTICAST(iph->daddr)) { /* Looped back packet, drop it! */ - if (rt_output((struct rtable *)skb->dst)) + if (((struct rtable *)skb->dst)->fl.iif == 0) goto drop; tunnel->stat.multicast++; skb->pkt_type = PACKET_BROADCAST; @@ -744,7 +745,7 @@ static int ipgre_tunnel_xmit(struct sk_b } { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .oif = tunnel->parms.link, .nl_u = { .ip4_u = { .daddr = dst, @@ -1096,7 +1097,7 @@ static int ipgre_open(struct net_device struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; if (MULTICAST(t->parms.iph.daddr)) { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .oif = t->parms.link, .nl_u = { .ip4_u = { .daddr = t->parms.iph.daddr, @@ -1120,7 +1121,7 @@ static int ipgre_close(struct net_device { struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; if (MULTICAST(t->parms.iph.daddr) && t->mlink) { - struct in_device *in_dev = inetdev_by_index(t->mlink); + struct in_device *in_dev = inetdev_by_index(dev->host, t->mlink); if (in_dev) { ip_mc_dec_group(in_dev, t->parms.iph.daddr); in_dev_put(in_dev); @@ -1170,7 +1171,7 @@ static int ipgre_tunnel_init(struct net_ /* Guess output device to choose reasonable mtu and hard_header_len */ if (iph->daddr) { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .oif = tunnel->parms.link, .nl_u = { .ip4_u = { .daddr = iph->daddr, @@ -1198,7 +1199,7 @@ static int ipgre_tunnel_init(struct net_ } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(dev->host, tunnel->parms.link); if (tdev) { hlen = tdev->hard_header_len; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 473d0f2..11f480c 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -299,7 +299,7 @@ static inline int ip_rcv_options(struct iph = skb->nh.iph; - if (ip_options_compile(NULL, skb)) { + if (ip_options_compile(NULL, skb, dev->host)) { IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); goto drop; } diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 11a03c9..af88966 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -38,7 +38,6 @@ void ip_options_build(struct sk_buff * s u32 daddr, struct rtable *rt, int is_frag) { unsigned char * iph = skb->nh.raw; - struct sock *sk = skb->sk; memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options)); memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen); @@ -50,9 +49,9 @@ void ip_options_build(struct sk_buff * s if (!is_frag) { if (opt->rr_needaddr) - ip_rt_get_source(sk->sk_host, iph+opt->rr+iph[opt->rr+2]-5, rt); + ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, rt); if (opt->ts_needaddr) - ip_rt_get_source(sk->sk_host, iph+opt->ts+iph[opt->ts+2]-9, rt); + ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt); if (opt->ts_needtime) { struct timeval tv; __u32 midtime; @@ -83,7 +82,8 @@ void ip_options_build(struct sk_buff * s * NOTE: dopt cannot point to skb. */ -int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) +int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb, + struct nethost *ihost) { struct ip_options *sopt; unsigned char *sptr, *dptr; @@ -149,7 +149,7 @@ int ip_options_echo(struct ip_options * __u32 addr; memcpy(&addr, sptr+soffset-1, 4); - if (inet_addr_type(addr) != RTN_LOCAL) { + if (inet_addr_type(ihost, addr) != RTN_LOCAL) { dopt->ts_needtime = 1; soffset += 8; } @@ -244,7 +244,8 @@ void ip_options_fragment(struct sk_buff * If opt == NULL, then skb->data should point to IP header. */ -int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) +int ip_options_compile(struct ip_options * opt, struct sk_buff * skb, + struct nethost *host) { int l; unsigned char * iph; @@ -390,7 +391,7 @@ int ip_options_compile(struct ip_options { u32 addr; memcpy(&addr, &optptr[optptr[2]-1], 4); - if (inet_addr_type(addr) == RTN_UNICAST) + if (inet_addr_type(host, addr) == RTN_UNICAST) break; if (skb) timeptr = (__u32*)&optptr[optptr[2]+3]; @@ -500,14 +501,15 @@ static struct ip_options *ip_options_get } static int ip_options_get_finish(struct ip_options **optp, - struct ip_options *opt, int optlen) + struct ip_options *opt, int optlen, + struct nethost *host) { while (optlen & 3) opt->__data[optlen++] = IPOPT_END; opt->optlen = optlen; opt->is_data = 1; opt->is_setbyuser = 1; - if (optlen && ip_options_compile(opt, NULL)) { + if (optlen && ip_options_compile(opt, NULL, host)) { kfree(opt); return -EINVAL; } @@ -517,7 +519,8 @@ static int ip_options_get_finish(struct return 0; } -int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *data, int optlen) +int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *data, + int optlen, struct nethost *host) { struct ip_options *opt = ip_options_get_alloc(optlen); @@ -527,10 +530,11 @@ int ip_options_get_from_user(struct ip_o kfree(opt); return -EFAULT; } - return ip_options_get_finish(optp, opt, optlen); + return ip_options_get_finish(optp, opt, optlen, host); } -int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen) +int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, + struct nethost *host) { struct ip_options *opt = ip_options_get_alloc(optlen); @@ -538,7 +542,7 @@ int ip_options_get(struct ip_options **o return -ENOMEM; if (optlen) memcpy(opt->__data, data, optlen); - return ip_options_get_finish(optp, opt, optlen); + return ip_options_get_finish(optp, opt, optlen, host); } void ip_forward_options(struct sk_buff *skb) @@ -550,7 +554,7 @@ void ip_forward_options(struct sk_buff * if (opt->rr_needaddr) { optptr = (unsigned char *)raw + opt->rr; - ip_rt_get_source(NULL, &optptr[optptr[2]-5], rt); + ip_rt_get_source(&optptr[optptr[2]-5], rt); opt->is_changed = 1; } if (opt->srr_is_hit) { @@ -569,14 +573,14 @@ void ip_forward_options(struct sk_buff * } if (srrptr + 3 <= srrspace) { opt->is_changed = 1; - ip_rt_get_source(NULL, &optptr[srrptr-1], rt); + ip_rt_get_source(&optptr[srrptr-1], rt); skb->nh.iph->daddr = rt->rt_dst; optptr[2] = srrptr+4; } else if (net_ratelimit()) printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); if (opt->ts_needaddr) { optptr = raw + opt->ts; - ip_rt_get_source(NULL, &optptr[optptr[2]-9], rt); + ip_rt_get_source(&optptr[optptr[2]-9], rt); opt->is_changed = 1; } } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 4554185..e80c03d 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -307,7 +307,7 @@ int ip_queue_xmit(struct sk_buff *skb, i daddr = opt->faddr; { - struct flowi fl = { .iif = sk->sk_host->loopback_dev.ifindex, + struct flowi fl = { .host = sk->sk_host, .oif = sk->sk_bound_dev_if, .nl_u = { .ip4_u = { .daddr = daddr, @@ -1262,7 +1262,7 @@ void ip_send_reply(struct sock *sk, stru u32 daddr; struct rtable *rt = (struct rtable*)skb->dst; - if (ip_options_echo(&replyopts.opt, skb)) + if (ip_options_echo(&replyopts.opt, skb, rt->fl.host)) return; daddr = ipc.addr = rt->rt_src; @@ -1276,7 +1276,7 @@ void ip_send_reply(struct sock *sk, stru } { - struct flowi fl = { .iif = skb->dst->dev->ifindex, + struct flowi fl = { .host = rt->fl.host, .nl_u = { .ip4_u = { .daddr = daddr, .saddr = rt->rt_spec_dst, diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 2f0b47d..15f1ad5 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -100,7 +100,7 @@ static void ip_cmsg_recv_retopts(struct if (IPCB(skb)->opt.optlen == 0) return; - if (ip_options_echo(opt, skb)) { + if (ip_options_echo(opt, skb, skb->sk->sk_host)) { msg->msg_flags |= MSG_CTRUNC; return; } @@ -140,7 +140,8 @@ void ip_cmsg_recv(struct msghdr *msg, st ip_cmsg_recv_retopts(msg, skb); } -int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) +int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc, + struct nethost *host) { int err; struct cmsghdr *cmsg; @@ -153,7 +154,7 @@ int ip_cmsg_send(struct msghdr *msg, str switch (cmsg->cmsg_type) { case IP_RETOPTS: err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); - err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40); + err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40, host); if (err) return err; break; @@ -425,7 +426,7 @@ int ip_setsockopt(struct sock *sk, int l struct ip_options * opt = NULL; if (optlen > 40 || optlen < 0) goto e_inval; - err = ip_options_get_from_user(&opt, optval, optlen); + err = ip_options_get_from_user(&opt, optval, optlen, sk->sk_host); if (err) break; if (sk->sk_type == SOCK_STREAM) { @@ -565,13 +566,13 @@ int ip_setsockopt(struct sock *sk, int l err = 0; break; } - dev = ip_dev_find(mreq.imr_address.s_addr); + dev = ip_dev_find(sk->sk_host, mreq.imr_address.s_addr); if (dev) { mreq.imr_ifindex = dev->ifindex; dev_put(dev); } } else - dev = __dev_get_by_index(mreq.imr_ifindex); + dev = __dev_get_by_index(current->host, mreq.imr_ifindex); err = -EADDRNOTAVAIL; diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index fc718df..9f7b70d 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -201,6 +201,7 @@ out_ok: static void ipcomp4_err(struct sk_buff *skb, u32 info) { u32 spi; + struct nethost *host = skb->dev->host; struct iphdr *iph = (struct iphdr *)skb->data; struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2)); struct xfrm_state *x; @@ -210,7 +211,7 @@ static void ipcomp4_err(struct sk_buff * return; spi = ntohl(ntohs(ipch->cpi)); - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, + x = xfrm_state_lookup(host, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET); if (!x) return; @@ -260,7 +261,7 @@ static int ipcomp_tunnel_attach(struct x int err = 0; struct xfrm_state *t; - t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr.a4, + t = xfrm_state_lookup(x->host, (xfrm_address_t *)&x->id.daddr.a4, x->props.saddr.a4, IPPROTO_IPIP, AF_INET); if (!t) { t = ipcomp_tunnel_create(x); diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index f5b4490..0623374 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -220,7 +220,8 @@ static struct ip_tunnel * ipip_tunnel_lo h ^= HASH(local); } for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) { - if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) + if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr + && t->dev->host == current->host) return t; } if (!create) @@ -232,7 +233,7 @@ static struct ip_tunnel * ipip_tunnel_lo int i; for (i=1; i<100; i++) { sprintf(name, "tunl%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(current->host, name) == NULL) break; } if (i==100) @@ -402,7 +403,7 @@ out: /* Try to guess incoming interface */ memset(&fl, 0, sizeof(fl)); - fl.iif = 0; + fl.host = skb->dev->host, fl.fl4_daddr = eiph->saddr; fl.fl4_tos = RT_TOS(eiph->tos); fl.proto = IPPROTO_IPIP; @@ -416,7 +417,7 @@ out: if (rt->rt_flags&RTCF_LOCAL) { ip_rt_put(rt); rt = NULL; - fl.iif = 0; + fl.host = skb2->dev->host, fl.fl4_daddr = eiph->daddr; fl.fl4_src = eiph->saddr; fl.fl4_tos = eiph->tos; @@ -550,7 +551,7 @@ static int ipip_tunnel_xmit(struct sk_bu } { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .oif = tunnel->parms.link, .nl_u = { .ip4_u = { .daddr = dst, @@ -811,7 +812,7 @@ static int ipip_tunnel_init(struct net_d memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); if (iph->daddr) { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .oif = tunnel->parms.link, .nl_u = { .ip4_u = { .daddr = iph->daddr, @@ -827,7 +828,7 @@ static int ipip_tunnel_init(struct net_d } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(dev->host, tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 070a815..f095442 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -118,11 +118,11 @@ static struct timer_list ipmr_expire_tim /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ static -struct net_device *ipmr_new_tunnel(struct vifctl *v) +struct net_device *ipmr_new_tunnel(struct nethost *host, struct vifctl *v) { struct net_device *dev; - dev = __dev_get_by_name("tunl0"); + dev = __dev_get_by_name(host, "tunl0"); if (dev) { int err; @@ -146,7 +146,7 @@ struct net_device *ipmr_new_tunnel(struc dev = NULL; - if (err == 0 && (dev = __dev_get_by_name(p.name)) != NULL) { + if (err == 0 && (dev = __dev_get_by_name(host, p.name)) != NULL) { dev->flags |= IFF_MULTICAST; in_dev = __in_dev_get_rtnl(dev); @@ -381,7 +381,7 @@ static void ipmr_update_thresholds(struc } } -static int vif_add(struct vifctl *vifc, int mrtsock) +static int vif_add(struct nethost *host, struct vifctl *vifc, int mrtsock) { int vifi = vifc->vifc_vifi; struct vif_device *v = &vif_table[vifi]; @@ -407,12 +407,12 @@ static int vif_add(struct vifctl *vifc, break; #endif case VIFF_TUNNEL: - dev = ipmr_new_tunnel(vifc); + dev = ipmr_new_tunnel(host, vifc); if (!dev) return -ENOBUFS; break; case 0: - dev=ip_dev_find(vifc->vifc_lcl_addr.s_addr); + dev=ip_dev_find(host, vifc->vifc_lcl_addr.s_addr); if (!dev) return -EADDRNOTAVAIL; __dev_put(dev); @@ -903,7 +903,7 @@ int ip_mroute_setsockopt(struct sock *sk return -ENFILE; rtnl_lock(); if (optname==MRT_ADD_VIF) { - ret = vif_add(&vif, sk==mroute_socket); + ret = vif_add(sk->sk_host, &vif, sk==mroute_socket); } else { ret = vif_delete(vif.vifc_vifi); } @@ -1156,7 +1156,7 @@ static void ipmr_queue_xmit(struct sk_bu #endif if (vif->flags&VIFF_TUNNEL) { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = vif->dev->host, .oif = vif->link, .nl_u = { .ip4_u = { .daddr = vif->remote, @@ -1167,7 +1167,7 @@ static void ipmr_queue_xmit(struct sk_bu goto out_free; encap = sizeof(struct iphdr); } else { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = vif->dev->host, .oif = vif->link, .nl_u = { .ip4_u = { .daddr = iph->daddr, @@ -1263,7 +1263,7 @@ static int ip_mr_forward(struct sk_buff if (vif_table[vif].dev != skb->dev) { int true_vifi; - if (rt_output((struct rtable *)skb->dst)) { + if (((struct rtable*)skb->dst)->fl.iif == 0) { /* It is our own packet, looped back. Very complicated situation... diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c index 9b04694..620bffb 100644 --- a/net/ipv4/ipvs/ip_vs_xmit.c +++ b/net/ipv4/ipvs/ip_vs_xmit.c @@ -70,7 +70,7 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp if (!(rt = (struct rtable *) __ip_vs_dst_check(dest, rtos, 0))) { struct flowi fl = { - .iif = 0, + .host = &init_host, .oif = 0, .nl_u = { .ip4_u = { @@ -94,7 +94,7 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp spin_unlock(&dest->dst_lock); } else { struct flowi fl = { - .iif = 0, + .host = &init_host, .oif = 0, .nl_u = { .ip4_u = { @@ -162,7 +162,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, s u8 tos = iph->tos; int mtu; struct flowi fl = { - .iif = 0, + .host = skb->dev->host, .oif = 0, .nl_u = { .ip4_u = { diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 19c46ad..9d781ab 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -21,12 +21,13 @@ int ip_route_me_harder(struct sk_buff ** struct flowi fl = {}; struct dst_entry *odst; unsigned int hh_len; + struct nethost *host = (*pskb)->dev->host; /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. */ - if (inet_addr_type(iph->saddr) == RTN_LOCAL) { - fl.iif = 0, + if (inet_addr_type(host, iph->saddr) == RTN_LOCAL) { + fl.host = host; fl.nl_u.ip4_u.daddr = iph->daddr; fl.nl_u.ip4_u.saddr = iph->saddr; fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); @@ -44,7 +45,7 @@ int ip_route_me_harder(struct sk_buff ** } else { /* non-local src, find valid iif to satisfy * rp-filter when calling ip_route_input. */ - fl.iif = 0, + fl.host = host; fl.nl_u.ip4_u.daddr = iph->saddr; if (ip_route_output_key(&rt, &fl) != 0) return -1; diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 7489e96..7193be6 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -54,7 +54,7 @@ static inline struct rtable *route_rever || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED) #endif ) { - fl.iif = 0; + fl.host = skb->dev->host, fl.nl_u.ip4_u.daddr = iph->saddr; if (hook == NF_IP_LOCAL_IN) fl.nl_u.ip4_u.saddr = iph->daddr; @@ -65,7 +65,7 @@ static inline struct rtable *route_rever } else { /* non-local src, find valid iif to satisfy * rp-filter when calling ip_route_input. */ - fl.iif = 0; + fl.host = skb->dev->host, fl.nl_u.ip4_u.daddr = iph->daddr; if (ip_route_output_key(&rt, &fl) != 0) return NULL; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 3c5eb7a..ca52f8e 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -162,7 +162,7 @@ int raw_v4_input(struct sk_buff *skb, st head = &raw_v4_htable[hash]; if (hlist_empty(head)) goto out; - host = rt_dhost((struct rtable *)skb->dst); + host = ((struct rtable *)skb->dst)->fl.host; sk = __raw_v4_lookup(__sk_head(head), iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex, host); @@ -437,7 +437,7 @@ static int raw_sendmsg(struct kiocb *ioc ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(msg, &ipc); + err = ip_cmsg_send(msg, &ipc, sk->sk_host); if (err) goto out; if (ipc.opt) @@ -475,7 +475,7 @@ static int raw_sendmsg(struct kiocb *ioc } { - struct flowi fl = { .iif = sk->sk_host->loopback_dev.ifindex, + struct flowi fl = { .host = sk->sk_host, .oif = ipc.oif, .nl_u = { .ip4_u = { .daddr = daddr, @@ -554,18 +554,11 @@ static int raw_bind(struct sock *sk, str if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); + chk_addr_ret = inet_addr_type(sk->sk_host, addr->sin_addr.s_addr); ret = -EADDRNOTAVAIL; if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) goto out; - - /* Verify local addresses are for the current host */ - if ((chk_addr_ret == RTN_LOCAL) && - !inet_confirm_addr(sk->sk_host, NULL, 0, addr->sin_addr.s_addr, - RT_SCOPE_NOWHERE)) - goto out; - inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) inet->saddr = 0; /* Use device */ diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 81dffd1..521ce1b 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -501,7 +501,7 @@ static __inline__ int rt_fast_clean(stru /* Kill broadcast/multicast entries very aggresively, if they collide in hash table with more useful entries */ return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) && - !(rth->rt_flags & RTCF_OUTPUT) && rth->u.rt_next; + rth->fl.iif && rth->u.rt_next; } static __inline__ int rt_valuable(struct rtable *rth) @@ -546,7 +546,7 @@ static inline u32 rt_score(struct rtable if (rt_valuable(rt)) score |= (1<<31); - if ((rt->rt_flags & RTCF_OUTPUT) || + if (!rt->fl.iif || !(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL))) score |= (1<<30); @@ -557,7 +557,8 @@ static inline int compare_keys(struct fl { return memcmp(&fl1->nl_u.ip4_u, &fl2->nl_u.ip4_u, sizeof(fl1->nl_u.ip4_u)) == 0 && fl1->oif == fl2->oif && - fl1->iif == fl2->iif; + fl1->iif == fl2->iif && + fl1->host == fl2->host; } #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED @@ -914,6 +915,7 @@ static int rt_intern_hash(unsigned hash, int chain_length; int attempts = !in_softirq(); + BUG_ON(!rt->fl.host); restart: chain_length = 0; min_score = ~(u32)0; @@ -987,7 +989,7 @@ restart: /* Try to bind route to arp only if it is output route or unicast forwarding path. */ - if (rt->rt_type == RTN_UNICAST || (rt->rt_flags & RTCF_OUTPUT)) { + if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) { int err = arp_bind_neighbour(&rt->u.dst); if (err) { spin_unlock_bh(rt_hash_lock_addr(hash)); @@ -1135,7 +1137,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev)) goto reject_redirect; } else { - if (inet_addr_type(new_gw) != RTN_UNICAST) + if (inet_addr_type(dev->host, new_gw) != RTN_UNICAST) goto reject_redirect; } @@ -1155,7 +1157,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd rth->fl.fl4_src != skeys[i] || rth->fl.fl4_tos != tos || rth->fl.oif != ikeys[k] || - !(rth->rt_flags & RTCF_OUTPUT)) { + rth->fl.iif != 0) { rthp = &rth->u.rt_next; continue; } @@ -1409,7 +1411,7 @@ unsigned short ip_rt_frag_needed(struct rth->rt_dst == daddr && rth->rt_src == iph->saddr && rth->fl.fl4_tos == tos && - (rth->rt_flags & RTCF_OUTPUT) && + rth->fl.iif == 0 && !(dst_metric_locked(&rth->u.dst, RTAX_MTU))) { unsigned short mtu = new_mtu; @@ -1484,8 +1486,9 @@ static void ipv4_dst_ifdown(struct dst_e { struct rtable *rt = (struct rtable *) dst; struct in_device *idev = rt->idev; - if (dev != &init_host.loopback_dev && idev && idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(&init_host.loopback_dev); + struct net_device *lo = &dev->host->loopback_dev; + if (dev != lo && idev && idev->dev == dev) { + struct in_device *loopback_idev = in_dev_get(lo); if (loopback_idev) { rt->idev = loopback_idev; in_dev_put(idev); @@ -1522,18 +1525,18 @@ static int ip_rt_bug(struct sk_buff *skb in IP options! */ -void ip_rt_get_source(struct nethost *host, u8 *addr, struct rtable *rt) +void ip_rt_get_source(u8 *addr, struct rtable *rt) { u32 src; struct fib_result res; - if (rt->rt_flags & RTCF_OUTPUT) + if (rt->fl.iif == 0) src = rt->rt_src; else if (fib_lookup(&rt->fl, &res) == 0) { - src = FIB_RES_PREFSRC(host, res); + src = FIB_RES_PREFSRC(res); fib_res_put(&res); } else - src = inet_select_addr(host, rt->u.dst.dev, rt->rt_gateway, + src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, RT_SCOPE_UNIVERSE); memcpy(addr, &src, 4); } @@ -1593,6 +1596,8 @@ static void rt_set_nexthop(struct rtable static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr, u8 tos, struct net_device *dev, int our) { + struct nethost *host = dev->host; + struct net_device *loopback_dev = &host->loopback_dev; unsigned hash; struct rtable *rth; u32 spec_dst; @@ -1611,9 +1616,9 @@ static int ip_route_input_mc(struct sk_b if (ZERONET(saddr)) { if (!LOCAL_MCAST(daddr)) goto e_inval; - spec_dst = inet_select_addr(NULL, dev, 0, RT_SCOPE_LINK); + spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); } else if (fib_validate_source(saddr, 0, tos, 0, - dev, &spec_dst, &itag) < 0) + dev, &spec_dst, &itag) < 0) goto e_inval; rth = dst_alloc(&ipv4_dst_ops); @@ -1626,6 +1631,7 @@ static int ip_route_input_mc(struct sk_b rth->u.dst.flags= DST_HOST; if (in_dev->cnf.no_policy) rth->u.dst.flags |= DST_NOPOLICY; + rth->fl.host = host; rth->fl.fl4_dst = daddr; rth->rt_dst = daddr; rth->fl.fl4_tos = tos; @@ -1639,7 +1645,7 @@ static int ip_route_input_mc(struct sk_b #endif rth->rt_iif = rth->fl.iif = dev->ifindex; - rth->u.dst.dev = &init_host.loopback_dev; + rth->u.dst.dev = loopback_dev; dev_hold(rth->u.dst.dev); rth->idev = in_dev_get(rth->u.dst.dev); rth->fl.oif = 0; @@ -1771,6 +1777,7 @@ static inline int __mkroute_input(struct rth->u.dst.flags |= DST_NOPOLICY; if (in_dev->cnf.no_xfrm) rth->u.dst.flags |= DST_NOXFRM; + rth->fl.host = in_dev->dev->host; rth->fl.fl4_dst = daddr; rth->rt_dst = daddr; rth->fl.fl4_tos = tos; @@ -1900,7 +1907,8 @@ static int ip_route_input_slow(struct sk { struct fib_result res; struct in_device *in_dev = in_dev_get(dev); - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .host = dev->host, + .nl_u = { .ip4_u = { .daddr = daddr, .saddr = saddr, .tos = tos, @@ -1910,6 +1918,7 @@ static int ip_route_input_slow(struct sk #endif } }, .iif = dev->ifindex }; + struct net_device *loopback_dev = &fl.host->loopback_dev; unsigned flags = 0; u32 itag = 0; struct rtable * rth; @@ -1917,8 +1926,6 @@ static int ip_route_input_slow(struct sk u32 spec_dst; int err = -EINVAL; int free_res = 0; - struct nethost *host = NULL; - struct net_device *loopback_dev = &init_host.loopback_dev; /* IP on this device is disabled. */ @@ -1961,10 +1968,6 @@ static int ip_route_input_slow(struct sk if (res.type == RTN_LOCAL) { int result; - host = inet_host(dev, daddr); - if (!host) - goto martian_destination; - loopback_dev = &host->loopback_dev; result = fib_validate_source(saddr, daddr, tos, loopback_dev->ifindex, dev, &spec_dst, &itag); @@ -1997,9 +2000,8 @@ brd_input: if (skb->protocol != htons(ETH_P_IP)) goto e_inval; - host = NULL; if (ZERONET(saddr)) - spec_dst = inet_select_addr(NULL, dev, 0, RT_SCOPE_LINK); + spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); else { err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag); @@ -2023,6 +2025,7 @@ local_input: rth->u.dst.flags= DST_HOST; if (in_dev->cnf.no_policy) rth->u.dst.flags |= DST_NOPOLICY; + rth->fl.host = fl.host; rth->fl.fl4_dst = daddr; rth->rt_dst = daddr; rth->fl.fl4_tos = tos; @@ -2055,7 +2058,7 @@ local_input: no_route: RT_CACHE_STAT_INC(in_no_route); - spec_dst = inet_select_addr(NULL, dev, 0, RT_SCOPE_UNIVERSE); + spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); res.type = RTN_UNREACHABLE; goto local_input; @@ -2093,7 +2096,9 @@ int ip_route_input(struct sk_buff *skb, { struct rtable * rth; unsigned hash; + struct nethost *host = dev->host; int iif = dev->ifindex; + BUG_ON(!host); /* Be certain to catch unfixed code! */ tos &= IPTOS_RT_MASK; hash = rt_hash_code(daddr, saddr ^ (iif << 5), tos); @@ -2101,7 +2106,8 @@ int ip_route_input(struct sk_buff *skb, rcu_read_lock(); for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; rth = rcu_dereference(rth->u.rt_next)) { - if (rth->fl.fl4_dst == daddr && + if (rth->fl.host == host && + rth->fl.fl4_dst == daddr && rth->fl.fl4_src == saddr && rth->fl.iif == iif && rth->fl.oif == 0 && @@ -2156,7 +2162,7 @@ int ip_route_input(struct sk_buff *skb, } static inline int __mkroute_output(struct rtable **result, - struct fib_result* res, + struct fib_result* res, const struct flowi *fl, const struct flowi *oldflp, struct net_device *dev_out, @@ -2177,7 +2183,6 @@ static inline int __mkroute_output(struc else if (BADCLASS(fl->fl4_dst) || ZERONET(fl->fl4_dst)) return -EINVAL; - flags |= RTCF_OUTPUT; if (dev_out->flags & IFF_LOOPBACK) flags |= RTCF_LOCAL; @@ -2228,11 +2233,11 @@ static inline int __mkroute_output(struc if (in_dev->cnf.no_policy) rth->u.dst.flags |= DST_NOPOLICY; + rth->fl.host = oldflp->host; rth->fl.fl4_dst = oldflp->fl4_dst; rth->fl.fl4_tos = tos; rth->fl.fl4_src = oldflp->fl4_src; rth->fl.oif = oldflp->oif; - rth->fl.iif = oldflp->iif; #ifdef CONFIG_IP_ROUTE_FWMARK rth->fl.fl4_fwmark= oldflp->fl4_fwmark; #endif @@ -2377,7 +2382,9 @@ static inline int ip_mkroute_output(stru static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp) { u32 tos = RT_FL_TOS(oldflp); - struct flowi fl = { .nl_u = { .ip4_u = + struct net_device *loopback_dev = &oldflp->host->loopback_dev; + struct flowi fl = { .host = oldflp->host, + .nl_u = { .ip4_u = { .daddr = oldflp->fl4_dst, .saddr = oldflp->fl4_src, .tos = tos & IPTOS_RT_MASK, @@ -2388,10 +2395,8 @@ static int ip_route_output_slow(struct r .fwmark = oldflp->fl4_fwmark #endif } }, - .iif = oldflp->iif ? : init_host.loopback_dev.ifindex, + .iif = loopback_dev->ifindex, .oif = oldflp->oif }; - struct net_device *loopback_dev = NULL; - struct nethost *host = NULL; struct fib_result res; unsigned flags = 0; struct net_device *dev_out = NULL; @@ -2404,14 +2409,6 @@ static int ip_route_output_slow(struct r res.r = NULL; #endif - if (oldflp->iif) { - err = -ENODEV; - loopback_dev = dev_get_by_index(fl.iif); - host = loopback_host(loopback_dev); - if (!host) - goto out; - } - if (oldflp->fl4_src) { err = -EINVAL; if (MULTICAST(oldflp->fl4_src) || @@ -2419,16 +2416,9 @@ static int ip_route_output_slow(struct r ZERONET(oldflp->fl4_src)) goto out; - /* Loopback addresses must have a host to be used */ - if (!host && LOOPBACK(oldflp->fl4_src)) - goto out; - - /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL - * In addition we verify the source ip address is for the - * correct host. - */ - if (!inet_confirm_addr(host, NULL, 0, oldflp->fl4_src, - RT_SCOPE_NOWHERE)) + /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ + dev_out = ip_dev_find(fl.host, oldflp->fl4_src); + if (dev_out == NULL) goto out; /* I removed check for oif == dev_out->oif here. @@ -2456,18 +2446,17 @@ static int ip_route_output_slow(struct r Luckily, this hack is good workaround. */ - dev_out = ip_dev_find(oldflp->fl4_src); - if (dev_out == NULL) - goto out; - fl.oif = dev_out->ifindex; goto make_route; } + if (dev_out) + dev_put(dev_out); + dev_out = NULL; } if (oldflp->oif) { - dev_out = dev_get_by_index(oldflp->oif); + dev_out = dev_get_by_index(oldflp->host, oldflp->oif); err = -ENODEV; if (dev_out == NULL) goto out; @@ -2480,29 +2469,26 @@ static int ip_route_output_slow(struct r if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF) { if (!fl.fl4_src) - fl.fl4_src = inet_select_addr(host, dev_out, 0, + fl.fl4_src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); goto make_route; } if (!fl.fl4_src) { if (MULTICAST(oldflp->fl4_dst)) - fl.fl4_src = inet_select_addr(host, dev_out, 0, + fl.fl4_src = inet_select_addr(dev_out, 0, fl.fl4_scope); else if (!oldflp->fl4_dst) - fl.fl4_src = inet_select_addr(host, dev_out, 0, + fl.fl4_src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST); } } if (!fl.fl4_dst) { - if (dev_out) - dev_put(dev_out); - err = -EINVAL; - if (!host) - goto out; fl.fl4_dst = fl.fl4_src; if (!fl.fl4_dst) fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK); + if (dev_out) + dev_put(dev_out); dev_out = loopback_dev; dev_hold(dev_out); fl.oif = loopback_dev->ifindex; @@ -2533,7 +2519,7 @@ static int ip_route_output_slow(struct r */ if (fl.fl4_src == 0) - fl.fl4_src = inet_select_addr(host, dev_out, 0, + fl.fl4_src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); res.type = RTN_UNICAST; goto make_route; @@ -2546,45 +2532,11 @@ static int ip_route_output_slow(struct r free_res = 1; if (res.type == RTN_LOCAL) { - struct nethost *dest_host; - /* Special case for loopback addresses. - * - * Routing decisions in general and fib_loopup in particular - * make decisions based upon the destination address. - * - * In the context of multiple hosts each host has its - * own loopback interface. Each loopback interface is - * configured with the same loopback address. Therefore - * we need to know which host we are starting from - * to stay there. The destination address which fib_lookup - * uses is not enough information. - * - * Luckily this is easy. - */ - if (LOOPBACK(fl.fl4_dst)) - dest_host = host; - else - dest_host = inet_host(FIB_RES_DEV(res), fl.fl4_dst); - BUG_ON(!dest_host); - if (!fl.fl4_src) { - if (!host || (dest_host == host)) - fl.fl4_src = fl.fl4_dst; - else { - if (res.scope >= RT_SCOPE_HOST) - res.scope = RT_SCOPE_LINK; - fl.fl4_src = FIB_RES_PREFSRC(host, res); - } - } - /* If fl.fl4_src is still 0 it is technically an error. - * However this only occurs if we don't have a valid - * source address we can use. Further protocols like - * DHCP expect 0 to be used as your source address when - * no source address is known. So we can't return - * an error here :( - */ + if (!fl.fl4_src) + fl.fl4_src = fl.fl4_dst; if (dev_out) dev_put(dev_out); - dev_out = &dest_host->loopback_dev; + dev_out = loopback_dev; dev_hold(dev_out); fl.oif = dev_out->ifindex; if (res.fi) @@ -2603,7 +2555,7 @@ static int ip_route_output_slow(struct r fib_select_default(&fl, &res); if (!fl.fl4_src) - fl.fl4_src = FIB_RES_PREFSRC(host, res); + fl.fl4_src = FIB_RES_PREFSRC(res); if (dev_out) dev_put(dev_out); @@ -2620,25 +2572,24 @@ make_route: fib_res_put(&res); if (dev_out) dev_put(dev_out); -out: - if (loopback_dev) - dev_put(loopback_dev); - return err; +out: return err; } int __ip_route_output_key(struct rtable **rp, const struct flowi *flp) { unsigned hash; struct rtable *rth; + BUG_ON(!flp->host); /* Be certain to catch unfixed code! */ hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5), flp->fl4_tos); rcu_read_lock_bh(); for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; rth = rcu_dereference(rth->u.rt_next)) { - if (rth->fl.fl4_dst == flp->fl4_dst && + if (rth->fl.host == flp->host && + rth->fl.fl4_dst == flp->fl4_dst && rth->fl.fl4_src == flp->fl4_src && - rth->fl.iif == flp->iif && + rth->fl.iif == 0 && rth->fl.oif == flp->oif && #ifdef CONFIG_IP_ROUTE_FWMARK rth->fl.fl4_fwmark == flp->fl4_fwmark && @@ -2740,7 +2691,7 @@ static int rt_fill_info(struct sk_buff * RTA_PUT(skb, RTA_MP_ALGO, 4, &alg); } #endif - if (!(rt->rt_flags & RTCF_OUTPUT)) + if (rt->fl.iif) RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst); else if (rt->rt_src != rt->fl.fl4_src) RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src); @@ -2810,6 +2761,7 @@ int inet_rtm_getroute(struct sk_buff *in int iif = 0; int err = -ENOBUFS; struct sk_buff *skb; + struct nethost *host = in_skb->sk->sk_host; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) @@ -2829,7 +2781,7 @@ int inet_rtm_getroute(struct sk_buff *in memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int)); if (iif) { - struct net_device *dev = __dev_get_by_index(iif); + struct net_device *dev = __dev_get_by_index(host, iif); err = -ENODEV; if (!dev) goto out_free; @@ -2842,7 +2794,7 @@ int inet_rtm_getroute(struct sk_buff *in if (!err && rt->u.dst.error) err = -rt->u.dst.error; } else { - struct flowi fl = { .iif = in_skb->sk->sk_host->loopback_dev.ifindex, + struct flowi fl = { .host = host, .nl_u = { .ip4_u = { .daddr = dst, .saddr = src, .tos = rtm->rtm_tos } } }; @@ -2882,6 +2834,7 @@ out_free: int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) { + struct nethost *host = skb->sk->sk_host; struct rtable *rt; int h, s_h; int idx, s_idx; @@ -2894,8 +2847,10 @@ int ip_rt_dump(struct sk_buff *skb, str s_idx = 0; rcu_read_lock_bh(); for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt; - rt = rcu_dereference(rt->u.rt_next), idx++) { - if (idx < s_idx) + rt = rcu_dereference(rt->u.rt_next)) { + if (rt->fl.host != host) + continue; + if (idx++ < s_idx) continue; skb->dst = dst_clone(&rt->u.dst); if (rt_fill_info(skb, NETLINK_CB(cb->skb).pid, diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 1107de0..3423a42 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -231,7 +231,7 @@ struct sock *cookie_v4_check(struct sock int opt_size = sizeof(struct ip_options) + opt->optlen; ireq->opt = kmalloc(opt_size, GFP_ATOMIC); - if (ireq->opt != NULL && ip_options_echo(ireq->opt, skb)) { + if (ireq->opt != NULL && ip_options_echo(ireq->opt, skb, sk->sk_host)) { kfree(ireq->opt); ireq->opt = NULL; } @@ -249,7 +249,7 @@ struct sock *cookie_v4_check(struct sock * no easy way to do this. */ { - struct flowi fl = { .iif = sk->sk_host->loopback_dev.ifindex, + struct flowi fl = { .host = sk->sk_host, .nl_u = { .ip4_u = { .daddr = ((opt && opt->srr) ? opt->faddr : diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fff3b41..430a4fd 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -497,7 +497,7 @@ static inline void do_pmtu_discovery(str * */ -void tcp_v4_err(struct sk_buff *skb, struct nethost *host, u32 info) +void tcp_v4_err(struct sk_buff *skb, u32 info) { struct iphdr *iph = (struct iphdr *)skb->data; struct tcphdr *th = (struct tcphdr *)(skb->data + (iph->ihl << 2)); @@ -515,7 +515,7 @@ void tcp_v4_err(struct sk_buff *skb, str } sk = inet_lookup(&tcp_hashinfo, iph->daddr, th->dest, iph->saddr, - th->source, inet_iif(skb), host); + th->source, inet_iif(skb), skb->dev->host); if (!sk) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; @@ -854,7 +854,7 @@ static inline struct ip_options *tcp_v4_ int opt_size = optlength(opt); dopt = kmalloc(opt_size, GFP_ATOMIC); if (dopt) { - if (ip_options_echo(dopt, skb)) { + if (ip_options_echo(dopt, skb, sk->sk_host)) { kfree(dopt); dopt = NULL; } @@ -1239,7 +1239,7 @@ int tcp_v4_rcv(struct sk_buff *skb) rt = (struct rtable*)skb->dst; sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source, skb->nh.iph->daddr, ntohs(th->dest), - inet_iif(skb), rt_dhost(rt)); + inet_iif(skb), rt->fl.host); if (!sk) goto no_tcp_socket; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f4255f3..53d5476 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -322,7 +322,7 @@ found: * to find the appropriate port. */ -void udp_err(struct sk_buff *skb, struct nethost *host, u32 info) +void udp_err(struct sk_buff *skb, u32 info) { struct inet_sock *inet; struct iphdr *iph = (struct iphdr*)skb->data; @@ -334,7 +334,7 @@ void udp_err(struct sk_buff *skb, struct int err; sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, - skb->dev->ifindex, host); + skb->dev->ifindex, skb->dev->host); if (sk == NULL) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; /* No socket for error */ @@ -561,7 +561,7 @@ int udp_sendmsg(struct kiocb *iocb, stru ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(msg, &ipc); + err = ip_cmsg_send(msg, &ipc, sk->sk_host); if (err) return err; if (ipc.opt) @@ -600,7 +600,7 @@ int udp_sendmsg(struct kiocb *iocb, stru rt = (struct rtable*)sk_dst_check(sk, 0); if (rt == NULL) { - struct flowi fl = { .iif = sk->sk_host->loopback_dev.ifindex, + struct flowi fl = { .host = sk->sk_host, .oif = ipc.oif, .nl_u = { .ip4_u = { .daddr = faddr, @@ -1158,7 +1158,7 @@ int udp_rcv(struct sk_buff *skb) return udp_v4_mcast_deliver(skb, uh, saddr, daddr); sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, - skb->dev->ifindex, rt_dhost(rt)); + skb->dev->ifindex, rt->fl.host); if (sk != NULL) { int ret = udp_queue_rcv_skb(sk, skb); diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 2d3849c..48cefb0 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -63,7 +63,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, if (xfrm_nr == XFRM_MAX_DEPTH) goto drop; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, iph->protocol, AF_INET); + x = xfrm_state_lookup(skb->dev->host, (xfrm_address_t *)&iph->daddr, + spi, iph->protocol, AF_INET); if (x == NULL) goto drop; diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index af33399..7eb9d65 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -276,7 +276,7 @@ static void xfrm4_dst_ifdown(struct dst_ xdst = (struct xfrm_dst *)dst; if (xdst->u.rt.idev->dev == dev) { - struct in_device *loopback_idev = in_dev_get(&init_host.loopback_dev); + struct in_device *loopback_idev = in_dev_get(&dev->host->loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index d23e07f..6d8db9b 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c @@ -48,7 +48,7 @@ __xfrm4_init_tempsel(struct xfrm_state * } static struct xfrm_state * -__xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) +__xfrm4_state_lookup(struct nethost *host, xfrm_address_t *daddr, u32 spi, u8 proto) { unsigned h = __xfrm4_spi_hash(daddr, spi, proto); struct xfrm_state *x; @@ -57,7 +57,8 @@ __xfrm4_state_lookup(xfrm_address_t *dad if (x->props.family == AF_INET && spi == x->id.spi && daddr->a4 == x->id.daddr.a4 && - proto == x->id.proto) { + proto == x->id.proto && + host == x->host) { xfrm_state_hold(x); return x; } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3a44096..587059c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -130,7 +130,6 @@ static DEFINE_SPINLOCK(addrconf_verify_l static void addrconf_join_anycast(struct inet6_ifaddr *ifp); static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); -static void addrconf_flush_host(struct nethost *host); static int addrconf_ifdown(struct net_device *dev, int how); static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); @@ -142,9 +141,7 @@ static void ipv6_ifa_notify(int event, s static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo); -static int ipv6_chk_same_host_addr(const struct in6_addr *addr, - struct net_device *dev, - struct nethost *host); +static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev); static struct notifier_block *inet6addr_chain; @@ -495,7 +492,7 @@ void inet6_ifa_finish_destroy(struct ine /* On success it returns ifp with increased reference count */ static struct inet6_ifaddr * -ipv6_add_addr(struct nethost *host, struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, +ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, int scope, u32 flags) { struct inet6_ifaddr *ifa = NULL; @@ -512,21 +509,12 @@ ipv6_add_addr(struct nethost *host, stru write_lock(&addrconf_hash_lock); /* Ignore adding duplicate addresses on an interface */ - /* Deny adding global addresses already used by another host */ - if (ipv6_chk_same_host_addr(addr, idev->dev, host)) { + if (ipv6_chk_same_addr(addr, idev->dev)) { ADBG(("ipv6_add_addr: already assigned\n")); err = -EEXIST; goto out; } - /* Deny adding addresses owned by other hosts to the loopback device */ - if ((idev->dev->flags & IFF_LOOPBACK) && - (idev->dev != &host->loopback_dev)) { - ADBG(("ipv6_add_addr: wrong host using loopback\n")); - err = -EINVAL; - goto out; - } - ifa = kmalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC); if (ifa == NULL) { @@ -535,14 +523,13 @@ ipv6_add_addr(struct nethost *host, stru goto out; } - rt = addrconf_dst_alloc(idev, host, addr); + rt = addrconf_dst_alloc(idev, addr, 0); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto out; } memset(ifa, 0, sizeof(struct inet6_ifaddr)); - ifa->host = host; ipv6_addr_copy(&ifa->addr, addr); spin_lock_init(&ifa->lock); @@ -790,7 +777,7 @@ retry: write_unlock(&idev->lock); ift = !max_addresses || ipv6_count_addresses(idev) < max_addresses ? - ipv6_add_addr(ifp->host, idev, &addr, tmp_plen, + ipv6_add_addr(idev, &addr, tmp_plen, ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL; if (!ift || IS_ERR(ift)) { in6_ifa_put(ifp); @@ -861,16 +848,14 @@ int ipv6_dev_get_saddr(struct nethost *h if (dev) { if ((dev->flags & IFF_LOOPBACK) && - (!host || (dev == &host->loopback_dev))) + (dev == &host->loopback_dev)) scope = IFA_HOST; read_lock(&addrconf_lock); idev = __in6_dev_get(dev); - if (idev) { + if (idev && dev->host == host) { read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { - if (host && ifp->host != host) - continue; if (ifp->scope == scope) { if (ifp->flags&IFA_F_TENTATIVE) continue; @@ -910,12 +895,12 @@ int ipv6_dev_get_saddr(struct nethost *h read_lock(&dev_base_lock); read_lock(&addrconf_lock); for (dev = dev_base; dev; dev=dev->next) { + if (dev->host != host) + continue; idev = __in6_dev_get(dev); if (idev) { read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { - if (host && ifp->host != host) - continue; if (ifp->scope == scope) { if (ifp->flags&IFA_F_TENTATIVE) continue; @@ -1001,16 +986,13 @@ static int ipv6_count_addresses(struct i return cnt; } -int ipv6_chk_addr(struct nethost *host, struct in6_addr *addr, - struct net_device *dev, int strict) +int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int strict) { 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 (host && (host != ifp->host)) - continue; if (ipv6_addr_equal(&ifp->addr, addr) && !(ifp->flags&IFA_F_TENTATIVE)) { if (dev == NULL || ifp->idev->dev == dev || @@ -1023,8 +1005,7 @@ int ipv6_chk_addr(struct nethost *host, } static -int ipv6_chk_same_host_addr(const struct in6_addr *addr, struct net_device *dev, - struct nethost *host) +int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev) { struct inet6_ifaddr * ifp; u8 hash = ipv6_addr_hash(addr); @@ -1033,9 +1014,6 @@ int ipv6_chk_same_host_addr(const struct if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev) break; - if (host && (ifp->host != host) && - !(ifp->scope & (IFA_LINK|IFA_HOST))) - break; } } return ifp != NULL; @@ -1219,15 +1197,13 @@ static int ipv6_generate_eui64(u8 *eui, return -1; } -static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev, struct nethost *host) +static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) { int err = -1; struct inet6_ifaddr *ifp; read_lock_bh(&idev->lock); for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { - if (ifp->host != host) - continue; if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { memcpy(eui, ifp->addr.s6_addr+8, 8); err = 0; @@ -1368,7 +1344,7 @@ addrconf_prefix_route(struct in6_addr *p if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT)) rtmsg.rtmsg_flags |= RTF_NONEXTHOP; - ip6_route_add(&rtmsg, NULL, NULL, NULL); + ip6_route_add(dev->host, &rtmsg, NULL, NULL, NULL); } /* Create "default" multicast route to the interface */ @@ -1385,7 +1361,7 @@ static void addrconf_add_mroute(struct n rtmsg.rtmsg_ifindex = dev->ifindex; rtmsg.rtmsg_flags = RTF_UP; rtmsg.rtmsg_type = RTMSG_NEWROUTE; - ip6_route_add(&rtmsg, NULL, NULL, NULL); + ip6_route_add(dev->host, &rtmsg, NULL, NULL, NULL); } static void sit_route_add(struct net_device *dev) @@ -1402,7 +1378,7 @@ static void sit_route_add(struct net_dev rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; rtmsg.rtmsg_ifindex = dev->ifindex; - ip6_route_add(&rtmsg, NULL, NULL, NULL); + ip6_route_add(dev->host, &rtmsg, NULL, NULL, NULL); } static void addrconf_add_lroute(struct net_device *dev) @@ -1519,7 +1495,7 @@ void addrconf_prefix_rcv(struct net_devi if (pinfo->prefix_len == 64) { memcpy(&addr, &pinfo->prefix, 8); if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && - ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev, &init_host)) { + ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { in6_dev_put(in6_dev); return; } @@ -1543,7 +1519,7 @@ ok: */ if (!max_addresses || ipv6_count_addresses(in6_dev) < max_addresses) - ifp = ipv6_add_addr(&init_host, in6_dev, &addr, pinfo->prefix_len, + ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, addr_type&IPV6_ADDR_SCOPE_MASK, 0); if (!ifp || IS_ERR(ifp)) { @@ -1660,7 +1636,7 @@ int addrconf_set_dstaddr(void __user *ar if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) goto err_exit; - dev = __dev_get_by_index(ireq.ifr6_ifindex); + dev = __dev_get_by_index(current->host, ireq.ifr6_ifindex); err = -ENODEV; if (dev == NULL) @@ -1675,7 +1651,6 @@ int addrconf_set_dstaddr(void __user *ar if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4)) goto err_exit; - /* FIXME current->host */ memset(&p, 0, sizeof(p)); p.iph.daddr = ireq.ifr6_addr.s6_addr32[3]; p.iph.saddr = 0; @@ -1691,7 +1666,7 @@ int addrconf_set_dstaddr(void __user *ar if (err == 0) { err = -ENOBUFS; - if ((dev = __dev_get_by_name(p.name)) == NULL) + if ((dev = __dev_get_by_name(current->host, p.name)) == NULL) goto err_exit; err = dev_open(dev); } @@ -1714,7 +1689,7 @@ static int inet6_addr_add(struct nethost ASSERT_RTNL(); - if ((dev = __dev_get_by_index(ifindex)) == NULL) + if ((dev = __dev_get_by_index(host, ifindex)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) @@ -1725,7 +1700,7 @@ static int inet6_addr_add(struct nethost scope = ipv6_addr_scope(pfx); - ifp = ipv6_add_addr(host, idev, pfx, plen, scope, IFA_F_PERMANENT); + ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { addrconf_dad_start(ifp, 0); in6_ifa_put(ifp); @@ -1741,7 +1716,7 @@ static int inet6_addr_del(struct nethost struct inet6_dev *idev; struct net_device *dev; - if ((dev = __dev_get_by_index(ifindex)) == NULL) + if ((dev = __dev_get_by_index(host, ifindex)) == NULL) return -ENODEV; if ((idev = __in6_dev_get(dev)) == NULL) @@ -1749,8 +1724,6 @@ static int inet6_addr_del(struct nethost read_lock_bh(&idev->lock); for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) { - if (ifp->host != host) - continue; if (ifp->prefix_len == plen && ipv6_addr_equal(pfx, &ifp->addr)) { in6_ifa_hold(ifp); @@ -1825,7 +1798,7 @@ static void sit_add_v4_addrs(struct inet } if (addr.s6_addr32[3]) { - ifp = ipv6_add_addr(&init_host, idev, &addr, 128, scope, IFA_F_PERMANENT); + ifp = ipv6_add_addr(idev, &addr, 128, scope, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; @@ -1860,7 +1833,7 @@ static void sit_add_v4_addrs(struct inet else plen = 96; - ifp = ipv6_add_addr(&init_host, idev, &addr, plen, flag, + ifp = ipv6_add_addr(idev, &addr, plen, flag, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); @@ -1878,7 +1851,6 @@ static void init_loopback(struct net_dev { struct inet6_dev *idev; struct inet6_ifaddr * ifp; - struct nethost *host; /* ::1 */ @@ -1889,8 +1861,7 @@ static void init_loopback(struct net_dev return; } - host = container_of(dev, struct nethost, loopback_dev); - ifp = ipv6_add_addr(host, idev, &in6addr_loopback, 128, IFA_HOST, IFA_F_PERMANENT); + ifp = ipv6_add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; @@ -1904,7 +1875,7 @@ static void addrconf_add_linklocal(struc { struct inet6_ifaddr * ifp; - ifp = ipv6_add_addr(&init_host, idev, addr, 64, IFA_LINK, IFA_F_PERMANENT); + ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { addrconf_dad_start(ifp, 0); in6_ifa_put(ifp); @@ -1979,15 +1950,18 @@ ipv6_inherit_linklocal(struct inet6_dev static void ip6_tnl_add_linklocal(struct inet6_dev *idev) { struct net_device *link_dev; + struct nethost *host = idev->dev->host; /* first try to inherit the link-local address from the link device */ if (idev->dev->iflink && - (link_dev = __dev_get_by_index(idev->dev->iflink))) { + (link_dev = __dev_get_by_index(host, idev->dev->iflink))) { if (!ipv6_inherit_linklocal(idev, link_dev)) return; } /* then try to inherit it from any device */ for (link_dev = dev_base; link_dev; link_dev = link_dev->next) { + if (link_dev->host != host) + continue; if (!ipv6_inherit_linklocal(idev, link_dev)) return; } @@ -2064,10 +2038,8 @@ static int addrconf_notify(struct notifi /* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */ - case NETDEV_UNREGISTER: - addrconf_flush_host(loopback_host(dev)); - /* fall through */ case NETDEV_DOWN: + case NETDEV_UNREGISTER: /* * Remove all addresses from this interface. */ @@ -2101,41 +2073,6 @@ static struct notifier_block ipv6_dev_no .priority = 0 }; - -static void addrconf_flush_host(struct nethost *host) -{ - struct inet6_ifaddr *ifa, **bifa; - int i; - if (!host) - return; - for (i = 0; i < IN6_ADDR_HSIZE; i++) { -restart: - bifa = &inet6_addr_lst[i]; - read_lock_bh(&addrconf_hash_lock); - while ((ifa = *bifa) != NULL) { - if (ifa->host == host) { - struct inet6_dev *idev; - idev = ifa->idev; - in6_ifa_hold(ifa); - read_unlock_bh(&addrconf_hash_lock); - - ipv6_del_addr(ifa); - - /* If the last address is deleted administratively, - disable IPv6 on this interface. - */ - if (idev->addr_list == NULL) { - addrconf_ifdown(idev->dev, 1); - } - goto restart; - } - bifa = &ifa->lst_next; - } - read_unlock_bh(&addrconf_hash_lock); - - } -} - static int addrconf_ifdown(struct net_device *dev, int how) { struct inet6_dev *idev; @@ -2147,6 +2084,21 @@ static int addrconf_ifdown(struct net_de if (dev == &init_host.loopback_dev && how == 1) how = 0; +#if 1 + idev = __in6_dev_get(dev); + if (idev) { + read_lock_bh(&idev->lock); + while ((ifa = idev->addr_list) != NULL) { + in6_ifa_hold(ifa); + read_unlock_bh(&idev->lock); + + ipv6_del_addr(ifa); + + read_lock_bh(&idev->lock); + } + read_unlock_bh(&idev->lock); + } +#endif rt6_ifdown(dev); neigh_ifdown(&nd_tbl, dev); @@ -2427,7 +2379,7 @@ static struct inet6_ifaddr *if6_get_firs for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { ifa = inet6_addr_lst[state->bucket]; - while (ifa && ifa->host != state->host) + while (ifa && ifa->idev->dev->host != state->host) ifa = ifa->lst_next; if (ifa) break; @@ -2441,7 +2393,7 @@ static struct inet6_ifaddr *if6_get_next ifa = ifa->lst_next; try_again: - while (ifa && ifa->host != state->host) + while (ifa && ifa->idev->dev->host != state->host) ifa = ifa->lst_next; if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) { ifa = inet6_addr_lst[state->bucket]; @@ -2844,6 +2796,8 @@ static int inet6_dump_addr(struct sk_buf read_lock(&dev_base_lock); for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { + if (dev->host != host) + continue; if (idx < s_idx) continue; if (idx > s_idx) @@ -2859,8 +2813,6 @@ static int inet6_dump_addr(struct sk_buf ifa = ifa->if_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; - if (ifa->host != host) - continue; if ((err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR, @@ -2946,7 +2898,7 @@ static void inet6_ifa_notify(int event, return; } NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFADDR; - netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFADDR, GFP_ATOMIC); + netlink_broadcast(rtnl, skb, ifa->idev->dev->host, 0, RTNLGRP_IPV6_IFADDR, GFP_ATOMIC); } static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, @@ -3082,7 +3034,7 @@ void inet6_ifinfo_notify(int event, stru return; } NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFINFO; - netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFINFO, GFP_ATOMIC); + netlink_broadcast(rtnl, skb, idev->dev->host, 0, RTNLGRP_IPV6_IFINFO, GFP_ATOMIC); } static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, @@ -3142,7 +3094,7 @@ static void inet6_prefix_notify(int even return; } NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_PREFIX; - netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_PREFIX, GFP_ATOMIC); + netlink_broadcast(rtnl, skb, idev->dev->host, 0, RTNLGRP_IPV6_PREFIX, GFP_ATOMIC); } static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 3168359..42a5348 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -57,6 +57,7 @@ #include #include #include +#include #ifdef CONFIG_IPV6_TUNNEL #include #endif @@ -83,6 +84,33 @@ static __inline__ struct ipv6_pinfo *ine return (struct ipv6_pinfo *)(((u8 *)sk) + offset); } +/* + * Initialize the per host ipv4 state. + */ +static int inet6_host_init(struct nethost *host) +{ + /* FIXME flesh me out */ + struct ip6_host *ihost; + ihost = kzalloc(sizeof(*ihost), GFP_KERNEL); + if (!ihost) + return -ENOMEM; + ihost->host = host; + host->ip6_host = ihost; + return 0; +} + +/* + * Cleanup the per host ipv4 state. + */ + +static void inet6_host_fini(struct nethost *host) +{ + struct ip6_host *ihost; + ihost = host->ip6_host; + host->ip6_host = NULL; + kfree(ihost); +} + static int inet6_create(struct socket *sock, int protocol) { struct inet_sock *inet; @@ -147,8 +175,6 @@ static int inet6_create(struct socket *s sock_init_data(sock, sk); rc = 0; - sk->sk_host = current->host; - get_host(sk->sk_host); sk->sk_no_check = answer_no_check; if (INET_PROTOSW_REUSE & answer_flags) sk->sk_reuse = 1; @@ -259,7 +285,7 @@ int inet6_bind(struct socket *sock, stru /* Check if the address belongs to the host. */ if (addr_type == IPV6_ADDR_MAPPED) { v4addr = addr->sin6_addr.s6_addr32[3]; - if (inet_addr_type(v4addr) != RTN_LOCAL) { + if (inet_addr_type(sk->sk_host, v4addr) != RTN_LOCAL) { err = -EADDRNOTAVAIL; goto out; } @@ -281,7 +307,7 @@ int inet6_bind(struct socket *sock, stru err = -EINVAL; goto out; } - dev = dev_get_by_index(sk->sk_bound_dev_if); + dev = dev_get_by_index(sk->sk_host, sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; goto out; @@ -293,7 +319,7 @@ int inet6_bind(struct socket *sock, stru */ v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { - if (!ipv6_chk_addr(sk->sk_host, &addr->sin6_addr, + if (!ipv6_chk_addr(&addr->sin6_addr, dev, 0)) { if (dev) dev_put(dev); @@ -490,10 +516,11 @@ struct proto_ops inet6_dgram_ops = { }; static struct net_proto_family inet6_family_ops = { - .family = PF_INET6, - .create = inet6_create, - .multi_host = 1, - .owner = THIS_MODULE, + .family = PF_INET6, + .host_init = inet6_host_init, + .host_fini = inet6_host_fini, + .create = inet6_create, + .owner = THIS_MODULE, }; /* Same as inet6_dgram_ops, sans udp_poll. */ diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index f362973..ee7f2fd 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -319,6 +319,7 @@ out: static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info) { + struct nethost *host = skb->dev->host; struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset); struct xfrm_state *x; @@ -327,7 +328,7 @@ static void ah6_err(struct sk_buff *skb, type != ICMPV6_PKT_TOOBIG) return; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); + x = xfrm_state_lookup(host, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); if (!x) return; diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index baf401d..8d4fe4a 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -89,7 +89,7 @@ int ipv6_sock_ac_join(struct sock *sk, i return -EPERM; if (ipv6_addr_is_multicast(addr)) return -EINVAL; - if (ipv6_chk_addr(NULL, addr, NULL, 0)) + if (ipv6_chk_addr(addr, NULL, 0)) return -EINVAL; pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL); @@ -112,10 +112,10 @@ int ipv6_sock_ac_join(struct sock *sk, i } else { /* router, no matching interface: just pick one */ - dev = dev_get_by_flags(IFF_UP, IFF_UP|IFF_LOOPBACK); + dev = dev_get_by_flags(sk->sk_host, IFF_UP, IFF_UP|IFF_LOOPBACK); } } else - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(sk->sk_host, ifindex); if (dev == NULL) { err = -ENODEV; @@ -196,7 +196,7 @@ int ipv6_sock_ac_drop(struct sock *sk, i write_unlock_bh(&ipv6_sk_ac_lock); - dev = dev_get_by_index(pac->acl_ifindex); + dev = dev_get_by_index(sk->sk_host, pac->acl_ifindex); if (dev) { ipv6_dev_ac_dec(dev, &pac->acl_addr); dev_put(dev); @@ -224,7 +224,7 @@ void ipv6_sock_ac_close(struct sock *sk) if (pac->acl_ifindex != prev_index) { if (dev) dev_put(dev); - dev = dev_get_by_index(pac->acl_ifindex); + dev = dev_get_by_index(sk->sk_host, pac->acl_ifindex); prev_index = pac->acl_ifindex; } if (dev) @@ -314,7 +314,7 @@ int ipv6_dev_ac_inc(struct net_device *d goto out; } - rt = addrconf_dst_alloc(idev, NULL, addr); + rt = addrconf_dst_alloc(idev, addr, 1); if (IS_ERR(rt)) { kfree(aca); err = PTR_ERR(rt); diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index a42d5a4..ef2253e 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -148,7 +148,7 @@ ipv4_connected: fl.proto = sk->sk_protocol; ipv6_addr_copy(&fl.fl6_dst, &np->daddr); ipv6_addr_copy(&fl.fl6_src, &np->saddr); - fl.iif = sk->sk_host->loopback_dev.ifindex; + fl.host = sk->sk_host, fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = inet->dport; fl.fl_ip_sport = inet->sport; @@ -529,12 +529,12 @@ int datagram_send_ctl(struct msghdr *msg if (!src_info->ipi6_ifindex) return -EINVAL; else { - dev = dev_get_by_index(src_info->ipi6_ifindex); + dev = dev_get_by_index(host, src_info->ipi6_ifindex); if (!dev) return -ENODEV; } } - if (!ipv6_chk_addr(host, &src_info->ipi6_addr, dev, 0)) { + if (!ipv6_chk_addr(&src_info->ipi6_addr, dev, 0)) { if (dev) dev_put(dev); err = -EINVAL; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 9b27460..51095b6 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -252,6 +252,7 @@ static u32 esp6_get_max_size(struct xfrm static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info) { + struct nethost *host = skb->dev->host; struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; struct ipv6_esp_hdr *esph = (struct ipv6_esp_hdr*)(skb->data+offset); struct xfrm_state *x; @@ -260,7 +261,7 @@ static void esp6_err(struct sk_buff *skb type != ICMPV6_PKT_TOOBIG) return; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); + x = xfrm_state_lookup(host, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); if (!x) return; printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/" diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index ae3f412..e7efcba 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -301,7 +301,7 @@ void icmpv6_send(struct sk_buff *skb, in */ addr_type = ipv6_addr_type(&hdr->daddr); - if (ipv6_chk_addr(NULL, &hdr->daddr, skb->dev, 0)) + if (ipv6_chk_addr(&hdr->daddr, skb->dev, 0)) saddr = &hdr->daddr; /* @@ -349,7 +349,7 @@ void icmpv6_send(struct sk_buff *skb, in ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr); if (saddr) ipv6_addr_copy(&fl.fl6_src, saddr); - fl.iif = skb->dst->dev->ifindex; + fl.host = skb->dst->dev->host, fl.oif = iif; fl.fl_icmp_type = type; fl.fl_icmp_code = code; @@ -454,7 +454,7 @@ static void icmpv6_echo_reply(struct sk_ ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr); if (saddr) ipv6_addr_copy(&fl.fl6_src, saddr); - fl.iif = skb->dst->dev->ifindex; + fl.host = skb->dst->dev->host; fl.oif = skb->dev->ifindex; fl.fl_icmp_type = ICMPV6_ECHO_REPLY; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 4fcc5a7..a0e15bf 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -394,7 +394,7 @@ insert_above: */ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, - struct nlmsghdr *nlh, struct netlink_skb_parms *req) + struct nlmsghdr *nlh, struct sk_buff *in_skb) { struct rt6_info *iter = NULL; struct rt6_info **ins; @@ -449,7 +449,7 @@ out: *ins = rt; rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); - inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req); + inet6_rt_notify(RTM_NEWROUTE, rt, nlh, in_skb); rt6_stats.fib_rt_entries++; if ((fn->fn_flags & RTN_RTINFO) == 0) { @@ -480,7 +480,7 @@ void fib6_force_start_gc(void) */ int fib6_add(struct fib6_node *root, struct rt6_info *rt, - struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) + struct nlmsghdr *nlh, void *_rtattr, struct sk_buff *in_skb) { struct fib6_node *fn; int err = -ENOMEM; @@ -553,7 +553,7 @@ int fib6_add(struct fib6_node *root, str } #endif - err = fib6_add_rt2node(fn, rt, nlh, req); + err = fib6_add_rt2node(fn, rt, nlh, in_skb); if (err == 0) { fib6_start_gc(rt); @@ -860,7 +860,7 @@ static struct fib6_node * fib6_repair_tr } static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, - struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) + struct nlmsghdr *nlh, void *_rtattr, struct sk_buff *in_skb) { struct fib6_walker_t *w; struct rt6_info *rt = *rtp; @@ -916,11 +916,11 @@ static void fib6_del_route(struct fib6_n if (atomic_read(&rt->rt6i_ref) != 1) BUG(); } - inet6_rt_notify(RTM_DELROUTE, rt, nlh, req); + inet6_rt_notify(RTM_DELROUTE, rt, nlh, in_skb); rt6_release(rt); } -int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) +int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct sk_buff *in_skb) { struct fib6_node *fn = rt->rt6i_node; struct rt6_info **rtp; @@ -945,7 +945,7 @@ int fib6_del(struct rt6_info *rt, struct for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { if (*rtp == rt) { - fib6_del_route(fn, rtp, nlh, _rtattr, req); + fib6_del_route(fn, rtp, nlh, _rtattr, in_skb); return 0; } } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index f2b840e..3cdba47 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -763,8 +763,7 @@ int ip6_dst_lookup(struct sock *sk, stru goto out_err_release; if (ipv6_addr_any(&fl->fl6_src)) { - struct nethost *host = ifindex_host(fl->iif); - err = ipv6_get_saddr(host, *dst, &fl->fl6_dst, &fl->fl6_src); + err = ipv6_get_saddr(fl->host, *dst, &fl->fl6_dst, &fl->fl6_src); if (err) goto out_err_release; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index e511209..701ec1f 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -233,7 +233,7 @@ ip6_tnl_create(struct ip6_tnl_parm *p, s int i; for (i = 1; i < IP6_TNL_MAX; i++) { sprintf(name, "ip6tnl%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(current->host, name) == NULL) break; } if (i == IP6_TNL_MAX) @@ -286,7 +286,8 @@ ip6ip6_tnl_locate(struct ip6_tnl_parm *p for (t = *ip6ip6_bucket(p); t; t = t->next) { if (ipv6_addr_equal(local, &t->parms.laddr) && - ipv6_addr_equal(remote, &t->parms.raddr)) { + ipv6_addr_equal(remote, &t->parms.raddr) && + t->dev->host == current->host) { *pt = t; return (create ? -EEXIST : 0); } @@ -796,12 +797,12 @@ static void ip6_tnl_set_cap(struct ip6_t int r_ok = 1; if (p->link) - ldev = dev_get_by_index(p->link); + ldev = dev_get_by_index(t->dev->host, p->link); - if (ltype&IPV6_ADDR_UNICAST && !ipv6_chk_addr(NULL, laddr, ldev, 0)) + if (ltype&IPV6_ADDR_UNICAST && !ipv6_chk_addr(laddr, ldev, 0)) l_ok = 0; - if (rtype&IPV6_ADDR_UNICAST && ipv6_chk_addr(NULL, raddr, NULL, 0)) + if (rtype&IPV6_ADDR_UNICAST && ipv6_chk_addr(raddr, NULL, 0)) r_ok = 0; if (l_ok && r_ok) { diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 85bfbc6..fad63d7 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -200,6 +200,7 @@ static void ipcomp6_err(struct sk_buff * int type, int code, int offset, __u32 info) { u32 spi; + struct nethost *host = skb->dev->host; struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; struct ipv6_comp_hdr *ipcomph = (struct ipv6_comp_hdr*)(skb->data+offset); struct xfrm_state *x; @@ -208,7 +209,7 @@ static void ipcomp6_err(struct sk_buff * return; spi = ntohl(ntohs(ipcomph->cpi)); - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); + x = xfrm_state_lookup(host, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); if (!x) return; @@ -255,7 +256,7 @@ static int ipcomp6_tunnel_attach(struct spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr); if (spi) - t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr, + t = xfrm_state_lookup(x->host, (xfrm_address_t *)&x->id.daddr, spi, IPPROTO_IPV6, AF_INET6); if (!t) { t = ipcomp6_tunnel_create(x); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f3af4c2..5dd0768 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -432,7 +432,7 @@ done: if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) goto e_inval; - if (__dev_get_by_index(val) == NULL) { + if (__dev_get_by_index(current->host, val) == NULL) { retv = -ENODEV; break; } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 39a96c7..58602ce 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -215,7 +215,7 @@ int ipv6_sock_mc_join(struct sock *sk, i dst_release(&rt->u.dst); } } else - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(sk->sk_host, ifindex); if (dev == NULL) { sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); @@ -265,7 +265,7 @@ int ipv6_sock_mc_drop(struct sock *sk, i *lnk = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); - if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) { + if ((dev = dev_get_by_index(sk->sk_host, mc_lst->ifindex)) != NULL) { struct inet6_dev *idev = in6_dev_get(dev); if (idev) { @@ -284,7 +284,8 @@ int ipv6_sock_mc_drop(struct sock *sk, i return -EADDRNOTAVAIL; } -static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) +static struct inet6_dev *ip6_mc_find_dev(struct nethost *host, + struct in6_addr *group, int ifindex) { struct net_device *dev = NULL; struct inet6_dev *idev = NULL; @@ -299,7 +300,7 @@ static struct inet6_dev *ip6_mc_find_dev dst_release(&rt->u.dst); } } else - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(host, ifindex); if (!dev) return NULL; @@ -330,7 +331,7 @@ void ipv6_sock_mc_close(struct sock *sk) np->ipv6_mc_list = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); - dev = dev_get_by_index(mc_lst->ifindex); + dev = dev_get_by_index(sk->sk_host, mc_lst->ifindex); if (dev) { struct inet6_dev *idev = in6_dev_get(dev); @@ -372,7 +373,7 @@ int ip6_mc_source(int add, int omode, st if (!ipv6_addr_is_multicast(group)) return -EINVAL; - idev = ip6_mc_find_dev(group, pgsr->gsr_interface); + idev = ip6_mc_find_dev(sk->sk_host, group, pgsr->gsr_interface); if (!idev) return -ENODEV; dev = idev->dev; @@ -503,7 +504,7 @@ int ip6_mc_msfilter(struct sock *sk, str gsf->gf_fmode != MCAST_EXCLUDE) return -EINVAL; - idev = ip6_mc_find_dev(group, gsf->gf_interface); + idev = ip6_mc_find_dev(sk->sk_host, group, gsf->gf_interface); if (!idev) return -ENODEV; @@ -582,7 +583,7 @@ int ip6_mc_msfget(struct sock *sk, struc if (!ipv6_addr_is_multicast(group)) return -EINVAL; - idev = ip6_mc_find_dev(group, gsf->gf_interface); + idev = ip6_mc_find_dev(sk->sk_host, group, gsf->gf_interface); if (!idev) return -ENODEV; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 9ef06c9..d77f9ec 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -435,7 +435,7 @@ static void ndisc_send_na(struct net_dev src_addr = solicited_addr; in6_ifa_put(ifp); } else { - if (ipv6_dev_get_saddr(NULL, dev, daddr, &tmpaddr)) + if (ipv6_dev_get_saddr(dev->host, dev, daddr, &tmpaddr)) return; src_addr = &tmpaddr; } @@ -685,7 +685,7 @@ static void ndisc_solicit(struct neighbo struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; int probes = atomic_read(&neigh->probes); - if (skb && ipv6_chk_addr(NULL, &skb->nh.ipv6h->saddr, dev, 1)) + if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev, 1)) saddr = &skb->nh.ipv6h->saddr; if ((probes -= neigh->parms->ucast_probes) < 0) { diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index cbcb51b..e2bb377 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -230,7 +230,7 @@ static int rawv6_bind(struct sock *sk, s if (!sk->sk_bound_dev_if) goto out; - dev = dev_get_by_index(sk->sk_bound_dev_if); + dev = dev_get_by_index(sk->sk_host, sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; goto out; @@ -243,7 +243,7 @@ static int rawv6_bind(struct sock *sk, s v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { err = -EADDRNOTAVAIL; - if (!ipv6_chk_addr(sk->sk_host, &addr->sin6_addr, dev, 0)) { + if (!ipv6_chk_addr(&addr->sin6_addr, dev, 0)) { if (dev) dev_put(dev); goto out; @@ -677,7 +677,7 @@ static int rawv6_sendmsg(struct kiocb *i * Get and verify the address. */ memset(&fl, 0, sizeof(fl)); - fl.iif = sk->sk_host->loopback_dev.ifindex; + fl.host = sk->sk_host; if (sin6) { if (addr_len < SIN6_LEN_RFC2133) diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index e4fe9ee..5ebe088 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -87,7 +87,7 @@ struct frag_queue struct sk_buff *fragments; int len; int meat; - int iif; + struct net_device *dev; struct timeval stamp; unsigned int csum; __u8 last_in; /* has first/last segment arrived? */ @@ -205,6 +205,9 @@ static inline void frag_kfree_skb(struct static inline void frag_free_queue(struct frag_queue *fq, int *work) { + if (fq->dev) + dev_put(fq->dev); + fq->dev = NULL; if (work) *work -= sizeof(struct frag_queue); atomic_sub(sizeof(struct frag_queue), &ip6_frag_mem); @@ -311,7 +314,7 @@ static void ip6_frag_expire(unsigned lon /* Send error only if the first segment arrived. */ if (fq->last_in&FIRST_IN && fq->fragments) { - struct net_device *dev = dev_get_by_index(fq->iif); + struct net_device *dev = fq->dev; /* But use as source device on which LAST ARRIVED @@ -322,7 +325,6 @@ static void ip6_frag_expire(unsigned lon fq->fragments->dev = dev; icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); - dev_put(dev); } } out: @@ -556,8 +558,12 @@ static void ip6_frag_queue(struct frag_q else fq->fragments = skb; - if (skb->dev) - fq->iif = skb->dev->ifindex; + if (skb->dev) { + if (fq->dev) + dev_put(fq->dev); + fq->dev = skb->dev; + dev_hold(fq->dev); + } skb->dev = NULL; skb_get_timestamp(skb, &fq->stamp); fq->meat += skb->len; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d41dac2..6668c05 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -113,6 +113,7 @@ struct rt6_info ip6_null_entry = { .dst = { .__refcnt = ATOMIC_INIT(1), .__use = 1, + /* hardcoding the init_host loopback dev correct in the multihost case? */ .dev = &init_host.loopback_dev, .obsolete = -1, .error = -ENETUNREACH, @@ -160,9 +161,10 @@ static void ip6_dst_ifdown(struct dst_en { struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; + struct net_device *lo = &dev->host->loopback_dev; - if (dev != &init_host.loopback_dev && idev != NULL && idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(&init_host.loopback_dev); + if (dev != lo && idev != NULL && idev->dev == dev) { + struct inet6_dev *loopback_idev = in6_dev_get(lo); if (loopback_idev != NULL) { rt->rt6i_idev = loopback_idev; in6_dev_put(idev); @@ -386,12 +388,12 @@ struct rt6_info *rt6_lookup(struct in6_a */ int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, - void *_rtattr, struct netlink_skb_parms *req) + void *_rtattr, struct sk_buff *in_skb) { int err; write_lock_bh(&rt6_lock); - err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr, req); + err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr, in_skb); write_unlock_bh(&rt6_lock); return err; @@ -402,7 +404,7 @@ int ip6_ins_rt(struct rt6_info *rt, stru */ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, - struct in6_addr *saddr, struct netlink_skb_parms *req) + struct in6_addr *saddr) { int err; struct rt6_info *rt; @@ -434,7 +436,7 @@ static struct rt6_info *rt6_cow(struct r dst_hold(&rt->u.dst); - err = ip6_ins_rt(rt, NULL, NULL, req); + err = ip6_ins_rt(rt, NULL, NULL, NULL); if (err == 0) return rt; @@ -493,9 +495,8 @@ restart: read_unlock_bh(&rt6_lock); nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr, - &skb->nh.ipv6h->saddr, - &NETLINK_CB(skb)); - + &skb->nh.ipv6h->saddr); + dst_release(&rt->u.dst); rt = nrt; @@ -554,7 +555,7 @@ restart: dst_hold(&rt->u.dst); read_unlock_bh(&rt6_lock); - nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src, NULL); + nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src); dst_release(&rt->u.dst); rt = nrt; @@ -790,8 +791,9 @@ int ipv6_get_hoplimit(struct net_device * */ -int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, - void *_rtattr, struct netlink_skb_parms *req) +int ip6_route_add(struct nethost *host, + struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, + void *_rtattr, struct sk_buff *in_skb) { int err; struct rtmsg *r; @@ -811,7 +813,7 @@ int ip6_route_add(struct in6_rtmsg *rtms #endif if (rtmsg->rtmsg_ifindex) { err = -ENODEV; - dev = dev_get_by_index(rtmsg->rtmsg_ifindex); + dev = dev_get_by_index(host, rtmsg->rtmsg_ifindex); if (!dev) goto out; idev = in6_dev_get(dev); @@ -964,7 +966,7 @@ install_route: rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); rt->u.dst.dev = dev; rt->rt6i_idev = idev; - return ip6_ins_rt(rt, nlh, _rtattr, req); + return ip6_ins_rt(rt, nlh, _rtattr, in_skb); out: if (dev) @@ -976,7 +978,7 @@ out: return err; } -int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) +int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct sk_buff *in_skb) { int err; @@ -984,7 +986,7 @@ int ip6_del_rt(struct rt6_info *rt, stru rt6_reset_dflt_pointer(NULL); - err = fib6_del(rt, nlh, _rtattr, req); + err = fib6_del(rt, nlh, _rtattr, in_skb); dst_release(&rt->u.dst); write_unlock_bh(&rt6_lock); @@ -992,7 +994,9 @@ int ip6_del_rt(struct rt6_info *rt, stru return err; } -static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) +static int ip6_route_del(struct nethost *host, + struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, + void *_rtattr, struct sk_buff *in_skb) { struct fib6_node *fn; struct rt6_info *rt; @@ -1019,7 +1023,7 @@ static int ip6_route_del(struct in6_rtms dst_hold(&rt->u.dst); read_unlock_bh(&rt6_lock); - return ip6_del_rt(rt, nlh, _rtattr, req); + return ip6_del_rt(rt, nlh, _rtattr, in_skb); } } read_unlock_bh(&rt6_lock); @@ -1194,7 +1198,7 @@ void rt6_pmtu_discovery(struct in6_addr 2. It is gatewayed route or NONEXTHOP route. Action: clone it. */ if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { - nrt = rt6_cow(rt, daddr, saddr, NULL); + nrt = rt6_cow(rt, daddr, saddr); if (!nrt->u.dst.error) { nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; if (allfrag) @@ -1295,7 +1299,7 @@ struct rt6_info *rt6_add_dflt_router(str rtmsg.rtmsg_ifindex = dev->ifindex; - ip6_route_add(&rtmsg, NULL, NULL, NULL); + ip6_route_add(dev->host, &rtmsg, NULL, NULL, NULL); return rt6_get_dflt_router(gwaddr, dev); } @@ -1339,10 +1343,10 @@ int ipv6_route_ioctl(unsigned int cmd, v rtnl_lock(); switch (cmd) { case SIOCADDRT: - err = ip6_route_add(&rtmsg, NULL, NULL, NULL); + err = ip6_route_add(current->host, &rtmsg, NULL, NULL, NULL); break; case SIOCDELRT: - err = ip6_route_del(&rtmsg, NULL, NULL, NULL); + err = ip6_route_del(current->host, &rtmsg, NULL, NULL, NULL); break; default: err = -EINVAL; @@ -1378,16 +1382,16 @@ static int ip6_pkt_discard_out(struct sk */ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, - struct nethost *host, - const struct in6_addr *addr) + const struct in6_addr *addr, + int anycast) { + struct nethost *host = idev->dev->host; + struct net_device *loopback_dev = &host->loopback_dev; struct rt6_info *rt = ip6_dst_alloc(); - struct net_device *loopback_dev; if (rt == NULL) return ERR_PTR(-ENOMEM); - loopback_dev = host ? &host->loopback_dev : &init_host.loopback_dev; dev_hold(loopback_dev); in6_dev_hold(idev); @@ -1402,7 +1406,7 @@ struct rt6_info *addrconf_dst_alloc(stru rt->u.dst.obsolete = -1; rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; - if (host) + if (!anycast) rt->rt6i_flags |= RTF_LOCAL; rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); if (rt->rt6i_nexthop == NULL) { @@ -1538,7 +1542,7 @@ int inet6_rtm_delroute(struct sk_buff *s if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) return -EINVAL; - return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb)); + return ip6_route_del(skb->sk->sk_host, &rtmsg, nlh, arg, skb); } int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) @@ -1548,7 +1552,7 @@ int inet6_rtm_newroute(struct sk_buff *s if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) return -EINVAL; - return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb)); + return ip6_route_add(skb->sk->sk_host, &rtmsg, nlh, arg, skb); } struct rt6_rtnl_dump_arg @@ -1616,7 +1620,8 @@ static int rt6_fill_node(struct sk_buff RTA_PUT(skb, RTA_IIF, 4, &iif); else if (dst) { struct in6_addr saddr_buf; - if (ipv6_get_saddr(NULL, &rt->u.dst, dst, &saddr_buf) == 0) + struct nethost *host = rt->u.dst.dev->host; + if (ipv6_get_saddr(host, &rt->u.dst, dst, &saddr_buf) == 0) RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) @@ -1764,6 +1769,7 @@ int inet6_rtm_getroute(struct sk_buff *i struct sk_buff *skb; struct flowi fl; struct rt6_info *rt; + struct nethost *host = in_skb->sk->sk_host; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (skb == NULL) @@ -1776,6 +1782,7 @@ int inet6_rtm_getroute(struct sk_buff *i skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); memset(&fl, 0, sizeof(fl)); + fl.host = host; if (rta[RTA_SRC-1]) ipv6_addr_copy(&fl.fl6_src, (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1])); @@ -1788,7 +1795,7 @@ int inet6_rtm_getroute(struct sk_buff *i if (iif) { struct net_device *dev; - dev = __dev_get_by_index(iif); + dev = __dev_get_by_index(host, iif); if (!dev) { err = -ENODEV; goto out_free; @@ -1825,15 +1832,16 @@ out_free: } void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh, - struct netlink_skb_parms *req) + struct sk_buff *in_skb) { + struct nethost *host = rt->rt6i_dev->host; struct sk_buff *skb; int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); u32 pid = current->tid; u32 seq = 0; - if (req) - pid = req->pid; + if (in_skb) + pid = NETLINK_CB(in_skb).pid; if (nlh) seq = nlh->nlmsg_seq; @@ -1848,7 +1856,7 @@ void inet6_rt_notify(int event, struct r return; } NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_ROUTE; - netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_ROUTE, gfp_any()); + netlink_broadcast(rtnl, skb, host, 0, RTNLGRP_IPV6_ROUTE, gfp_any()); } /* diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 8aa1e6c..72fb8ef 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -172,7 +172,7 @@ static struct ip_tunnel * ipip6_tunnel_l int i; for (i=1; i<100; i++) { sprintf(name, "sit%d", i); - if (__dev_get_by_name(name) == NULL) + if (__dev_get_by_name(current->host, name) == NULL) break; } if (i==100) @@ -215,7 +215,7 @@ static void ipip6_tunnel_uninit(struct n } -static void ipip6_err(struct sk_buff *skb, struct nethost *host, u32 info) +static void ipip6_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -474,7 +474,7 @@ static int ipip6_tunnel_xmit(struct sk_b } { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .nl_u = { .ip4_u = { .daddr = dst, .saddr = tiph->saddr, @@ -743,7 +743,7 @@ static int ipip6_tunnel_init(struct net_ memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); if (iph->daddr) { - struct flowi fl = { .iif = 0, + struct flowi fl = { .host = dev->host, .nl_u = { .ip4_u = { .daddr = iph->daddr, .saddr = iph->saddr, @@ -759,7 +759,7 @@ static int ipip6_tunnel_init(struct net_ } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->parms.link); + tdev = __dev_get_by_index(dev->host, tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f8f413a..20994f7 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -618,7 +618,7 @@ static int tcp_v6_connect(struct sock *s ipv6_addr_copy(&fl.fl6_dst, &np->daddr); ipv6_addr_copy(&fl.fl6_src, (saddr ? saddr : &np->saddr)); - fl.iif = sk->sk_host->loopback_dev.ifindex; + fl.host = sk->sk_host; fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = usin->sin6_port; fl.fl_ip_sport = inet->sport; @@ -750,7 +750,7 @@ static void tcp_v6_err(struct sk_buff *s fl.proto = IPPROTO_TCP; ipv6_addr_copy(&fl.fl6_dst, &np->daddr); ipv6_addr_copy(&fl.fl6_src, &np->saddr); - fl.iif = sk->sk_host->loopback_dev.ifindex; + fl.host = sk->sk_host; fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = inet->dport; fl.fl_ip_sport = inet->sport; @@ -845,7 +845,7 @@ static int tcp_v6_send_synack(struct soc ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); fl.fl6_flowlabel = 0; - fl.iif = sk->sk_host->loopback_dev.ifindex; + fl.host = sk->sk_host; fl.oif = treq->iif; fl.fl_ip_dport = inet_rsk(req)->rmt_port; fl.fl_ip_sport = inet_sk(sk)->sport; @@ -996,7 +996,7 @@ static void tcp_v6_send_reset(struct sk_ buff->csum); fl.proto = IPPROTO_TCP; - fl.iif = skb->dst->dev->ifindex; + fl.host = skb->dst->dev->host; fl.oif = inet6_iif(skb); fl.fl_ip_dport = t1->dest; fl.fl_ip_sport = t1->source; @@ -1064,7 +1064,7 @@ static void tcp_v6_send_ack(struct sk_bu buff->csum); fl.proto = IPPROTO_TCP; - fl.iif = skb->dst->dev->ifindex; + fl.host = skb->dst->dev->host; fl.oif = inet6_iif(skb); fl.fl_ip_dport = t1->dest; fl.fl_ip_sport = t1->source; @@ -1310,7 +1310,7 @@ static struct sock * tcp_v6_syn_recv_soc final_p = &final; } ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); - fl.iif = sk->sk_host->loopback_dev.ifindex; + fl.host = sk->sk_host; fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = inet_rsk(req)->rmt_port; fl.fl_ip_sport = inet_sk(sk)->sport; @@ -1716,7 +1716,7 @@ static int tcp_v6_rebuild_header(struct ipv6_addr_copy(&fl.fl6_dst, &np->daddr); ipv6_addr_copy(&fl.fl6_src, &np->saddr); fl.fl6_flowlabel = np->flow_label; - fl.iif = sk->sk_host->loopback_dev.ifindex; + fl.host = sk->sk_host; fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = inet->dport; fl.fl_ip_sport = inet->sport; @@ -1764,7 +1764,7 @@ static int tcp_v6_xmit(struct sk_buff *s ipv6_addr_copy(&fl.fl6_src, &np->saddr); fl.fl6_flowlabel = np->flow_label; IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); - fl.iif = sk->sk_host->loopback_dev.ifindex; + fl.host = sk->sk_host; fl.oif = sk->sk_bound_dev_if; fl.fl_ip_sport = inet->sport; fl.fl_ip_dport = inet->dport; diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 28c29d7..67b9d84 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -51,7 +51,8 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, if (xfrm_nr == XFRM_MAX_DEPTH) goto drop; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET6); + x = xfrm_state_lookup(skb->dev->host, (xfrm_address_t *)&iph->daddr, + spi, nexthdr, AF_INET6); if (x == NULL) goto drop; spin_lock(&x->lock); diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index f214ccc..525cb07 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -281,7 +281,7 @@ static void xfrm6_dst_ifdown(struct dst_ xdst = (struct xfrm_dst *)dst; if (xdst->u.rt6.rt6i_idev->dev == dev) { - struct inet6_dev *loopback_idev = in6_dev_get(&init_host.loopback_dev); + struct inet6_dev *loopback_idev = in6_dev_get(&dev->host->loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index bf0d0ab..121b35f 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c @@ -47,7 +47,7 @@ __xfrm6_init_tempsel(struct xfrm_state * } static struct xfrm_state * -__xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) +__xfrm6_state_lookup(struct nethost *host, xfrm_address_t *daddr, u32 spi, u8 proto) { unsigned h = __xfrm6_spi_hash(daddr, spi, proto); struct xfrm_state *x; @@ -56,7 +56,8 @@ __xfrm6_state_lookup(xfrm_address_t *dad if (x->props.family == AF_INET6 && spi == x->id.spi && ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && - proto == x->id.proto) { + proto == x->id.proto && + host == x->host) { xfrm_state_hold(x); return x; } diff --git a/net/key/af_key.c b/net/key/af_key.c index 3903168..dee3c8b 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -518,7 +518,7 @@ static int pfkey_sadb_addr2xfrm_addr(str /* NOTREACHED */ } -static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs) +static struct xfrm_state *pfkey_xfrm_state_lookup(struct nethost *host, struct sadb_msg *hdr, void **ext_hdrs) { struct sadb_sa *sa; struct sadb_address *addr; @@ -556,7 +556,7 @@ static struct xfrm_state *pfkey_xfrm_st if (!xaddr) return NULL; - return xfrm_state_lookup(xaddr, sa->sadb_sa_spi, proto, family); + return xfrm_state_lookup(host, xaddr, sa->sadb_sa_spi, proto, family); } #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1))) @@ -902,7 +902,8 @@ static struct sk_buff * pfkey_xfrm_state return skb; } -static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, +static struct xfrm_state * pfkey_msg2xfrm_state(struct nethost *host, + struct sadb_msg *hdr, void **ext_hdrs) { struct xfrm_state *x; @@ -969,6 +970,8 @@ static struct xfrm_state * pfkey_msg2xfr if (x == NULL) return ERR_PTR(-ENOBUFS); + get_host(host); + x->host = host; x->id.proto = proto; x->id.spi = sa->sadb_sa_spi; x->props.replay_window = sa->sadb_sa_replay; @@ -1318,7 +1321,7 @@ static int pfkey_add(struct sock *sk, st xfrm_probe_algs(); - x = pfkey_msg2xfrm_state(hdr, ext_hdrs); + x = pfkey_msg2xfrm_state(sk->sk_host, hdr, ext_hdrs); if (IS_ERR(x)) return PTR_ERR(x); @@ -1357,7 +1360,7 @@ static int pfkey_delete(struct sock *sk, ext_hdrs[SADB_EXT_ADDRESS_DST-1])) return -EINVAL; - x = pfkey_xfrm_state_lookup(hdr, ext_hdrs); + x = pfkey_xfrm_state_lookup(sk->sk_host, hdr, ext_hdrs); if (x == NULL) return -ESRCH; @@ -1393,7 +1396,7 @@ static int pfkey_get(struct sock *sk, st ext_hdrs[SADB_EXT_ADDRESS_DST-1])) return -EINVAL; - x = pfkey_xfrm_state_lookup(hdr, ext_hdrs); + x = pfkey_xfrm_state_lookup(sk->sk_host, hdr, ext_hdrs); if (x == NULL) return -ESRCH; @@ -1994,7 +1997,7 @@ static int pfkey_spdadd(struct sock *sk, if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) return -EINVAL; - xp = xfrm_policy_alloc(GFP_KERNEL); + xp = xfrm_policy_alloc(sk->sk_host, GFP_KERNEL); if (xp == NULL) return -ENOBUFS; @@ -2655,7 +2658,7 @@ static int pfkey_send_acquire(struct xfr return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); } -static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, +static struct xfrm_policy *pfkey_compile_policy(struct nethost *host, u16 family, int opt, u8 *data, int len, int *dir) { struct xfrm_policy *xp; @@ -2689,7 +2692,7 @@ static struct xfrm_policy *pfkey_compile (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND)) return NULL; - xp = xfrm_policy_alloc(GFP_ATOMIC); + xp = xfrm_policy_alloc(host, GFP_ATOMIC); if (xp == NULL) { *dir = -ENOBUFS; return NULL; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index bea05f1..cead1e6 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -367,8 +367,7 @@ static struct proto netlink_proto = { .obj_size = sizeof(struct netlink_sock), }; -static struct sock *__netlink_create(struct nethost *host, struct socket *sock, - int protocol) +static struct sock *__netlink_create(struct socket *sock, int protocol) { struct sock *sk; struct netlink_sock *nlk; @@ -388,19 +387,16 @@ static struct sock *__netlink_create(str sk->sk_destruct = netlink_sock_destruct; sk->sk_protocol = protocol; - sk->sk_host = host; - if (host) - get_host(host); return sk; } -struct sock *__netlink_kernel_create(struct nethost *host, struct socket *sock, - int unit, void (*input)(struct sock *sk, int len)) +struct sock *__netlink_kernel_create(struct socket *sock, int unit, + void (*input)(struct sock *sk, int len)) { struct sock *sk; int err; - if (IS_ERR(sk = __netlink_create(host, sock, unit))) + if (IS_ERR(sk = __netlink_create(sock, unit))) goto out; sk->sk_data_ready = netlink_data_ready; @@ -442,7 +438,7 @@ retry: if (!data_ready) goto out; - sk = __netlink_kernel_create(host, NULL, protocol, data_ready); + sk = __netlink_kernel_create(NULL, protocol, data_ready); if (IS_ERR(sk)) { err = PTR_ERR(sk); sk = NULL; @@ -455,6 +451,12 @@ out: return err; } +static int netlink_host_init(struct nethost *host) +{ + /* We don't need any per host state */ + return 0; +} + static int netlink_create(struct socket *sock, int protocol) { struct module *module = NULL; @@ -492,7 +494,7 @@ static int netlink_create(struct socket #endif err = -ENOMEM; - if (IS_ERR(sk = __netlink_create(current->host, sock, protocol))) + if (IS_ERR(sk = __netlink_create(sock, protocol))) goto out_module; nlk = nlk_sk(sk); @@ -500,6 +502,7 @@ static int netlink_create(struct socket if ((err = get_kern_sk(nlk)) < 0) goto out_release_sock; + WARN_ON(nlk->kern_sk->sk_host != sk->sk_host); out: return err; @@ -987,14 +990,16 @@ out: return 0; } -int netlink_host_broadcast(struct sock *ssk, struct sk_buff *skb, - struct nethost *host, u32 pid, - u32 group, gfp_t allocation) +int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, + struct nethost *host, u32 pid, u32 group, + gfp_t allocation) { struct netlink_broadcast_data info; struct hlist_node *node; struct sock *sk; + WARN_ON(!host); + skb = netlink_trim(skb, allocation); info.exclude_sk = ssk; @@ -1032,13 +1037,6 @@ int netlink_host_broadcast(struct sock * return -ESRCH; } -int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, - u32 group, gfp_t allocation) -{ - return netlink_host_broadcast(ssk, skb, ssk->sk_host, pid, group, - allocation); -} - struct netlink_set_err_data { struct sock *exclude_sk; u32 pid; @@ -1260,7 +1258,7 @@ static int netlink_sendmsg(struct kiocb if (dst_group) { atomic_inc(&skb->users); - netlink_host_broadcast(sk, skb, sk->sk_host, dst_pid, dst_group, GFP_KERNEL); + netlink_broadcast(sk, skb, sk->sk_host, dst_pid, dst_group, GFP_KERNEL); } err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT); @@ -1353,6 +1351,7 @@ netlink_kernel_create(int unit, unsigned struct sock *sk; struct netlink_sock *nlk; + WARN_ON(current->host != &init_host); sk = NULL; if (!nl_table) @@ -1364,7 +1363,7 @@ netlink_kernel_create(int unit, unsigned if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock) < 0) goto out; - if (IS_ERR(sk = __netlink_kernel_create(NULL, sock, unit, input))) + if (IS_ERR(sk = __netlink_kernel_create(sock, unit, input))) goto out_sock_release; nlk = nlk_sk(sk); @@ -1713,10 +1712,10 @@ static struct proto_ops netlink_ops = { }; static struct net_proto_family netlink_family_ops = { - .family = PF_NETLINK, - .create = netlink_create, - .multi_host = 1, - .owner = THIS_MODULE, /* for consistency 8) */ + .family = PF_NETLINK, + .host_init = netlink_host_init, + .create = netlink_create, + .owner = THIS_MODULE, /* for consistency 8) */ }; extern void netlink_skb_parms_too_large(void); @@ -1785,7 +1784,6 @@ core_initcall(netlink_proto_init); EXPORT_SYMBOL(netlink_ack); EXPORT_SYMBOL(netlink_broadcast); -EXPORT_SYMBOL(netlink_host_broadcast); EXPORT_SYMBOL(netlink_dump_start); EXPORT_SYMBOL(netlink_kernel_create); EXPORT_SYMBOL(netlink_register_notifier); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 499ae3d..da15c93 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -281,6 +281,9 @@ static int packet_rcv_spkt(struct sk_buf if (skb->pkt_type == PACKET_LOOPBACK) goto out; + + if (dev->host != sk->sk_host) + goto out; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto oom; @@ -353,7 +356,7 @@ static int packet_sendmsg_spkt(struct ki */ saddr->spkt_device[13] = 0; - dev = dev_get_by_name(saddr->spkt_device); + dev = dev_get_by_name(current->host, saddr->spkt_device); err = -ENODEV; if (dev == NULL) goto out_unlock; @@ -471,6 +474,9 @@ static int packet_rcv(struct sk_buff *sk sk = pt->af_packet_priv; po = pkt_sk(sk); + if (dev->host != sk->sk_host) + goto drop; + skb->dev = dev; if (dev->hard_header) { @@ -580,6 +586,9 @@ static int tpacket_rcv(struct sk_buff *s sk = pt->af_packet_priv; po = pkt_sk(sk); + if (dev->host != sk->sk_host) + goto drop; + if (dev->hard_header) { if (sk->sk_type != SOCK_DGRAM) skb_push(skb, skb->data - skb->mac.raw); @@ -739,7 +748,7 @@ static int packet_sendmsg(struct kiocb * } - dev = dev_get_by_index(ifindex); + dev = dev_get_by_index(current->host, ifindex); err = -ENXIO; if (dev == NULL) goto out_unlock; @@ -938,7 +947,7 @@ static int packet_bind_spkt(struct socke return -EINVAL; strlcpy(name,uaddr->sa_data,sizeof(name)); - dev = dev_get_by_name(name); + dev = dev_get_by_name(sk->sk_host, name); if (dev) { err = packet_do_bind(sk, dev, pkt_sk(sk)->num); dev_put(dev); @@ -966,7 +975,7 @@ static int packet_bind(struct socket *so if (sll->sll_ifindex) { err = -ENODEV; - dev = dev_get_by_index(sll->sll_ifindex); + dev = dev_get_by_index(sk->sk_host, sll->sll_ifindex); if (dev == NULL) goto out; } @@ -984,6 +993,12 @@ static struct proto packet_proto = { .obj_size = sizeof(struct packet_sock), }; +static int packet_host_init(struct nethost *host) +{ + /* We don't need any per host state */ + return 0; +} + /* * Create a packet of type SOCK_PACKET. */ @@ -1149,7 +1164,7 @@ static int packet_getname_spkt(struct so return -EOPNOTSUPP; uaddr->sa_family = AF_PACKET; - dev = dev_get_by_index(pkt_sk(sk)->ifindex); + dev = dev_get_by_index(sk->sk_host, pkt_sk(sk)->ifindex); if (dev) { strlcpy(uaddr->sa_data, dev->name, 15); dev_put(dev); @@ -1175,7 +1190,7 @@ static int packet_getname(struct socket sll->sll_family = AF_PACKET; sll->sll_ifindex = po->ifindex; sll->sll_protocol = po->num; - dev = dev_get_by_index(po->ifindex); + dev = dev_get_by_index(sk->sk_host, po->ifindex); if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; @@ -1228,7 +1243,7 @@ static int packet_mc_add(struct sock *sk rtnl_lock(); err = -ENODEV; - dev = __dev_get_by_index(mreq->mr_ifindex); + dev = __dev_get_by_index(sk->sk_host, mreq->mr_ifindex); if (!dev) goto done; @@ -1282,7 +1297,7 @@ static int packet_mc_drop(struct sock *s if (--ml->count == 0) { struct net_device *dev; *mlp = ml->next; - dev = dev_get_by_index(ml->ifindex); + dev = dev_get_by_index(sk->sk_host, ml->ifindex); if (dev) { packet_dev_mc(dev, ml, -1); dev_put(dev); @@ -1310,7 +1325,7 @@ static void packet_flush_mclist(struct s struct net_device *dev; po->mclist = ml->next; - if ((dev = dev_get_by_index(ml->ifindex)) != NULL) { + if ((dev = dev_get_by_index(sk->sk_host, ml->ifindex)) != NULL) { packet_dev_mc(dev, ml, -1); dev_put(dev); } @@ -1822,6 +1837,7 @@ static struct proto_ops packet_ops = { static struct net_proto_family packet_family_ops = { .family = PF_PACKET, + .host_init = packet_host_init, .create = packet_create, .owner = THIS_MODULE, }; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index b4d89fb..93a6d9b 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -145,6 +145,7 @@ static int tc_ctl_tfilter(struct sk_buff unsigned long cl; unsigned long fh; int err; + struct nethost *host = skb->sk->sk_host; replay: tca = arg; @@ -165,7 +166,7 @@ replay: /* Find head of filter chain. */ /* Find link */ - if ((dev = __dev_get_by_index(t->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(host, t->tcm_ifindex)) == NULL) return -ENODEV; /* Find qdisc */ @@ -356,7 +357,8 @@ static int tfilter_notify(struct sk_buff struct tcf_proto *tp, unsigned long fh, int event) { struct sk_buff *skb; - u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; + struct nethost *host = oskb->sk->sk_host; + u32 pid = NETLINK_CB(oskb).pid; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) @@ -367,7 +369,7 @@ static int tfilter_notify(struct sk_buff return -EINVAL; } - return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + return rtnetlink_send(skb, host, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); } struct tcf_dump_args @@ -396,10 +398,11 @@ static int tc_dump_tfilter(struct sk_buf unsigned long cl = 0; struct Qdisc_class_ops *cops; struct tcf_dump_args arg; + struct nethost *host = skb->sk->sk_host; if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) return skb->len; - if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = dev_get_by_index(host, tcm->tcm_ifindex)) == NULL) return skb->len; read_lock_bh(&qdisc_tree_lock); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 31570b9..ca95188 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -558,9 +558,10 @@ static int tc_get_qdisc(struct sk_buff * u32 clid = tcm->tcm_parent; struct Qdisc *q = NULL; struct Qdisc *p = NULL; + struct nethost *host = skb->sk->sk_host; int err; - if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(host, tcm->tcm_ifindex)) == NULL) return -ENODEV; if (clid) { @@ -618,6 +619,7 @@ static int tc_modify_qdisc(struct sk_buf struct net_device *dev; u32 clid; struct Qdisc *q, *p; + struct nethost *host = skb->sk->sk_host; int err; replay: @@ -627,7 +629,7 @@ replay: clid = tcm->tcm_parent; q = p = NULL; - if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(host, tcm->tcm_ifindex)) == NULL) return -ENODEV; if (clid) { @@ -800,7 +802,8 @@ static int qdisc_notify(struct sk_buff * u32 clid, struct Qdisc *old, struct Qdisc *new) { struct sk_buff *skb; - u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; + struct nethost *host = oskb->sk->sk_host; + u32 pid = NETLINK_CB(oskb).pid; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) @@ -816,7 +819,7 @@ static int qdisc_notify(struct sk_buff * } if (skb->len) - return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + return rtnetlink_send(skb, host, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); err_out: kfree_skb(skb); @@ -884,9 +887,10 @@ static int tc_ctl_tclass(struct sk_buff u32 pid = tcm->tcm_parent; u32 clid = tcm->tcm_handle; u32 qid = TC_H_MAJ(clid); + struct nethost *host = skb->sk->sk_host; int err; - if ((dev = __dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = __dev_get_by_index(host, tcm->tcm_ifindex)) == NULL) return -ENODEV; /* @@ -1029,7 +1033,8 @@ static int tclass_notify(struct sk_buff struct Qdisc *q, unsigned long cl, int event) { struct sk_buff *skb; - u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; + struct nethost *host = oskb->sk->sk_host; + u32 pid = NETLINK_CB(oskb).pid; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) @@ -1040,7 +1045,7 @@ static int tclass_notify(struct sk_buff return -EINVAL; } - return rtnetlink_send(skb, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); + return rtnetlink_send(skb, host, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); } struct qdisc_dump_args @@ -1066,10 +1071,11 @@ static int tc_dump_tclass(struct sk_buff struct Qdisc *q; struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh); struct qdisc_dump_args arg; + struct nethost *host = skb->sk->sk_host; if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) return 0; - if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL) + if ((dev = dev_get_by_index(host, tcm->tcm_ifindex)) == NULL) return 0; s_t = cb->args[0]; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 5ed5536..0935547 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -445,10 +445,11 @@ static struct dst_entry *sctp_v4_get_dst union sctp_addr dst_saddr; memset(&fl, 0x0, sizeof(struct flowi)); + BUG_ON(!assoc); /* I need an assoc to get the host... */ fl.fl4_dst = daddr->v4.sin_addr.s_addr; fl.proto = IPPROTO_SCTP; if (asoc) { - fl.iif = assoc->base.sk->sk_host->loopback_dev.ifindex; + fl.host = assoc->base.sk->sk_host; fl.fl4_tos = RT_CONN_FLAGS(asoc->base.sk); fl.oif = asoc->base.sk->sk_bound_dev_if; } diff --git a/net/socket.c b/net/socket.c index d0a9015..c050b8a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -211,7 +211,7 @@ static DEFINE_PER_CPU(int, sockets_in_us the AF_UNIX size (see net/unix/af_unix.c :unix_mkname()). */ - + /** * move_addr_to_kernel - copy a socket address into kernel space * @uaddr: Address in user space @@ -1150,7 +1150,7 @@ static int __sock_create(int family, int /* Unless the address family supports multiple hosts on the same * machine. Fail if we are not the primary host. */ - if ((current->host != &init_host) && !net_families[family]->multi_host) + if ((current->host != &init_host) && !net_families[family]->host_init) goto out_module_put; if ((err = net_families[family]->create(sock, protocol)) < 0) { @@ -1999,6 +1999,43 @@ asmlinkage long sys_socketcall(int call, #endif /* __ARCH_WANT_SYS_SOCKETCALL */ +int sock_host_init(struct nethost *host) +{ + int err = 0, i; + + net_family_read_lock(); + for(i = 0; !err && (i < NPROTO); i++) { + struct net_proto_family *family; + int (*init)(struct nethost *host); + family = net_families[i]; + if (family) { + init = family->host_init; + if (init) + err = init(host); + } + } + net_family_read_unlock(); + return err; +} + +void sock_host_fini(struct nethost *host) +{ + int i; + + net_family_read_lock(); + for(i = 0; i < NPROTO; i++) { + struct net_proto_family *family; + void (*fini)(struct nethost *host); + family = net_families[i]; + if (family) { + fini = family->host_fini; + if (fini) + fini(host); + } + } + net_family_read_unlock(); +} + /* * This function is called by a protocol handler that wants to * advertise its address family, and have it linked into the diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 4073b4d..41c5b67 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -545,6 +545,12 @@ static struct proto unix_proto = { .obj_size = sizeof(struct unix_sock), }; +static int unix_host_init(struct nethost *host) +{ + /* We don't need any per host state */ + return 0; +} + static struct sock * unix_create1(struct socket *sock) { struct sock *sk = NULL; @@ -557,8 +563,6 @@ static struct sock * unix_create1(struct if (!sk) goto out; - sk->sk_host = current->host; - get_host(sk->sk_host); atomic_inc(&unix_nr_socks); sock_init_data(sock,sk); @@ -2043,10 +2047,10 @@ static struct file_operations unix_seq_f #endif static struct net_proto_family unix_family_ops = { - .family = PF_UNIX, - .create = unix_create, - .multi_host = 1, - .owner = THIS_MODULE, + .family = PF_UNIX, + .host_init = unix_host_init, + .create = unix_create, + .owner = THIS_MODULE, }; static int __init af_unix_init(void) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 76b5cf9..a1b4938 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -228,7 +228,7 @@ expired: * SPD calls. */ -struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) +struct xfrm_policy *xfrm_policy_alloc(struct nethost *host, gfp_t gfp) { struct xfrm_policy *policy; @@ -241,6 +241,8 @@ struct xfrm_policy *xfrm_policy_alloc(gf init_timer(&policy->timer); policy->timer.data = (unsigned long)policy; policy->timer.function = xfrm_policy_timer; + policy->host = host; + get_host(policy->host); } return policy; } @@ -259,6 +261,8 @@ void __xfrm_policy_destroy(struct xfrm_p if (del_timer(&policy->timer)) BUG(); + put_host(policy->host); + kfree(policy); } EXPORT_SYMBOL(__xfrm_policy_destroy); @@ -507,6 +511,9 @@ static void xfrm_policy_lookup(struct fl if (pol->family != family) continue; + if (pol->host != fl->host) + continue; + match = xfrm_selector_match(sel, fl, family); if (match) { xfrm_pol_hold(pol); @@ -595,7 +602,7 @@ int xfrm_sk_policy_insert(struct sock *s static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) { - struct xfrm_policy *newp = xfrm_policy_alloc(GFP_ATOMIC); + struct xfrm_policy *newp = xfrm_policy_alloc(old->host, GFP_ATOMIC); if (newp) { newp->selector = old->selector; @@ -1035,8 +1042,9 @@ static int stale_bundle(struct dst_entry void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) { while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { - dst->dev = &init_host.loopback_dev; - dev_hold(&init_host.loopback_dev); + struct net_device *lo = &dev->host->loopback_dev; + dst->dev = lo; + dev_hold(lo); dev_put(dev); } } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 9d206c2..a170716 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -228,6 +228,8 @@ static int __xfrm_state_delete(struct xf list_del(&x->byspi); atomic_dec(&x->refcnt); } + put_host(x->host); + x->host = NULL; spin_unlock(&xfrm_state_lock); if (del_timer(&x->timer)) atomic_dec(&x->refcnt); @@ -367,7 +369,7 @@ xfrm_state_find(xfrm_address_t *daddr, x x = best; if (!x && !error && !acquire_in_progress) { if (tmpl->id.spi && - (x0 = afinfo->state_lookup(daddr, tmpl->id.spi, + (x0 = afinfo->state_lookup(fl->host, daddr, tmpl->id.spi, tmpl->id.proto)) != NULL) { xfrm_state_put(x0); error = -EEXIST; @@ -380,6 +382,8 @@ xfrm_state_find(xfrm_address_t *daddr, x } /* Initialize temporary selector matching only * to current session. */ + x->host = fl->host; + get_host(x->host); xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); if (km_query(x, tmpl, pol) == 0) { @@ -415,6 +419,7 @@ out: static void __xfrm_state_insert(struct xfrm_state *x) { unsigned h = xfrm_dst_hash(&x->id.daddr, x->props.family); + BUG_ON(!x->host); list_add(&x->bydst, xfrm_state_bydst+h); xfrm_state_hold(x); @@ -454,7 +459,7 @@ int xfrm_state_add(struct xfrm_state *x) spin_lock_bh(&xfrm_state_lock); - x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); + x1 = afinfo->state_lookup(x->host, &x->id.daddr, x->id.spi, x->id.proto); if (x1) { xfrm_state_put(x1); x1 = NULL; @@ -502,7 +507,7 @@ int xfrm_state_update(struct xfrm_state return -EAFNOSUPPORT; spin_lock_bh(&xfrm_state_lock); - x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); + x1 = afinfo->state_lookup(x->host, &x->id.daddr, x->id.spi, x->id.proto); err = -ESRCH; if (!x1) @@ -606,7 +611,7 @@ err: EXPORT_SYMBOL(xfrm_state_check); struct xfrm_state * -xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, +xfrm_state_lookup(struct nethost *host, xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family) { struct xfrm_state *x; @@ -615,7 +620,7 @@ xfrm_state_lookup(xfrm_address_t *daddr, return NULL; spin_lock_bh(&xfrm_state_lock); - x = afinfo->state_lookup(daddr, spi, proto); + x = afinfo->state_lookup(host, daddr, spi, proto); spin_unlock_bh(&xfrm_state_lock); xfrm_state_put_afinfo(afinfo); return x; @@ -692,7 +697,7 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 return; if (minspi == maxspi) { - x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); + x0 = xfrm_state_lookup(x->host, &x->id.daddr, minspi, x->id.proto, x->props.family); if (x0) { xfrm_state_put(x0); return; @@ -704,7 +709,7 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 maxspi = ntohl(maxspi); for (h=0; hid.daddr, htonl(spi), x->id.proto, x->props.family); + x0 = xfrm_state_lookup(x->host, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); if (x0 == NULL) { x->id.spi = htonl(spi); break; @@ -912,7 +917,7 @@ int xfrm_user_policy(struct sock *sk, in err = -EINVAL; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) { - pol = km->compile_policy(sk->sk_family, optname, data, + pol = km->compile_policy(sk->sk_host, sk->sk_family, optname, data, optlen, &err); if (err >= 0) break; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index cb41473..4397369 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -304,12 +304,13 @@ out: static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) { + struct nethost *host = skb->sk->sk_host; struct xfrm_state *x; int err; struct km_event c; struct xfrm_usersa_id *p = NLMSG_DATA(nlh); - x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); + x = xfrm_state_lookup(host, &p->daddr, p->spi, p->proto, p->family); if (x == NULL) return -ESRCH; @@ -444,12 +445,13 @@ static struct sk_buff *xfrm_state_netlin static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) { + struct nethost *host = skb->sk->sk_host; struct xfrm_usersa_id *p = NLMSG_DATA(nlh); struct xfrm_state *x; struct sk_buff *resp_skb; int err; - x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); + x = xfrm_state_lookup(host, &p->daddr, p->spi, p->proto, p->family); err = -ESRCH; if (x == NULL) goto out_noput; @@ -670,9 +672,9 @@ static void copy_to_user_policy(struct x p->share = XFRM_SHARE_ANY; /* XXX xp->share */ } -static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **xfrma, int *errp) +static struct xfrm_policy *xfrm_policy_construct(struct nethost *host, struct xfrm_userpolicy_info *p, struct rtattr **xfrma, int *errp) { - struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL); + struct xfrm_policy *xp = xfrm_policy_alloc(host, GFP_KERNEL); int err; if (!xp) { @@ -693,6 +695,7 @@ static struct xfrm_policy *xfrm_policy_c static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) { + struct nethost *host = skb->sk->sk_host; struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh); struct xfrm_policy *xp; struct km_event c; @@ -703,7 +706,7 @@ static int xfrm_add_policy(struct sk_buf if (err) return err; - xp = xfrm_policy_construct(p, (struct rtattr **) xfrma, &err); + xp = xfrm_policy_construct(host, p, (struct rtattr **) xfrma, &err); if (!xp) return err; @@ -1126,10 +1129,10 @@ static int xfrm_exp_state_notify(struct BUG(); NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); + return netlink_broadcast(xfrm_nl, skb, x->host, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); } -static int xfrm_notify_sa_flush(struct km_event *c) +static int xfrm_notify_sa_flush(struct xfrm_state *x, struct km_event *c) { struct xfrm_usersa_flush *p; struct nlmsghdr *nlh; @@ -1152,7 +1155,7 @@ static int xfrm_notify_sa_flush(struct k nlh->nlmsg_len = skb->tail - b; NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); + return netlink_broadcast(xfrm_nl, skb, x->host, 0, XFRMNLGRP_SA, GFP_ATOMIC); nlmsg_failure: kfree_skb(skb); @@ -1227,7 +1230,7 @@ static int xfrm_notify_sa(struct xfrm_st nlh->nlmsg_len = skb->tail - b; NETLINK_CB(skb).dst_group = XFRMNLGRP_SA; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); + return netlink_broadcast(xfrm_nl, skb, x->host, 0, XFRMNLGRP_SA, GFP_ATOMIC); nlmsg_failure: rtattr_failure: @@ -1246,7 +1249,7 @@ static int xfrm_send_state_notify(struct case XFRM_MSG_NEWSA: return xfrm_notify_sa(x, c); case XFRM_MSG_FLUSHSA: - return xfrm_notify_sa_flush(c); + return xfrm_notify_sa_flush(x, c); default: printk("xfrm_user: Unknown SA event %d\n", c->event); break; @@ -1306,13 +1309,13 @@ static int xfrm_send_acquire(struct xfrm BUG(); NETLINK_CB(skb).dst_group = XFRMNLGRP_ACQUIRE; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); + return netlink_broadcast(xfrm_nl, skb, x->host, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); } /* User gives us xfrm_user_policy_info followed by an array of 0 * or more templates. */ -static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, +static struct xfrm_policy *xfrm_compile_policy(struct nethost *host, u16 family, int opt, u8 *data, int len, int *dir) { struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; @@ -1353,7 +1356,7 @@ static struct xfrm_policy *xfrm_compile_ if (p->dir > XFRM_POLICY_OUT) return NULL; - xp = xfrm_policy_alloc(GFP_KERNEL); + xp = xfrm_policy_alloc(host, GFP_KERNEL); if (xp == NULL) { *dir = -ENOBUFS; return NULL; @@ -1406,7 +1409,7 @@ static int xfrm_exp_policy_notify(struct BUG(); NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); + return netlink_broadcast(xfrm_nl, skb, xp->host, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); } static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) @@ -1455,7 +1458,7 @@ static int xfrm_notify_policy(struct xfr nlh->nlmsg_len = skb->tail - b; NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); + return netlink_broadcast(xfrm_nl, skb, xp->host, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); nlmsg_failure: rtattr_failure: @@ -1463,7 +1466,7 @@ rtattr_failure: return -1; } -static int xfrm_notify_policy_flush(struct km_event *c) +static int xfrm_notify_policy_flush(struct xfrm_policy *xp, struct km_event *c) { struct nlmsghdr *nlh; struct sk_buff *skb; @@ -1481,7 +1484,7 @@ static int xfrm_notify_policy_flush(stru nlh->nlmsg_len = skb->tail - b; NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); + return netlink_broadcast(xfrm_nl, skb, xp->host, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); nlmsg_failure: kfree_skb(skb); @@ -1497,7 +1500,7 @@ static int xfrm_send_policy_notify(struc case XFRM_MSG_DELPOLICY: return xfrm_notify_policy(xp, dir, c); case XFRM_MSG_FLUSHPOLICY: - return xfrm_notify_policy_flush(c); + return xfrm_notify_policy_flush(xp, c); case XFRM_MSG_POLEXPIRE: return xfrm_exp_policy_notify(xp, dir, c); default: -- 1.0.GIT