--- zzzz-none-000/linux-2.6.39.4/net/ipv4/arp.c 2011-08-03 19:43:28.000000000 +0000 +++ puma6-atom-6490-729/linux-2.6.39.4/net/ipv4/arp.c 2021-11-10 13:38:18.000000000 +0000 @@ -729,6 +729,80 @@ } EXPORT_SYMBOL(arp_xmit); +#ifdef CONFIG_AVM_PUMA6_ARP_REPLY_SPOOF + +static int arp_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev); + +static __be32 arp_fake_ip __read_mostly; +static unsigned char arp_fake_hw[ETH_ALEN] __read_mostly; + +#define TOIPADDR(a,b,c,d) ((((a)&0xff)<<24)|(((b)&0xff)<<16)|(((c)&0xff)<<8)|((d)&0xff)) + +#include + +static __init void arp_init_avm_puma6_arp_reply_spoof(void) +{ + const char *val; +#ifdef CONFIG_ARM + char env[] = "macb"; + arp_fake_ip = __constant_htonl(TOIPADDR(169,254,1,2)); +#else + char env[] = "maca"; + arp_fake_ip = __constant_htonl(TOIPADDR(169,254,1,1)); +#endif + val = prom_getmac(env, arp_fake_hw); + if (unlikely(!val)) { + panic("\"%s\" missing from urlader environment for other core's mac address\n", env); + return; + } +} + +/* must be called from softiq context because arp_rcv() assumes this context + * due to normally being called via netif_receive_skb() */ +static void arp_reply_spoof(struct sk_buff *skb, struct net_device *dev, + __be32 dest_ip, unsigned char *hw) +{ + struct arphdr *arp; + unsigned char *p; + size_t copy_n; + + arp = arp_hdr(skb); + arp->ar_op = __constant_htons(ARPOP_REPLY); + + p = (unsigned char *)(arp+1); + copy_n = ETH_ALEN + sizeof(u32); + /* copy sender information into receiver fields */ + memcpy(p + copy_n, p, copy_n); + /* fill in new sender, this should be the other core */ + /* copy requested ip address */ + memcpy(p + ETH_ALEN, &dest_ip, sizeof(dest_ip)); + /* at last fill in the resolved mac address */ + memcpy(p, hw, ETH_ALEN); + /* arp_rcv ignores the last 2 parameters */ + arp_rcv(skb, dev, NULL, NULL); + printk(KERN_INFO "Faked arp reply for %pI4 (%pM)\n", &dest_ip, hw); +} + + +/* + * Use tasklet to perform the actual fake-reply because it must be promoted to + * softirq, because to arp_rcv() assumes to be called in softirq context. + * arp_send can also be called from process context */ +static struct sk_buff *arp_spoof_skb; +static struct net_device *arp_spoof_ndev; + +static void arp_spoof_fn(unsigned long data) +{ + (void) data; + + arp_reply_spoof(arp_spoof_skb, arp_spoof_ndev, arp_fake_ip, arp_fake_hw); +} + +static DECLARE_TASKLET(arp_spoof_task, arp_spoof_fn, 0); + +#endif + /* * Create and send an arp packet. */ @@ -751,6 +825,21 @@ if (skb == NULL) return; +#ifdef CONFIG_AVM_PUMA6_ARP_REPLY_SPOOF + if (unlikely(type == ARPOP_REQUEST && dest_ip == arp_fake_ip)) { + /* tasklet data is modified, therefore the tasklet must not be running + * simultaneously, if it is already running this arp request will not get a reply + * and has to be retried (do not wait because we might be in (soft)irq context) */ + if (tasklet_trylock(&arp_spoof_task)) { + arp_spoof_skb = skb; + arp_spoof_ndev = dev; + tasklet_schedule(&arp_spoof_task); + tasklet_unlock(&arp_spoof_task); + } + return; + } +#endif + arp_xmit(skb); } EXPORT_SYMBOL(arp_send); @@ -1316,6 +1405,9 @@ neigh_sysctl_register(NULL, &arp_tbl.parms, "ipv4", NULL); #endif register_netdevice_notifier(&arp_netdev_notifier); +#ifdef CONFIG_AVM_PUMA6_ARP_REPLY_SPOOF + arp_init_avm_puma6_arp_reply_spoof(); +#endif } #ifdef CONFIG_PROC_FS