summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ipoe/ipoe.c38
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;