and if you feel truly adventurous you can try this, which maintains
and uses the rb tree. known broken with ipvshit router advertisement
shit until that shit is fixe^Wmade a little less sucky. did i mention
shit yet?
has a little debug goo in it: if you ifconfig destroy a non-existant
but destroyable if (vether or gif, for instance) the rb tree is dumped
to the console. link-local ipvshit addresses look a bit shittier than
usual because that shit embed the scope id shit in a shitty way so
there's shit in bytes 3 and 4. did i say shit yet?
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:20:00 -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
@@ -2210,6 +2217,8 @@ ifa_item_insert(struct sockaddr *sa, str
{
struct ifaddr_item *ifai, *p;
+ if (!sa->sa_family)
+ return;
ifai = pool_get(&ifaddr_item_pl, PR_WAITOK);
ifai->ifai_addr = sa;
ifai->ifai_ifa = ifa;
@@ -2251,6 +2260,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:20:00 -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:20:00 -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:20:00 -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:20:00 -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, [email protected], [email protected]
BS Web Services, http://bsws.de
Full-Service ISP - Secure Hosting, Mail and DNS Services
Dedicated Servers, Rootservers, Application Hosting