static int
dnat_mac(struct net_bridge_port *p, struct sk_buff *skb)
{
- struct snat_conf *sc;
+ struct snat_conf *sc = p->snat;
struct iphdr *iph = ip_hdr(skb);
struct ethhdr *eh = eth_hdr(skb);
struct snat_mapping *m;
- unsigned long flags;
- spin_lock_irqsave(&p->lock, flags);
- sc = p->snat;
- if (!sc) {
- spin_unlock_irqrestore(&p->lock, flags);
- return -EINVAL;
- }
-
- if (skb->protocol != htons(ETH_P_IP)) {
- spin_unlock_irqrestore(&p->lock, flags);
+ if (skb->protocol != htons(ETH_P_IP))
return 0;
- }
list_for_each_entry (m, &sc->mappings, node) {
if (m->ip_addr == iph->daddr){
if (!make_writable(&skb)) {
if (net_ratelimit())
printk("make_writable failed\n");
- spin_unlock_irqrestore(&p->lock, flags);
return -EINVAL;
}
m->used = jiffies;
}
}
- spin_unlock_irqrestore(&p->lock, flags);
return 0;
}
+static int
+__snat_this_address(struct snat_conf *sc, u32 ip_addr)
+{
+ if (sc) {
+ u32 h_ip_addr = ntohl(ip_addr);
+ return (h_ip_addr >= sc->ip_addr_start &&
+ h_ip_addr <= sc->ip_addr_end);
+ }
+ return 0;
+}
+
+static int
+snat_this_address(struct net_bridge_port *p, u32 ip_addr)
+{
+ unsigned long int flags;
+ int retval;
+
+ spin_lock_irqsave(&p->lock, flags);
+ retval = __snat_this_address(p->snat, ip_addr);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ return retval;
+}
+
static int
snat_pre_route_finish(struct sk_buff *skb)
{
struct net_bridge_port *p = skb->dev->br_port;
+ struct snat_conf *sc;
+ struct iphdr *iph = ip_hdr(skb);
+ unsigned long flags;
skb->dst = (struct dst_entry *)&__fake_rtable;
dst_hold(skb->dst);
+ /* Don't process packets that were not translated due to NAT */
+ spin_lock_irqsave(&p->lock, flags);
+ sc = p->snat;
+ if (__snat_this_address(sc, iph->daddr)) {
+ spin_unlock_irqrestore(&p->lock, flags);
+ return -1;
+ }
+
/* If SNAT is configured for this input device, check the IP->MAC
* mappings to see if we should update the destination MAC. */
- if (p->snat)
+ if (sc)
dnat_mac(skb->dev->br_port, skb);
+ spin_unlock_irqrestore(&p->lock, flags);
+
return 0;
}
{
struct net_bridge_port *p = skb->dev->br_port;
struct ip_arphdr *ah = (struct ip_arphdr *)arp_hdr(skb);
- uint32_t ip_addr;
- unsigned long flags;
- struct snat_conf *sc;
if ((ah->ar_op != htons(ARPOP_REQUEST))
|| ah->ar_hln != ETH_ALEN
|| ah->ar_pln != 4)
return 0;
- ip_addr = ntohl(ah->ar_tip);
- spin_lock_irqsave(&p->lock, flags);
- sc = p->snat;
-
/* We're only interested in addresses we rewrite. */
- if (!sc || (sc && ((ip_addr < sc->ip_addr_start)
- || (ip_addr > sc->ip_addr_end)))) {
- spin_unlock_irqrestore(&p->lock, flags);
+ if (!snat_this_address(p, ah->ar_tip)) {
return 0;
}
- spin_unlock_irqrestore(&p->lock, flags);
arp_send(ARPOP_REPLY, ETH_P_ARP, ah->ar_sip, skb->dev, ah->ar_tip,
ah->ar_sha, p->dp->netdev->dev_addr, ah->ar_sha);
handle_icmp_snat(struct sk_buff *skb)
{
struct net_bridge_port *p = skb->dev->br_port;
- struct snat_conf *sc;
struct ethhdr *eh;
struct iphdr *iph = ip_hdr(skb);
- uint32_t ip_addr;
struct icmphdr *icmph;
unsigned int datalen;
uint8_t tmp_eth[ETH_ALEN];
uint32_t tmp_ip;
struct sk_buff *nskb;
- unsigned long flags;
-
-
- ip_addr = ntohl(iph->daddr);
- spin_lock_irqsave(&p->lock, flags);
- sc = p->snat;
/* We're only interested in addresses we rewrite. */
- if (!sc || (sc && ((ip_addr < sc->ip_addr_start)
- || (ip_addr > sc->ip_addr_end)))) {
- spin_unlock_irqrestore(&p->lock, flags);
+ if (!snat_this_address(p, iph->daddr)) {
return 0;
}
- spin_unlock_irqrestore(&p->lock, flags);
icmph = (struct icmphdr *) ((u_int32_t *)iph + iph->ihl);
datalen = skb->len - iph->ihl * 4;
/* Update the MAC->IP mappings for the private side of the SNAT'd
* interface. */
static void
-update_mapping(struct net_bridge_port *p, struct sk_buff *skb)
+update_mapping(struct net_bridge_port *p, const struct sk_buff *skb)
{
unsigned long flags;
struct snat_conf *sc;
- struct iphdr *iph = ip_hdr(skb);
- struct ethhdr *eh = eth_hdr(skb);
+ const struct iphdr *iph = ip_hdr(skb);
+ const struct ethhdr *eh = eth_hdr(skb);
struct snat_mapping *m;
spin_lock_irqsave(&p->lock, flags);
list_for_each_entry (m, &sc->mappings, node) {
if (m->ip_addr == iph->saddr){
- if (memcmp(m->hw_addr, eh->h_source, ETH_ALEN)) {
- memcpy(m->hw_addr, eh->h_source, ETH_ALEN);
- }
+ memcpy(m->hw_addr, eh->h_source, ETH_ALEN);
m->used = jiffies;
goto done;
}
}
m = kmalloc(sizeof *m, GFP_ATOMIC);
+ if (!m)
+ goto done;
m->ip_addr = iph->saddr;
memcpy(m->hw_addr, eh->h_source, ETH_ALEN);
m->used = jiffies;
* unmodified. 'skb' is not consumed, so caller will need to free it.
*/
void
-snat_skb(struct datapath *dp, struct sk_buff *skb, int out_port)
+snat_skb(struct datapath *dp, const struct sk_buff *skb, int out_port)
{
struct net_bridge_port *p = dp->ports[out_port];
struct sk_buff *nskb;