static unsigned int hwaddr_out_hook_fn(struct nf_hook_ops const *ops, #endif struct sk_buff *skb, struct net_device const *in, struct net_device const *out, int (*okfn)(struct sk_buff *)) { struct net_device *target = NULL; struct hwaddr_entry *entry = NULL; struct iphdr const *const nhdr = ip_hdr(skb); if (!out) return NF_ACCEPT; target = ip_dev_find(dev_net(out), nhdr->saddr); if (!target) return NF_ACCEPT; rcu_read_lock(); entry = hwaddr_lookup(nhdr->daddr, nhdr->saddr); if (entry) hwaddr_update_route(skb, entry); rcu_read_unlock(); dev_put(target); return NF_ACCEPT; }
static unsigned int hwaddr_output_hook( #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) unsigned unused, #else struct nf_hook_ops const *unused, #endif struct sk_buff *skb, struct net_device const *in, struct net_device const *out, int (*okfn)(struct sk_buff *)) { struct net_device *target = NULL; struct hwaddr_entry *entry = NULL; struct iphdr *nhdr = ip_hdr(skb); target = ip_dev_find(dev_net(out), nhdr->saddr); if (!target) return NF_ACCEPT; rcu_read_lock(); entry = hwaddr_lookup(nhdr->daddr, nhdr->saddr); if (entry) { dst_hold(&entry->h_dst); skb_dst_drop(skb); skb_dst_set(skb, &entry->h_dst); } rcu_read_unlock(); dev_put(target); return NF_ACCEPT; }