Subject: Re: CVS commit: syssrc
To: None <itojun@iijlab.net>
From: enami tsugutomo <enami@but-b.or.jp>
List: source-changes
Date: 10/08/2000 16:24:19
> >Log Message:
> >- Keep track of allhost multicast address record we joined into
> >  each in_ifaddr and delete it when an address is purged.
> 
> 	maybe the above commit changed the goal slightly.
> 	the goal of multicast kludge table (which i ported from
> 	sys/netinet6/in6.c) was to keep multicast group information ONLY,
> 	when all the interface address is gone.  it was not my intention
> 	to avoid the removal of the last IPv4 interface address.
> 	could you tell me why is the change?

Hmm, I guess you're misunderstanding my change or the comment I wrote
was miss the point.  I didn't change ``to avoid the removal of the
last IPv4 interface address.''

The change this comment refer is:

	- Add ia_allhost to in_ifaddr.
	- Remember the value in_addmulti returns in it.  Note that
	  same in_multi may be shared.
	- Call in_delmulti for it when address is deleted.

I just used the last in_ifaddr for the chain head of in_multi.  And we
have to keep track of the value retrun by in_addmulti for the reason I
explain below.

> >- Don't simply try to delete a multicast address record listed in the
> >  ia_multiaddrs.  It results a dangling pointer.  Let who holds a
> >  reference to it to delete it.
> 
> 	this refers to in_purgemkludge(), correct?  i experimented this
> 	with IPv6 case and IPv4 case, and don't understand why we have
> 	dangling pointer.   i assumed that in_purgemkludge() is called
> 	only after we flushed all interface addresses.

It refers the both loops in the patch like this:
	for (inm = LIST_FIRST(&ia->ia_multiaddrs); ....)
		in_delmulti(inm);

As I wrote in the other mail, since the struct in_multi is reference
counted, this is insufficient.  Of course, the reference in
ia_multiadrs isn't counted, since the counter is for the caller who
called in_addmulti().  It is refered from a socket and now from a
in_ifaddr.  The in_multi refered from a socket is used when the socket
is closed.  So, we have to remove the reference when interface is
gone.  Without it, we gets panic after a program who uses multicast
close a socket.  And, it is done in in_pcbpurgeif().

For example, in_purgeif() and in_pcbpurgeif() are called with
following order.

	in_purgeif(...)
	in_pcbpurgeif(&udbtable, ...)
	in_purgeif(...)
	in_pcbpurgeif(&tcbtable, ...)
	in_purgeif(...)
	in_pcbpurgeif(&rawcbtable, ...)

So, for the in_multi refered from socket, calling in_delmulti() for it
while in in_purgeif() is wrong.  And it should be unnecessary if all
references are kept.  To keep all reference, I've add ia_allhosts to
in_ifaddr.

There was also a bug that if an interface is removed while in_multi
was kept in kludge table, in_delmulti() will dereference the null
pointer.

enami.