diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ipoe/ipoe.c | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index c2ff3ba..ceab7c9 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -138,6 +138,8 @@ static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer); static int ipoe_queue_u(struct sk_buff *skb, __be32 addr); static int ipoe_lookup1_u(__be32 addr, unsigned long *ts); +static struct net *pick_net(struct sk_buff *skb); + static const struct net_device_ops ipoe_netdev_ops; static struct genl_family ipoe_nl_family; @@ -223,6 +225,33 @@ static int ipoe_check_exclude(__be32 addr) return r; } +static int check_nat_required(struct sk_buff *skb, struct net_device *link) +{ + struct net *net = pick_net(skb); + struct rtable *rt; + struct flowi4 fl4; + struct iphdr *iph = ip_hdr(skb); + int r = 0; + + if (!list_empty(&ipoe_networks)) + return ipoe_check_network(iph->daddr) == 0; + + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = iph->daddr; + fl4.flowi4_tos = RT_TOS(0); + fl4.flowi4_scope = RT_SCOPE_UNIVERSE; + rt = ip_route_output_key(net, &fl4); + if (IS_ERR(rt)) + return 0; + + if (rt->rt_gateway || (rt->dst.dev != link && rt->dst.dev != skb->dev)) + r = 1; + + ip_rt_put(rt); + + return r; +} + static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer) { struct iphdr *iph; @@ -703,7 +732,6 @@ static rx_handler_result_t ipoe_recv(struct sk_buff **pskb) struct net_device *out = NULL; struct ipoe_session *ses = NULL; struct iphdr *iph = NULL; - struct _arphdr *arph = NULL; struct ethhdr *eth = eth_hdr(skb); int noff; struct net_device_stats *stats; @@ -724,7 +752,9 @@ static rx_handler_result_t ipoe_recv(struct sk_buff **pskb) iph = ip_hdr(skb); saddr = iph->saddr; - } else if (likely(skb->protocol == htons(ETH_P_ARP))) { + } /*else if (likely(skb->protocol == htons(ETH_P_ARP))) { + struct _arphdr *arph = NULL; + noff = skb_network_offset(skb); if (skb->len < sizeof(*arph)) @@ -745,7 +775,7 @@ static rx_handler_result_t ipoe_recv(struct sk_buff **pskb) return RX_HANDLER_PASS; saddr = arph->ar_sip; - } else + }*/ else return RX_HANDLER_PASS; if (!saddr || saddr == 0xffffffff) @@ -788,7 +818,7 @@ static rx_handler_result_t ipoe_recv(struct sk_buff **pskb) else if (memcmp(eth->h_source, ses->hwaddr, ETH_ALEN)) goto drop; - if (ses->addr > 1 && ipoe_do_nat(skb, ses->addr, 0)) + if (ses->addr > 1 && check_nat_required(skb, ses->link_dev) && ipoe_do_nat(skb, ses->addr, 0)) goto drop; skb->dev = ses->dev; |