Commit 64233bff authored by Oliver Dawid's avatar Oliver Dawid Committed by David S. Miller

[APPLETALK]: Fix broadcast bug.

From: Oliver Dawid <oliver@helios.de>

we found a bug in net/appletalk/ddp.c concerning broadcast packets. In 
kernel 2.4 it was working fine. The bug first occured 4 years ago when 
switching to new SNAP layer handling. This bug can be splitted up into a 
sending(1) and reception(2) problem:

Sending(1)
In kernel 2.4 broadcast packets were sent to a matching ethernet device 
and atalk_rcv() was called to receive it as "loopback" (so loopback 
packets were shortcutted and handled in DDP layer).

When switching to the new SNAP structure, this shortcut was removed and 
the loopback packet was send to SNAP layer. The author forgot to replace 
the remote device pointer by the loopback device pointer before sending 
the packet to SNAP layer (by calling ddp_dl->request() ) therfor the 
packet was not sent back by underlying layers to ddp's atalk_rcv().

Reception(2)
In atalk_rcv() a packet received by this loopback mechanism contains now 
the (rigth) loopback device pointer (in Kernel 2.4 it was the (wrong) 
remote ethernet device pointer) and therefor no matching socket will be 
found to deliver this packet to. Because a broadcast packet should be 
send to the first matching socket (as it is done in many other protocols 
(?)), we removed the network comparison in broadcast case.

Below you will find a patch to correct this bug. Its diffed to kernel 
2.6.14-rc1
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ba645c16
...@@ -100,8 +100,7 @@ static struct sock *atalk_search_socket(struct sockaddr_at *to, ...@@ -100,8 +100,7 @@ static struct sock *atalk_search_socket(struct sockaddr_at *to,
continue; continue;
if (to->sat_addr.s_net == ATADDR_ANYNET && if (to->sat_addr.s_net == ATADDR_ANYNET &&
to->sat_addr.s_node == ATADDR_BCAST && to->sat_addr.s_node == ATADDR_BCAST)
at->src_net == atif->address.s_net)
goto found; goto found;
if (to->sat_addr.s_net == at->src_net && if (to->sat_addr.s_net == at->src_net &&
...@@ -1443,8 +1442,10 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -1443,8 +1442,10 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
else else
atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode); atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode);
/* Not ours, so we route the packet via the correct AppleTalk iface */
if (!atif) { if (!atif) {
/* Not ours, so we route the packet via the correct
* AppleTalk iface
*/
atalk_route_packet(skb, dev, ddp, &ddphv, origlen); atalk_route_packet(skb, dev, ddp, &ddphv, origlen);
goto out; goto out;
} }
...@@ -1592,9 +1593,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr ...@@ -1592,9 +1593,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) { if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) {
rt = atrtr_find(&usat->sat_addr); rt = atrtr_find(&usat->sat_addr);
if (!rt)
return -ENETUNREACH;
dev = rt->dev; dev = rt->dev;
} else { } else {
struct atalk_addr at_hint; struct atalk_addr at_hint;
...@@ -1603,11 +1601,12 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr ...@@ -1603,11 +1601,12 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
at_hint.s_net = at->src_net; at_hint.s_net = at->src_net;
rt = atrtr_find(&at_hint); rt = atrtr_find(&at_hint);
dev = rt->dev;
}
if (!rt) if (!rt)
return -ENETUNREACH; return -ENETUNREACH;
dev = rt->dev; dev = rt->dev;
}
SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n", SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n",
sk, size, dev->name); sk, size, dev->name);
...@@ -1677,6 +1676,20 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr ...@@ -1677,6 +1676,20 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk); SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk);
/* loop back */ /* loop back */
skb_orphan(skb); skb_orphan(skb);
if (ddp->deh_dnode == ATADDR_BCAST) {
struct atalk_addr at_lo;
at_lo.s_node = 0;
at_lo.s_net = 0;
rt = atrtr_find(&at_lo);
if (!rt) {
kfree_skb(skb);
return -ENETUNREACH;
}
dev = rt->dev;
skb->dev = dev;
}
ddp_dl->request(ddp_dl, skb, dev->dev_addr); ddp_dl->request(ddp_dl, skb, dev->dev_addr);
} else { } else {
SOCK_DEBUG(sk, "SK %p: send out.\n", sk); SOCK_DEBUG(sk, "SK %p: send out.\n", sk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment