SO_BINDTODEVICE in 2.1.57

David Woodhouse (D.W.Woodhouse@nortel.co.uk)
Thu, 25 Sep 1997 20:05:51 +0100


This is a multipart MIME message.

--===_0_Thu_Sep_25_20:05:15_BST_1997
Content-Type: text/plain; charset=us-ascii

Would people care to test this, please?

--===_0_Thu_Sep_25_20:05:15_BST_1997
Content-Type: application/octet-stream
Content-Description: so_bind-57

diff -uNr linux-2.1.57-7/Makefile linux/Makefile
--- linux-2.1.57-7/Makefile Thu Sep 25 10:33:35 1997
+++ linux/Makefile Thu Sep 25 16:26:00 1997
@@ -88,7 +88,7 @@
# standard CFLAGS
#

-CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+CFLAGS = -Wall -Wno-sign-compare -Wstrict-prototypes -O2 -fomit-frame-pointer

ifdef CONFIG_CPP
CFLAGS := $(CFLAGS) -x c++
diff -uNr linux-2.1.57-7/include/asm-i386/socket.h linux/include/asm-i386/socket.h
--- linux-2.1.57-7/include/asm-i386/socket.h Thu Mar 27 22:40:06 1997
+++ linux/include/asm-i386/socket.h Thu Sep 25 13:15:39 1997
@@ -33,4 +33,6 @@
#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
#define SO_SECURITY_ENCRYPTION_NETWORK 24

+#define SO_BINDTODEVICE 25
+
#endif /* _ASM_SOCKET_H */
diff -uNr linux-2.1.57-7/include/net/raw.h linux/include/net/raw.h
--- linux-2.1.57-7/include/net/raw.h Tue Mar 4 18:25:26 1997
+++ linux/include/net/raw.h Thu Sep 25 14:13:34 1997
@@ -32,6 +32,7 @@


extern struct sock *raw_v4_lookup(struct sock *sk, unsigned short num,
- unsigned long raddr, unsigned long laddr);
+ unsigned long raddr, unsigned long laddr,
+ struct device *dev);

#endif /* _RAW_H */
diff -uNr linux-2.1.57-7/include/net/route.h linux/include/net/route.h
--- linux-2.1.57-7/include/net/route.h Wed Sep 24 12:45:08 1997
+++ linux/include/net/route.h Thu Sep 25 19:43:38 1997
@@ -136,17 +136,17 @@
}


-static __inline__ int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos)
+static __inline__ int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, struct device *dev)
{
int err;
- err = ip_route_output(rp, dst, src, tos, NULL);
+ err = ip_route_output(rp, dst, src, tos, dev);
if (err || (dst && src))
return err;
dst = (*rp)->rt_dst;
src = (*rp)->rt_src;
ip_rt_put(*rp);
*rp = NULL;
- return ip_route_output(rp, dst, src, tos, NULL);
+ return ip_route_output(rp, dst, src, tos, dev);
}

static __inline__ void ip_ll_header(struct sk_buff *skb)
diff -uNr linux-2.1.57-7/include/net/sock.h linux/include/net/sock.h
--- linux-2.1.57-7/include/net/sock.h Wed Sep 24 12:40:33 1997
+++ linux/include/net/sock.h Thu Sep 25 19:38:17 1997
@@ -374,6 +374,7 @@
broadcast,
nonagle,
bsdism;
+ struct device *bound_device;
unsigned long lingertime;
int proc;

diff -uNr linux-2.1.57-7/net/core/sock.c linux/net/core/sock.c
--- linux-2.1.57-7/net/core/sock.c Thu Sep 25 10:33:44 1997
+++ linux/net/core/sock.c Thu Sep 25 19:07:25 1997
@@ -143,6 +143,7 @@
int valbool;
int err;
struct linger ling;
+ struct ifreq req;
int ret = 0;

/*
@@ -317,6 +318,45 @@
return -EINVAL;
break;
#endif
+ case SO_BINDTODEVICE:
+ /* Bind this socket to a particular device like "eth0",
+ * as specified in an ifreq structure. If the device
+ * is "", socket is NOT bound to a device.
+ */
+
+ if (!valbool) {
+ sk->bound_device = NULL;
+ }
+ else {
+ if (copy_from_user(&req, optval, sizeof(req)) < 0)
+ return -EFAULT;
+
+ /* Remove any cached route for this socket. */
+ if (sk->dst_cache) {
+ ip_rt_put((struct rtable*)sk->dst_cache);
+ sk->dst_cache = NULL;
+ }
+
+ if (req.ifr_ifrn.ifrn_name[0] == '\0') {
+ sk->bound_device = NULL;
+ }
+ else {
+ sk->bound_device = dev_get(req.ifr_ifrn.ifrn_name);
+ if (!sk->bound_device)
+ return -EINVAL;
+ if (sk->daddr) {
+ int ret;
+ ret = ip_route_output((struct rtable**)&sk->dst_cache,
+ sk->daddr, sk->saddr,
+ sk->ip_tos, sk->bound_device);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ return 0;
+
+
/* We implement the SO_SNDLOWAT etc to
not be settable (1003.1g 5.3) */
default:
diff -uNr linux-2.1.57-7/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- linux-2.1.57-7/net/ipv4/icmp.c Thu Sep 4 21:25:28 1997
+++ linux/net/ipv4/icmp.c Thu Sep 25 14:13:31 1997
@@ -770,12 +770,12 @@
hash = iph->protocol & (MAX_INET_PROTOS - 1);
if ((raw_sk = raw_v4_htable[hash]) != NULL)
{
- raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr);
+ raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr, skb->dev);
while (raw_sk)
{
raw_err(raw_sk, skb);
raw_sk = raw_v4_lookup(raw_sk->next, iph->protocol,
- iph->saddr, iph->daddr);
+ iph->saddr, iph->daddr, skb->dev);
}
}

@@ -1000,8 +1000,8 @@
*/

/* This should work with the new hashes now. -DaveM */
-extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport);
-extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport);
+extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev);
+extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev);

int icmp_chkaddr(struct sk_buff *skb)
{
@@ -1017,7 +1017,7 @@
{
struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2));

- sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source);
+ sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev);
if (!sk) return 0;
if (sk->saddr != iph->saddr) return 0;
if (sk->daddr != iph->daddr) return 0;
@@ -1031,7 +1031,7 @@
{
struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph)+(iph->ihl<<2));

- sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source);
+ sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev);
if (!sk) return 0;
if (sk->saddr != iph->saddr && __ip_chk_addr(iph->saddr) != IS_MYADDR)
return 0;
diff -uNr linux-2.1.57-7/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- linux-2.1.57-7/net/ipv4/ip_input.c Thu Mar 27 22:40:15 1997
+++ linux/net/ipv4/ip_input.c Thu Sep 25 17:04:39 1997
@@ -256,12 +256,12 @@
if((raw_sk = raw_v4_htable[hash]) != NULL) {
struct sock *sknext = NULL;
struct sk_buff *skb1;
- raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr);
+ raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr, skb->dev);
if(raw_sk) { /* Any raw sockets */
do {
/* Find the next */
sknext = raw_v4_lookup(raw_sk->next, iph->protocol,
- iph->saddr, iph->daddr);
+ iph->saddr, iph->daddr, skb->dev);
if(sknext)
skb1 = skb_clone(skb, GFP_ATOMIC);
else
diff -uNr linux-2.1.57-7/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- linux-2.1.57-7/net/ipv4/ip_output.c Thu Sep 4 21:25:28 1997
+++ linux/net/ipv4/ip_output.c Thu Sep 25 15:06:57 1997
@@ -92,7 +92,7 @@
daddr = opt->faddr;

err = ip_route_output(&rt, daddr, saddr, RT_TOS(sk->ip_tos) |
- (sk->localroute||0), NULL);
+ (sk->localroute||0), sk->bound_device);
if (err)
{
ip_statistics.IpOutNoRoutes++;
@@ -172,7 +172,7 @@
if (!rt || rt->u.dst.obsolete) {
ip_rt_put(rt);
err = ip_route_output(&rt, daddr, sk->saddr, RT_TOS(sk->ip_tos) |
- (sk->localroute||0), NULL);
+ (sk->localroute||0), sk->bound_device);
if (err)
return err;
sk->dst_cache = &rt->u.dst;
diff -uNr linux-2.1.57-7/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- linux-2.1.57-7/net/ipv4/ip_sockglue.c Thu Sep 4 21:25:28 1997
+++ linux/net/ipv4/ip_sockglue.c Thu Sep 25 17:07:27 1997
@@ -325,7 +325,8 @@
{
struct in_addr addr;
struct device *dev = NULL;
-
+ char *skdevname = sk->bound_device?sk->bound_device->name:NULL;
+
/*
* Check the arguments are allowable
*/
@@ -352,7 +353,7 @@
* Find the device
*/

- dev=ip_dev_find(addr.s_addr, NULL);
+ dev=ip_dev_find(addr.s_addr, skdevname);

/*
* Did we find one
@@ -376,6 +377,7 @@
struct ip_mreq mreq;
struct rtable *rt;
struct device *dev=NULL;
+ char *skdevname = sk->bound_device?sk->bound_device->name:NULL;

/*
* Check the arguments.
@@ -391,13 +393,13 @@
*/

if (mreq.imr_interface.s_addr==INADDR_ANY) {
- err = ip_route_output(&rt, mreq.imr_multiaddr.s_addr, 0, 1, NULL);
+ err = ip_route_output(&rt, mreq.imr_multiaddr.s_addr, 0, 1, sk->bound_device);
if (err)
return err;
dev = rt->u.dst.dev;
ip_rt_put(rt);
} else
- dev = ip_dev_find(mreq.imr_interface.s_addr, NULL);
+ dev = ip_dev_find(mreq.imr_interface.s_addr, skdevname);

/*
* No device, no cookies.
@@ -418,6 +420,7 @@
struct ip_mreq mreq;
struct rtable *rt;
struct device *dev=NULL;
+ char *skdevname = sk->bound_device?sk->bound_device->name:NULL;

/*
* Check the arguments
@@ -439,7 +442,7 @@
dev = rt->u.dst.dev;
ip_rt_put(rt);
} else
- dev = ip_dev_find(mreq.imr_interface.s_addr, NULL);
+ dev = ip_dev_find(mreq.imr_interface.s_addr, skdevname);

/*
* Did we find a suitable device.
@@ -459,6 +462,7 @@
{
struct ip_mreqn mreq;
struct device *dev = NULL;
+ char *skdevname = sk->bound_device?sk->bound_device->name:NULL;

if(optlen<sizeof(mreq))
return -EINVAL;
@@ -471,7 +475,7 @@
sk->ip_mc_addr = 0;
return 0;
}
- dev = ip_dev_find(mreq.imr_address.s_addr, NULL);
+ dev = ip_dev_find(mreq.imr_address.s_addr, skdevname);
} else
dev = dev_get_by_index(mreq.imr_ifindex);

diff -uNr linux-2.1.57-7/net/ipv4/raw.c linux/net/ipv4/raw.c
--- linux-2.1.57-7/net/ipv4/raw.c Thu Jun 26 20:33:41 1997
+++ linux/net/ipv4/raw.c Thu Sep 25 17:01:46 1997
@@ -126,7 +126,8 @@

/* Grumble... icmp and ip_input want to get at this... */
struct sock *raw_v4_lookup(struct sock *sk, unsigned short num,
- unsigned long raddr, unsigned long laddr)
+ unsigned long raddr, unsigned long laddr,
+ struct device *dev)
{
struct sock *s = sk;

@@ -135,7 +136,8 @@
if((s->num == num) &&
!(s->dead && (s->state == TCP_CLOSE)) &&
!(s->daddr && s->daddr != raddr) &&
- !(s->rcv_saddr && s->rcv_saddr != laddr))
+ !(s->rcv_saddr && s->rcv_saddr != laddr) &&
+ !(s->bound_device && s->bound_device != dev))
break; /* gotcha */
}
SOCKHASH_UNLOCK();
@@ -252,7 +254,7 @@
static int raw_sendto(struct sock *sk, const unsigned char *from,
int len, struct msghdr *msg)
{
- struct device *dev = NULL;
+ struct device *dev = sk->bound_device;
struct ipcm_cookie ipc;
struct rawfakehdr rfh;
struct rtable *rt;
diff -uNr linux-2.1.57-7/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- linux-2.1.57-7/net/ipv4/tcp_ipv4.c Wed Sep 24 10:46:51 1997
+++ linux/net/ipv4/tcp_ipv4.c Thu Sep 25 18:37:17 1997
@@ -116,6 +116,12 @@
unsigned char state = sk2->state;
int sk2_reuse = sk2->reuse;

+ /* Two sockets can be bound to the same port if they're
+ * bound to different interfaces..
+ */
+ if (sk->bound_device != sk2->bound_device)
+ continue;
+
if(!sk2->rcv_saddr || !sk->rcv_saddr) {
if((!sk2_reuse) ||
(!sk_reuse) ||
@@ -301,20 +307,35 @@
* connection. So always assume those are both wildcarded
* during the search since they can never be otherwise.
*/
-static struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum)
+static struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum,
+ struct device *dev)
{
struct sock *sk;
struct sock *result = NULL;
+ int score, hiscore;

+ hiscore = 0;
for(sk = tcp_listening_hash[tcp_lhashfn(hnum)]; sk; sk = sk->next) {
if(sk->num == hnum) {
__u32 rcv_saddr = sk->rcv_saddr;
+ score = 1;

if(rcv_saddr) {
- if(rcv_saddr == daddr)
- return sk; /* Best possible match. */
- } else if(!result)
+ if (rcv_saddr != daddr)
+ continue;
+ score++;
+ }
+ if (sk->bound_device) {
+ if (dev != sk->bound_device)
+ continue;
+ score++;
+ }
+ if (score == 3)
+ return sk; /* Best possible match */
+ if (score > hiscore) {
+ hiscore = score;
result = sk;
+ }
}
}
return result;
@@ -323,8 +344,8 @@
/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
* we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
*/
-static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
- u32 saddr, u16 sport, u32 daddr, u16 dport)
+static inline struct sock *__tcp_v4_lookup(struct tcphdr *th, u32 saddr, u16 sport,
+ u32 daddr, u16 dport, struct device *dev)
{
unsigned short hnum = ntohs(dport);
struct sock *sk;
@@ -335,28 +356,30 @@
* gets called from within NET_BH.
*/
for(sk = tcp_established_hash[hash]; sk; sk = sk->next)
- if(sk->daddr == saddr && /* remote address */
- sk->dummy_th.dest == sport && /* remote port */
- sk->num == hnum && /* local port */
- sk->rcv_saddr == daddr) /* local address */
+ if(sk->daddr == saddr && /* remote address */
+ sk->dummy_th.dest == sport && /* remote port */
+ sk->num == hnum && /* local port */
+ sk->rcv_saddr == daddr && /* local address */
+ ((!sk->bound_device) || (sk->bound_device == dev))) /* bound device */
goto hit; /* You sunk my battleship! */

/* Must check for a TIME_WAIT'er before going to listener hash. */
for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
- if(sk->daddr == saddr && /* remote address */
- sk->dummy_th.dest == sport && /* remote port */
- sk->num == hnum && /* local port */
- sk->rcv_saddr == daddr) /* local address */
+ if(sk->daddr == saddr && /* remote address */
+ sk->dummy_th.dest == sport && /* remote port */
+ sk->num == hnum && /* local port */
+ sk->rcv_saddr == daddr && /* local address */
+ ((!sk->bound_device) || (sk->bound_device == dev))) /* bound device */
goto hit;

- sk = tcp_v4_lookup_listener(daddr, hnum);
+ sk = tcp_v4_lookup_listener(daddr, hnum, dev);
hit:
return sk;
}

