--- 242/include/net/neighbour.h 2003-07-20 19:42:33.000000000 -0400 +++ 242/include/net/patchedneighbour.h 2003-07-20 19:42:38.000000000 -0400 @@ -180,6 +180,7 @@ extern void neigh_destroy(struct neighbour *neigh); extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp); +extern int neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); extern int neigh_resolve_output(struct sk_buff *skb); extern int neigh_connected_output(struct sk_buff *skb); --- 242/net/core/neighbour.c 2003-07-20 19:38:19.000000000 -0400 +++ 242/net/core/patchedneighbour.c 2003-08-18 07:15:35.000000000 -0400 @@ -50,6 +50,7 @@ static void neigh_app_notify(struct neighbour *n); #endif static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); +int neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); static int neigh_glbl_allocs; static struct neigh_table *neigh_tables; @@ -410,6 +411,52 @@ return -ENOENT; } +void update_neigh_hh(struct neighbour *neigh) +{ + + struct hh_cache *hh; + + int (*update)(struct neighbour *neigh, struct hh_cache *hh) = + neigh->dev->hard_header_cache; + + if (update) { + for (hh=neigh->hh; hh; hh=hh->hh_next) { + write_lock_bh(&hh->hh_lock); + update(neigh, hh); + write_unlock_bh(&hh->hh_lock); + } + } + else { + printk("device neigh %p does not have a update method!\n",neigh); + } +} + +int neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) +{ + int i; + + write_lock_bh(&tbl->lock); + + for (i=0; i<=NEIGH_HASHMASK; i++) { + struct neighbour *n, **np; + + np = &tbl->hash_buckets[i]; + while ((n = *np) != NULL) { + if (dev && n->dev != dev) { + np = &n->next; + continue; + } + *np = n->next; + write_lock_bh(&n->lock); + update_neigh_hh(n); + write_unlock_bh(&n->lock); + } + } + + write_unlock_bh(&tbl->lock); + return 0; +} + static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev) { struct pneigh_entry *n, **np; @@ -432,6 +479,7 @@ } + /* * neighbour must already be out of the table; * @@ -488,8 +536,9 @@ neigh->output = neigh->ops->output; - for (hh = neigh->hh; hh; hh = hh->hh_next) + for (hh = neigh->hh; hh; hh = hh->hh_next) { hh->hh_output = neigh->ops->output; + } } /* Neighbour state is OK; @@ -507,8 +556,10 @@ neigh->output = neigh->ops->connected_output; - for (hh = neigh->hh; hh; hh = hh->hh_next) + for (hh = neigh->hh; hh; hh = hh->hh_next) { hh->hh_output = neigh->ops->hh_output; + } + } /* @@ -924,6 +975,7 @@ atomic_inc(&hh->hh_refcnt); dst->hh = hh; } + } /* This function can be used in contexts, where only old dev_queue_xmit @@ -961,6 +1013,7 @@ int err; struct net_device *dev = neigh->dev; if (dev->hard_header_cache && dst->hh == NULL) { + write_lock_bh(&neigh->lock); if (dst->hh == NULL) neigh_hh_init(neigh, dst, dst->ops->protocol); --- 242/net/ipv4/arp.c 2003-07-20 19:37:52.000000000 -0400 +++ 242/net/ipv4/patchedarp.c 2003-08-18 07:19:08.000000000 -0400 @@ -1,6 +1,6 @@ /* linux/net/inet/arp.c * - * Version: $Id: arp.c,v 1.90 2000/10/04 09:20:56 anton Exp $ + * Version: $Id: arp.c,v 1.1 2003/07/04 14:04:46 root Exp root $ * * Copyright (C) 1994 by Florian La Roche * @@ -123,6 +123,7 @@ static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); static void parp_redo(struct sk_buff *skb); +static int arp_n_event(struct notifier_block *this, unsigned long event, void *ptr); static struct neigh_ops arp_generic_ops = { AF_INET, @@ -1140,6 +1141,30 @@ } #endif + +struct notifier_block arp_netdev_notifier = { + arp_n_event, + NULL, + 0 +}; + +static int arp_n_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct net_device *dev = (struct net_device *)(ptr) ; + + switch (event) { + default: + break; + case NETDEV_CHANGEADDR: + neigh_changeaddr(&arp_tbl, dev); + break; + } + + return NOTIFY_DONE; + +} + + /* Note, that it is not on notifier chain. It is necessary, that this routine was called after route cache will be flushed. @@ -1174,6 +1199,7 @@ #ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4"); #endif + register_netdevice_notifier(&arp_netdev_notifier); }