diff options
author | rwatson <rwatson@FreeBSD.org> | 2004-08-06 03:45:45 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2004-08-06 03:45:45 +0000 |
commit | 11a2e8ce3c40516b1b505be3d5cdbf720ba8069f (patch) | |
tree | 38d3ac3c4e0dee27c2bff0875fc15138701f62ba /sys/netinet6/in6_pcb.c | |
parent | 6680706c2bf89170fdfb9bd5bc9332aa7319a17a (diff) | |
download | FreeBSD-src-11a2e8ce3c40516b1b505be3d5cdbf720ba8069f.zip FreeBSD-src-11a2e8ce3c40516b1b505be3d5cdbf720ba8069f.tar.gz |
Pass pcbinfo structures to in6_pcbnotify() rather than pcbhead
structures, allowing in6_pcbnotify() to lock the pcbinfo and each
inpcb that it notifies of ICMPv6 events. This prevents inpcb
assertions from firing when IPv6 generates and delievers event
notifications for inpcbs.
Reported by: kuriyama
Tested by: kuriyama
Diffstat (limited to 'sys/netinet6/in6_pcb.c')
-rw-r--r-- | sys/netinet6/in6_pcb.c | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 674dbd1..48d153f 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -610,8 +610,8 @@ in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam) * Must be called at splnet. */ void -in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify) - struct inpcbhead *head; +in6_pcbnotify(pcbinfo, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify) + struct inpcbinfo *pcbinfo; struct sockaddr *dst; const struct sockaddr *src; u_int fport_arg, lport_arg; @@ -619,6 +619,7 @@ in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify) void *cmdarg; struct inpcb *(*notify) __P((struct inpcb *, int)); { + struct inpcbhead *head; struct inpcb *inp, *ninp; struct sockaddr_in6 sa6_src, *sa6_dst; u_short fport = fport_arg, lport = lport_arg; @@ -656,11 +657,16 @@ in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify) } errno = inet6ctlerrmap[cmd]; s = splnet(); + head = pcbinfo->listhead; + INP_INFO_WLOCK(pcbinfo); for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) { + INP_LOCK(inp); ninp = LIST_NEXT(inp, inp_list); - if ((inp->inp_vflag & INP_IPV6) == 0) + if ((inp->inp_vflag & INP_IPV6) == 0) { + INP_UNLOCK(inp); continue; + } /* * If the error designates a new path MTU for a destination @@ -698,13 +704,17 @@ in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify) (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) && !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &sa6_src.sin6_addr)) || - (fport && inp->inp_fport != fport)) + (fport && inp->inp_fport != fport)) { + INP_UNLOCK(inp); continue; + } do_notify: if (notify) (*notify)(inp, errno); + INP_UNLOCK(inp); } + INP_INFO_WUNLOCK(pcbinfo); splx(s); } |