> oups, one superfluous check forgotten to remove.
>
> note to self: in main tree on anakin (ryan sez it's the next level of
> krautcomputing)
>
> Index: net/if.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if.c,v
> retrieving revision 1.225
> diff -u -p -r1.225 if.c
> --- net/if.c 27 Aug 2010 17:08:01 -0000 1.225
> +++ net/if.c 23 Sep 2010 11:43:14 -0000
> @@ -157,6 +157,7 @@ int if_group_egress_build(void);
> int ifai_cmp(struct ifaddr_item *, struct ifaddr_item *);
> void ifa_item_insert(struct sockaddr *, struct ifaddr *, struct ifnet *);
> void ifa_item_remove(struct sockaddr *, struct ifaddr *, struct ifnet *);
> +void ifa_print_rb(void); /* XXX debug */
> RB_HEAD(ifaddr_items, ifaddr_item) ifaddr_items = RB_INITIALIZER(&ifaddr_items);
> RB_PROTOTYPE(ifaddr_items, ifaddr_item, ifai_entry, ifai_cmp);
> RB_GENERATE(ifaddr_items, ifaddr_item, ifai_entry, ifai_cmp);
> @@ -722,9 +723,11 @@ if_clone_destroy(const char *name)
> return (EINVAL);
>
> ifp = ifunit(name);
> - if (ifp == NULL)
> - return (ENXIO);
> + if (ifp == NULL) {
> +ifa_print_rb();
>
> + return (ENXIO);
> +}
> if (ifc->ifc_destroy == NULL)
> return (EOPNOTSUPP);
>
> @@ -880,32 +883,22 @@ if_congestion_clear(void *arg)
> struct ifaddr *
> ifa_ifwithaddr(struct sockaddr *addr, u_int rdomain)
> {
> - struct ifnet *ifp;
> - struct ifaddr *ifa;
> + struct ifaddr_item *ifai, key;
> +
> + bzero(&key, sizeof(key));
> + key.ifai_addr = addr;
> + key.ifai_rdomain = rtable_l2(rdomain);
> +
> + ifai = RB_FIND(ifaddr_items, &ifaddr_items, &key);
> + if (ifai)
> + return (ifai->ifai_ifa);
> + return (NULL);
> +}
>
> #define equal(a1, a2) \
> (bcmp((caddr_t)(a1), (caddr_t)(a2), \
> ((struct sockaddr *)(a1))->sa_len) == 0)
>
> - rdomain = rtable_l2(rdomain);
> - TAILQ_FOREACH(ifp, &ifnet, if_list) {
> - if (ifp->if_rdomain != rdomain)
> - continue;
> - TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
> - if (ifa->ifa_addr->sa_family != addr->sa_family)
> - continue;
> - if (equal(addr, ifa->ifa_addr))
> - return (ifa);
> - if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
> - /* IP6 doesn't have broadcast */
> - ifa->ifa_broadaddr->sa_len != 0 &&
> - equal(ifa->ifa_broadaddr, addr))
> - return (ifa);
> - }
> - }
> - return (NULL);
> -}
> -
> /*
> * Locate the point to point interface with a given destination address.
> */
> @@ -2188,12 +2181,26 @@ ifa_add(struct ifnet *ifp, struct ifaddr
> TAILQ_INSERT_HEAD(&ifp->if_addrlist, ifa, ifa_list);
> else
> TAILQ_INSERT_TAIL(&ifp->if_addrlist, ifa, ifa_list);
> + ifa_item_insert(ifa->ifa_addr, ifa, ifp);
> + if (ifp->if_flags & IFF_BROADCAST && ifa->ifa_broadaddr)
> + ifa_item_insert(ifa->ifa_broadaddr, ifa, ifp);
> }
>
> void
> ifa_del(struct ifnet *ifp, struct ifaddr *ifa)
> {
> TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
> + ifa_item_remove(ifa->ifa_addr, ifa, ifp);
> + if (ifp->if_flags & IFF_BROADCAST && ifa->ifa_broadaddr)
> + ifa_item_remove(ifa->ifa_broadaddr, ifa, ifp);
> +}
> +
> +void
> +ifa_update_broadaddr(struct ifnet *ifp, struct ifaddr *ifa, struct sockaddr *sa)
> +{
> + ifa_item_remove(ifa->ifa_broadaddr, ifa, ifp);
> + ifa->ifa_broadaddr = sa;
> + ifa_item_insert(ifa->ifa_broadaddr, ifa, ifp);
> }
>
> int
> @@ -2251,6 +2258,31 @@ ifa_item_remove(struct sockaddr *sa, str
> } else
> ifai_last->ifai_next = ifai->ifai_next;
> pool_put(&ifaddr_item_pl, ifai);
> +}
> +
> +void
> +ifa_print_rb(void)
> +{
> + struct ifaddr_item *ifai, *p;
> + RB_FOREACH(p, ifaddr_items, &ifaddr_items) {
> + for (ifai = p; ifai; ifai = ifai->ifai_next) {
> + switch (ifai->ifai_addr->sa_family) {
> + case AF_INET:
> + printf("%s", inet_ntoa((satosin(
> + ifai->ifai_addr))->sin_addr));
> + break;
> + case AF_INET6:
> + printf("%s", ip6_sprintf(&(satosin6(
> + ifai->ifai_addr))->sin6_addr));
> + break;
> + case AF_LINK:
> + printf("%s",
> + ether_sprintf(ifai->ifai_addr->sa_data));
> + break;
> + }
> + printf(" on %s\n", ifai->ifai_ifa->ifa_ifp->if_xname);
> + }
> + }
> }
>
> void
> Index: net/if.h
> ===================================================================
> RCS file: /cvs/src/sys/net/if.h,v
> retrieving revision 1.118
> diff -u -p -r1.118 if.h
> --- net/if.h 27 Aug 2010 17:08:01 -0000 1.118
> +++ net/if.h 23 Sep 2010 11:43:14 -0000
> @@ -848,5 +848,7 @@ int looutput(struct ifnet *,
> void lortrequest(int, struct rtentry *, struct rt_addrinfo *);
> void ifa_add(struct ifnet *, struct ifaddr *);
> void ifa_del(struct ifnet *, struct ifaddr *);
> +void ifa_update_broadaddr(struct ifnet *, struct ifaddr *,
> + struct sockaddr *);
> #endif /* _KERNEL */
> #endif /* _NET_IF_H_ */
> Index: net/if_spppsubr.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_spppsubr.c,v
> retrieving revision 1.82
> diff -u -p -r1.82 if_spppsubr.c
> --- net/if_spppsubr.c 13 Sep 2010 08:53:06 -0000 1.82
> +++ net/if_spppsubr.c 23 Sep 2010 11:43:14 -0000
> @@ -4743,7 +4743,7 @@ sppp_set_ip_addrs(struct sppp *sp, u_int
> *dest = new_dst; /* fix dstaddr in place */
> }
> }
> - if (!(error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0)))
> + if (!(error = in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, 0)))
> dohooks(ifp->if_addrhooks, 0);
> if (debug && error) {
> log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addrs: in_ifinit "
> @@ -4795,7 +4795,7 @@ sppp_clear_ip_addrs(struct sppp *sp)
> if (sp->ipcp.flags & IPCP_HISADDR_DYN)
> /* replace peer addr in place */
> dest->sin_addr.s_addr = sp->ipcp.saved_hisaddr;
> - if (!in_ifinit(ifp, ifatoia(ifa), &new_sin, 0))
> + if (!in_ifinit(ifp, ifatoia(ifa), &new_sin, 0, 0))
> dohooks(ifp->if_addrhooks, 0);
> sppp_update_gw(ifp);
> }
> Index: netinet/in.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/in.c,v
> retrieving revision 1.60
> diff -u -p -r1.60 in.c
> --- netinet/in.c 13 Jan 2010 10:45:21 -0000 1.60
> +++ netinet/in.c 23 Sep 2010 11:43:14 -0000
> @@ -271,7 +271,6 @@ in_control(so, cmd, data, ifp)
> LIST_INIT(&ia->ia_multiaddrs);
> if ((ifp->if_flags & IFF_LOOPBACK) == 0)
> in_interfaces++;
> - ifa_add(ifp, (struct ifaddr *)ia);
> splx(s);
>
> newifaddr = 1;
> @@ -351,12 +350,14 @@ in_control(so, cmd, data, ifp)
> case SIOCSIFBRDADDR:
> if ((ifp->if_flags & IFF_BROADCAST) == 0)
> return (EINVAL);
> - ia->ia_broadaddr = *satosin(&ifr->ifr_broadaddr);
> + ifa_update_broadaddr(ifp, (struct ifaddr *)ia,
> + &ifr->ifr_broadaddr);
> break;
>
> case SIOCSIFADDR:
> s = splsoftnet();
> - error = in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), 1);
> + error = in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), 1,
> + newifaddr);
> if (!error)
> dohooks(ifp->if_addrhooks, 0);
> else if (newifaddr) {
> @@ -381,7 +382,7 @@ in_control(so, cmd, data, ifp)
> ifra->ifra_addr = ia->ia_addr;
> hostIsNew = 0;
> } else if (ifra->ifra_addr.sin_addr.s_addr ==
> - ia->ia_addr.sin_addr.s_addr)
> + ia->ia_addr.sin_addr.s_addr && !newifaddr)
> hostIsNew = 0;
> }
> if (ifra->ifra_mask.sin_len) {
> @@ -396,13 +397,19 @@ in_control(so, cmd, data, ifp)
> ia->ia_dstaddr = ifra->ifra_dstaddr;
> maskIsNew = 1; /* We lie; but the effect's the same */
> }
> + if ((ifp->if_flags & IFF_BROADCAST) &&
> + (ifra->ifra_broadaddr.sin_family == AF_INET)) {
> + if (newifaddr)
> + ia->ia_broadaddr = ifra->ifra_broadaddr;
> + else
> + ifa_update_broadaddr(ifp, (struct ifaddr *)ia,
> + sintosa(&ifra->ifra_broadaddr));
> + }
> if (ifra->ifra_addr.sin_family == AF_INET &&
> (hostIsNew || maskIsNew)) {
> - error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
> + error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0,
> + newifaddr);
> }
> - if ((ifp->if_flags & IFF_BROADCAST) &&
> - (ifra->ifra_broadaddr.sin_family == AF_INET))
> - ia->ia_broadaddr = ifra->ifra_broadaddr;
> if (!error)
> dohooks(ifp->if_addrhooks, 0);
> else if (newifaddr) {
> @@ -652,18 +659,22 @@ in_ifscrub(ifp, ia)
> * and routing table entry.
> */
> int
> -in_ifinit(ifp, ia, sin, scrub)
> +in_ifinit(ifp, ia, sin, scrub, newaddr)
> struct ifnet *ifp;
> struct in_ifaddr *ia;
> struct sockaddr_in *sin;
> int scrub;
> + int newaddr;
> {
> u_int32_t i = sin->sin_addr.s_addr;
> struct sockaddr_in oldaddr;
> int s = splnet(), flags = RTF_UP, error;
>
> + if (!newaddr)
> + ifa_del(ifp, (struct ifaddr *)ia);
> oldaddr = ia->ia_addr;
> ia->ia_addr = *sin;
> +
> /*
> * Give the interface a chance to initialize
> * if this is its first address,
> @@ -719,6 +730,7 @@ in_ifinit(ifp, ia, sin, scrub)
> flags |= RTF_HOST;
> }
> error = in_addprefix(ia, flags);
> +
> /*
> * If the interface supports multicast, join the "all hosts"
> * multicast group on that interface.
> @@ -729,6 +741,9 @@ in_ifinit(ifp, ia, sin, scrub)
> addr.s_addr = INADDR_ALLHOSTS_GROUP;
> ia->ia_allhosts = in_addmulti(&addr, ifp);
> }
> +
> + ifa_add(ifp, (struct ifaddr *)ia);
> +
> return (error);
> }
>
> Index: netinet/in_var.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet/in_var.h,v
> retrieving revision 1.15
> diff -u -p -r1.15 in_var.h
> --- netinet/in_var.h 13 Jan 2010 07:05:28 -0000 1.15
> +++ netinet/in_var.h 23 Sep 2010 11:43:14 -0000
> @@ -207,7 +207,7 @@ do { \
> } while (/* CONSTCOND */ 0)
>
> int in_ifinit(struct ifnet *,
> - struct in_ifaddr *, struct sockaddr_in *, int);
> + struct in_ifaddr *, struct sockaddr_in *, int, int);
> struct in_multi *in_addmulti(struct in_addr *, struct ifnet *);
> void in_delmulti(struct in_multi *);
> void in_ifscrub(struct ifnet *, struct in_ifaddr *);
>
>
> --
> Henning Brauer,
hb@bsws.de,
henning@openbsd.org
> BS Web Services,
http://bsws.de
> Full-Service ISP - Secure Hosting, Mail and DNS Services
> Dedicated Servers, Rootservers, Application Hosting
>