--- linux-2.4.18-5/include/linux/sockios.h Sat Sep 14 23:55:25 2002 +++ linux-2.4.18-5.dev/include/linux/sockios.h Sat Sep 14 23:56:20 2002 @@ -114,6 +114,16 @@ #define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */ #define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave */ + +/* Ben's little hack land */ +#define SIOCSACCEPTLOCALADDRS 0x89a0 /* Allow interfaces to accept pkts from + * local interfaces...use with SO_BINDTODEVICE + */ +#define SIOCGACCEPTLOCALADDRS 0x89a1 /* Allow interfaces to accept pkts from + * local interfaces...use with SO_BINDTODEVICE + */ + + /* Device private ioctl calls */ /* --- linux-2.4.18-5/include/net/tcp.h Sat Sep 14 23:55:25 2002 +++ linux-2.4.18-5.dev/include/net/tcp.h Sun Sep 15 00:09:51 2002 @@ -520,6 +520,12 @@ struct tcp_v6_open_req v6_req; #endif } af; + int bound_dev_if; /* This is so we can connect to ourselves and not collide + * in the open-request hash (the addresses and ports are the + * same, but we need two ends, so use the interface to determine + * one from the other. Active when SO_BINDTODEVICE is used. + * --Ben + */ }; /* SLAB cache for open requests. */ --- linux-2.4.18-5/net/ipv4/arp.c Sat Sep 14 23:55:25 2002 +++ linux-2.4.18-5.dev/net/ipv4/arp.c Sat Sep 14 23:56:20 2002 @@ -1,4 +1,4 @@ -/* linux/net/inet/arp.c +/* linux/net/inet/arp.c -*-linux-c-*- * * Version: $Id: sts_RH_2.4.18-5.patch,v 1.2 2002/09/17 07:01:55 greear Exp $ * @@ -351,12 +351,22 @@ int flag = 0; /*unsigned long now; */ - if (ip_route_output(&rt, sip, tip, 0, 0) < 0) + if (ip_route_output(&rt, sip, tip, 0, 0) < 0) { return 1; - if (rt->u.dst.dev != dev) { - NET_INC_STATS_BH(ArpFilter); - flag = 1; - } + } + if (rt->u.dst.dev != dev) { + if ((dev->priv_flags & IFF_ACCEPT_LOCAL_ADDRS) && + (rt->u.dst.dev == &loopback_dev)) { + /* OK, we'll let this special case slide, so that we can arp from one + * local interface to another. This seems to work, but could use some + * review. --Ben + */ + } + else { + NET_INC_STATS_BH(ArpFilter); + flag = 1; + } + } ip_rt_put(rt); return flag; } --- linux-2.4.18-5/net/ipv4/fib_frontend.c Sat Sep 14 23:55:25 2002 +++ linux-2.4.18-5.dev/net/ipv4/fib_frontend.c Sat Sep 14 23:56:20 2002 @@ -228,13 +228,24 @@ } read_unlock(&inetdev_lock); - if (in_dev == NULL) + if (in_dev == NULL) { goto e_inval; + } - if (fib_lookup(&key, &res)) + if (fib_lookup(&key, &res)) { goto last_resort; - if (res.type != RTN_UNICAST) - goto e_inval_res; + } + + if (res.type != RTN_UNICAST) { + if ((res.type == RTN_LOCAL) && + (dev->priv_flags & IFF_ACCEPT_LOCAL_ADDRS)) { + /* All is OK */ + } + else { + goto e_inval_res; + } + } + *spec_dst = FIB_RES_PREFSRC(res); fib_combine_itag(itag, &res); #ifdef CONFIG_IP_ROUTE_MULTIPATH --- linux-2.4.18-5/net/ipv4/ip_output.c Sat Sep 14 23:55:25 2002 +++ linux-2.4.18-5.dev/net/ipv4/ip_output.c Sat Sep 14 23:56:20 2002 @@ -965,7 +965,7 @@ daddr = replyopts.opt.faddr; } - if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0)) + if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), sk->bound_dev_if)) return; /* And let IP do all the hard work. --- linux-2.4.18-5/net/ipv4/tcp_ipv4.c Sat Sep 14 23:55:25 2002 +++ linux-2.4.18-5.dev/net/ipv4/tcp_ipv4.c Sat Sep 14 23:56:20 2002 @@ -865,21 +865,32 @@ return h&(TCP_SYNQ_HSIZE-1); } +/** Netdevice ID can be wild-carded by making it zero. + */ static struct open_request *tcp_v4_search_req(struct tcp_opt *tp, struct open_request ***prevp, __u16 rport, - __u32 raddr, __u32 laddr) + __u32 raddr, __u32 laddr, + int netdevice_id) { struct tcp_listen_opt *lopt = tp->listen_opt; struct open_request *req, **prev; + /* Will only take netdevice_id into the equation if neither are + * 0. This should be backwards compatible with older code, and also + * let us connect to ourselves over external ports. Otherwise, we + * get confused about which connection is the originator v/s the + * receiver of the open request. --Ben + */ for (prev = &lopt->syn_table[tcp_v4_synq_hash(raddr, rport)]; (req = *prev) != NULL; prev = &req->dl_next) { if (req->rmt_port == rport && req->af.v4_req.rmt_addr == raddr && req->af.v4_req.loc_addr == laddr && - TCP_INET_FAMILY(req->class->family)) { + TCP_INET_FAMILY(req->class->family) && + ((!netdevice_id) || (!req->bound_dev_if) || + (req->bound_dev_if == netdevice_id))) { BUG_TRAP(req->sk == NULL); *prevp = prev; return req; @@ -899,7 +910,8 @@ req->retrans = 0; req->sk = NULL; req->dl_next = lopt->syn_table[h]; - + req->bound_dev_if = sk->bound_dev_if; + write_lock(&tp->syn_wait_lock); lopt->syn_table[h] = req; write_unlock(&tp->syn_wait_lock); @@ -979,7 +991,8 @@ struct sock *sk; __u32 seq; int err; - + int netdevice_id = 0; + if (skb->len < (iph->ihl << 2) + 8) { ICMP_INC_STATS_BH(IcmpInErrors); return; @@ -1048,9 +1061,13 @@ if (sk->lock.users != 0) goto out; + if (skb->dev) { + netdevice_id = skb->dev->ifindex; + } + req = tcp_v4_search_req(tp, &prev, th->dest, - iph->daddr, iph->saddr); + iph->daddr, iph->saddr, netdevice_id); if (!req) goto out; @@ -1394,7 +1411,7 @@ #define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */ #endif - /* Never answer to SYNs send to broadcast or multicast */ + /* Never answer to SYNs sent to broadcast or multicast */ if (((struct rtable *)skb->dst)->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) goto drop; @@ -1452,6 +1469,8 @@ req->af.v4_req.rmt_addr = saddr; req->af.v4_req.opt = tcp_v4_save_options(sk, skb); req->class = &or_ipv4; + req->bound_dev_if = sk->bound_dev_if; + if (!want_cookie) TCP_ECN_create_request(req, skb->h.th); @@ -1587,11 +1606,12 @@ struct iphdr *iph = skb->nh.iph; struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct sock *nsk; - + int device_id = tcp_v4_iif(skb); + /* Find possible connection requests. */ req = tcp_v4_search_req(tp, &prev, th->source, - iph->saddr, iph->daddr); + iph->saddr, iph->daddr, device_id); if (req) return tcp_check_req(sk, skb, req, prev); @@ -1599,7 +1619,7 @@ th->source, skb->nh.iph->daddr, ntohs(th->dest), - tcp_v4_iif(skb)); + device_id); if (nsk) { if (nsk->state != TCP_TIME_WAIT) {