-__inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport)
+__inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev)
{
- return __tcp_v4_lookup(0, saddr, sport, daddr, dport);
+ return __tcp_v4_lookup(0, saddr, sport, daddr, dport, dev);
}

#ifdef CONFIG_IP_TRANSPARENT_PROXY
@@ -376,7 +399,8 @@

struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
unsigned short rnum, unsigned long laddr,
- unsigned long paddr, unsigned short pnum)
+ unsigned long paddr, unsigned short pnum,
+ struct device *dev)
{
struct sock *s, *result = NULL;
int badness = -1;
@@ -408,7 +432,12 @@
continue;
score++;
}
- if(score == 3 && s->num == hnum) {
+ if(s->bound_device) {
+ if(s->bound_device != dev)
+ continue;
+ score++;
+ }
+ if(score == 4 && s->num == hnum) {
result = s;
break;
} else if(score > badness && (s->num == hpnum || s->rcv_saddr)) {
@@ -517,7 +546,8 @@
}

tmp = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
- RT_TOS(sk->ip_tos)|(sk->localroute || 0));
+ RT_TOS(sk->ip_tos)|(sk->localroute || 0),
+ sk->bound_device);
if (tmp < 0)
return tmp;

@@ -784,7 +814,7 @@

th = (struct tcphdr*)(dp+(iph->ihl<<2));

- sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source);
+ sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev);
if (sk == NULL) {
icmp_statistics.IcmpInErrors++;
return;
@@ -963,7 +993,7 @@
struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);
struct sock *sk;

- sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest);
+ sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest, skb->dev);

if (!sk)
return 0;
@@ -1457,10 +1487,10 @@
#ifdef CONFIG_IP_TRANSPARENT_PROXY
if (IPCB(skb)->redirport)
sk = tcp_v4_proxy_lookup(th->dest, saddr, th->source, daddr,
- skb->dev->pa_addr, IPCB(skb)->redirport);
+ skb->dev->pa_addr, IPCB(skb)->redirport, skb->dev);
else
#endif
- sk = __tcp_v4_lookup(th, saddr, th->source, daddr, th->dest);
+ sk = __tcp_v4_lookup(th, saddr, th->source, daddr, th->dest, skb->dev);
if (!sk)
goto no_tcp_socket;
if(!ipsec_sk_policy(sk,skb))
@@ -1527,7 +1557,7 @@
static struct sock * tcp_v4_get_sock(struct sk_buff *skb, struct tcphdr *th)
{
return tcp_v4_lookup(skb->nh.iph->saddr, th->source,
- skb->nh.iph->daddr, th->dest);
+ skb->nh.iph->daddr, th->dest, skb->dev);
}

static void v4_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
diff -uNr linux-2.1.57-7/net/ipv4/udp.c linux/net/ipv4/udp.c
--- linux-2.1.57-7/net/ipv4/udp.c Sat May 24 17:10:26 1997
+++ linux/net/ipv4/udp.c Thu Sep 25 18:36:36 1997
@@ -133,13 +133,19 @@
unsigned char state = sk2->state;
int sk2_reuse = sk2->reuse;

+ /* Two sockets can be bound to the same port if they're
+ * bound to different interfaces.
+ */
+ if(sk->bound_device != sk2->bound_device)
+ continue;
+
if(!sk2->rcv_saddr || !sk->rcv_saddr) {
if((!sk2_reuse) ||
(!sk_reuse) ||
(state == TCP_LISTEN)) {
retval = 1;
break;
- }
+ }
} else if(sk2->rcv_saddr == sk->rcv_saddr) {
if((!sk_reuse) ||
(!sk2_reuse) ||
@@ -277,7 +283,7 @@
/* UDP is nearly always wildcards out the wazoo, it makes no sense to try
* harder than this here plus the last hit cache. -DaveM
*/
-struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport)
+struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev)
{
struct sock *sk, *result = NULL;
unsigned short hnum = ntohs(dport);
@@ -301,7 +307,12 @@
continue;
score++;
}
- if(score == 3) {
+ if(sk->bound_device) {
+ if(dev != sk->bound_device)
+ continue;
+ score++;
+ }
+ if(score == 4) {
result = sk;
break;
} else if(score > badness) {
@@ -313,23 +324,28 @@
return result;
}

-__inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport)
+__inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev)
{
struct sock *sk;

- if(uh_cache_sk &&
+ if(!dev && uh_cache_sk &&
uh_cache_saddr == saddr &&
uh_cache_sport == sport &&
uh_cache_dport == dport &&
uh_cache_daddr == daddr)
return uh_cache_sk;

- sk = udp_v4_lookup_longway(saddr, sport, daddr, dport);
- uh_cache_sk = sk;
- uh_cache_saddr = saddr;
- uh_cache_daddr = daddr;
- uh_cache_sport = sport;
- uh_cache_dport = dport;
+ sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dev);
+
+ if (!dev) {
+ /* Don't cache it if it was bound to a specific device */
+ uh_cache_sk = sk;
+ uh_cache_saddr = saddr;
+ uh_cache_daddr = daddr;
+ uh_cache_sport = sport;
+ uh_cache_dport = dport;
+ }
+
return sk;
}

@@ -350,7 +366,8 @@

struct sock *udp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
unsigned short rnum, unsigned long laddr,
- unsigned long paddr, unsigned short pnum)
+ unsigned long paddr, unsigned short pnum,
+ struct device *dev)
{
struct sock *s, *result = NULL;
int badness = -1;
@@ -382,7 +399,12 @@
continue;
score++;
}
- if(score == 3 && s->num == hnum) {
+ if(s->bound_device) {
+ if(s->bound_device != dev)
+ continue;
+ score++;
+ }
+ if(score == 4 && s->num == hnum) {
result = s;
break;
} else if(score > badness && (s->num == hpnum || s->rcv_saddr)) {
@@ -405,7 +427,8 @@
unsigned short num,
unsigned long raddr,
unsigned short rnum,
- unsigned long laddr)
+ unsigned long laddr,
+ struct device *dev)
{
struct sock *s = sk;
unsigned short hnum = ntohs(num);
@@ -414,7 +437,8 @@
(s->dead && (s->state == TCP_CLOSE)) ||
(s->daddr && s->daddr!=raddr) ||
(s->dummy_th.dest != rnum && s->dummy_th.dest != 0) ||
- (s->rcv_saddr && s->rcv_saddr != laddr))
+ (s->rcv_saddr && s->rcv_saddr != laddr) ||
+ (s->bound_device && s->bound_device != dev))
continue;
break;
}
@@ -442,7 +466,7 @@
int code = skb->h.icmph->code;
struct sock *sk;

- sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source);
+ sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev);
if (sk == NULL)
return; /* No socket for error */

@@ -624,7 +648,7 @@
int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
{
int ulen = len + sizeof(struct udphdr);
- struct device *dev = NULL;
+ struct device *dev = sk->bound_device;
struct ipcm_cookie ipc;
struct udpfakehdr ufh;
struct rtable *rt;
@@ -907,7 +931,7 @@
return(-EAFNOSUPPORT);

err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
- sk->ip_tos|sk->localroute);
+ sk->ip_tos|sk->localroute, sk->bound_device);
if (err)
return err;
if ((rt->rt_flags&RTF_BROADCAST) && !sk->broadcast) {
@@ -988,7 +1012,7 @@

SOCKHASH_LOCK();
sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
- sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr);
+ sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr, skb->dev);
if(sk) {
struct sock *sknext = NULL;

@@ -996,7 +1020,7 @@
struct sk_buff *skb1 = skb;

sknext = udp_v4_mcast_next(sk->next, uh->dest, saddr,
- uh->source, daddr);
+ uh->source, daddr, skb->dev);
if(sknext)
skb1 = skb_clone(skb, GFP_ATOMIC);

@@ -1024,7 +1048,7 @@
struct udphdr *uh = (struct udphdr *)(skb->nh.raw + iph->ihl*4);
struct sock *sk;

- sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest);
+ sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, skb->dev);
if (!sk)
return 0;

@@ -1120,10 +1144,10 @@
if (IPCB(skb)->redirport)
sk = udp_v4_proxy_lookup(uh->dest, saddr, uh->source,
daddr, skb->dev->pa_addr,
- IPCB(skb)->redirport);
+ IPCB(skb)->redirport, skb->dev);
else
#endif
- sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest);
+ sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev);

if (sk == NULL) {
udp_statistics.UdpNoPorts++;

--===_0_Thu_Sep_25_20:05:15_BST_1997
Content-Type: text/plain; charset=us-ascii

David Woodhouse, CB3 9AN http://dwmw2.robinson.cam.ac.uk/
dwmw2@cam.ac.uk Tel: 0976 658355
( D.W.Woodhouse@nortel.co.uk Tel: 01279 402332 )

(Use the former; I'm going back to College next week.)

--===_0_Thu_Sep_25_20:05:15_BST_1997--