Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/in6_pcb.c
Show First 20 Lines • Show All 667 Lines • ▼ Show 20 Lines | |||||
* Pass some notification to all connections of a protocol | * Pass some notification to all connections of a protocol | ||||
* associated with address dst. The local address and/or port numbers | * associated with address dst. The local address and/or port numbers | ||||
* may be specified to limit the search. The "usual action" will be | * may be specified to limit the search. The "usual action" will be | ||||
* taken, depending on the ctlinput cmd. The caller must filter any | * taken, depending on the ctlinput cmd. The caller must filter any | ||||
* cmds that are uninteresting (e.g., no error in the map). | * cmds that are uninteresting (e.g., no error in the map). | ||||
* Call the protocol specific routine (if any) to report | * Call the protocol specific routine (if any) to report | ||||
* any errors for each matching socket. | * any errors for each matching socket. | ||||
*/ | */ | ||||
static bool | |||||
inp_match6(const struct inpcb *inp, void *v __unused) | |||||
{ | |||||
return ((inp->inp_vflag & INP_IPV6) != 0); | |||||
} | |||||
void | void | ||||
in6_pcbnotify(struct inpcbinfo *pcbinfo, struct sockaddr *dst, | in6_pcbnotify(struct inpcbinfo *pcbinfo, struct sockaddr *dst, | ||||
u_int fport_arg, const struct sockaddr *src, u_int lport_arg, | u_int fport_arg, const struct sockaddr *src, u_int lport_arg, | ||||
int cmd, void *cmdarg, | int cmd, void *cmdarg, | ||||
struct inpcb *(*notify)(struct inpcb *, int)) | struct inpcb *(*notify)(struct inpcb *, int)) | ||||
{ | { | ||||
struct inpcb *inp, *inp_temp; | struct inpcb_iterator inpi = INP_ITERATOR(pcbinfo, INPLOOKUP_WLOCKPCB, | ||||
inp_match6, NULL); | |||||
struct inpcb *inp; | |||||
struct sockaddr_in6 sa6_src, *sa6_dst; | struct sockaddr_in6 sa6_src, *sa6_dst; | ||||
u_short fport = fport_arg, lport = lport_arg; | u_short fport = fport_arg, lport = lport_arg; | ||||
u_int32_t flowinfo; | u_int32_t flowinfo; | ||||
int errno; | int errno; | ||||
if ((unsigned)cmd >= PRC_NCMDS || dst->sa_family != AF_INET6) | if ((unsigned)cmd >= PRC_NCMDS || dst->sa_family != AF_INET6) | ||||
return; | return; | ||||
Show All 19 Lines | if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { | ||||
fport = 0; | fport = 0; | ||||
lport = 0; | lport = 0; | ||||
bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr)); | bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr)); | ||||
if (cmd != PRC_HOSTDEAD) | if (cmd != PRC_HOSTDEAD) | ||||
notify = in6_rtchange; | notify = in6_rtchange; | ||||
} | } | ||||
errno = inet6ctlerrmap[cmd]; | errno = inet6ctlerrmap[cmd]; | ||||
INP_INFO_WLOCK(pcbinfo); | while ((inp = inp_next(&inpi)) != NULL) { | ||||
CK_LIST_FOREACH_SAFE(inp, pcbinfo->ipi_listhead, inp_list, inp_temp) { | INP_WLOCK_ASSERT(inp); | ||||
INP_WLOCK(inp); | |||||
if ((inp->inp_vflag & INP_IPV6) == 0) { | |||||
INP_WUNLOCK(inp); | |||||
continue; | |||||
} | |||||
/* | /* | ||||
* If the error designates a new path MTU for a destination | * If the error designates a new path MTU for a destination | ||||
* and the application (associated with this socket) wanted to | * and the application (associated with this socket) wanted to | ||||
* know the value, notify. | * know the value, notify. | ||||
* XXX: should we avoid to notify the value to TCP sockets? | * XXX: should we avoid to notify the value to TCP sockets? | ||||
*/ | */ | ||||
if (cmd == PRC_MSGSIZE && cmdarg != NULL) | if (cmd == PRC_MSGSIZE && cmdarg != NULL) | ||||
ip6_notify_pmtu(inp, (struct sockaddr_in6 *)dst, | ip6_notify_pmtu(inp, (struct sockaddr_in6 *)dst, | ||||
Show All 15 Lines | while ((inp = inp_next(&inpi)) != NULL) { | ||||
else if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, | else if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, | ||||
&sa6_dst->sin6_addr) || | &sa6_dst->sin6_addr) || | ||||
inp->inp_socket == 0 || | inp->inp_socket == 0 || | ||||
(lport && inp->inp_lport != lport) || | (lport && inp->inp_lport != lport) || | ||||
(!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) && | (!IN6_IS_ADDR_UNSPECIFIED(&sa6_src.sin6_addr) && | ||||
!IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, | !IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, | ||||
&sa6_src.sin6_addr)) || | &sa6_src.sin6_addr)) || | ||||
(fport && inp->inp_fport != fport)) { | (fport && inp->inp_fport != fport)) { | ||||
INP_WUNLOCK(inp); | |||||
continue; | continue; | ||||
} | } | ||||
do_notify: | do_notify: | ||||
if (notify) { | if (notify) | ||||
if ((*notify)(inp, errno)) | (*notify)(inp, errno); | ||||
INP_WUNLOCK(inp); | |||||
} else | |||||
INP_WUNLOCK(inp); | |||||
} | } | ||||
INP_INFO_WUNLOCK(pcbinfo); | |||||
} | } | ||||
/* | /* | ||||
* Lookup a PCB based on the local address and port. Caller must hold the | * Lookup a PCB based on the local address and port. Caller must hold the | ||||
* hash lock. No inpcb locks or references are acquired. | * hash lock. No inpcb locks or references are acquired. | ||||
*/ | */ | ||||
struct inpcb * | struct inpcb * | ||||
in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr, | in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr, | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | if (phd != NULL) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return (match); | return (match); | ||||
} | } | ||||
} | } | ||||
static bool | |||||
in6_multi_match(const struct inpcb *inp, void *v __unused) | |||||
{ | |||||
if ((inp->inp_vflag & INP_IPV6) && inp->in6p_moptions != NULL) | |||||
return (true); | |||||
else | |||||
return (false); | |||||
} | |||||
void | void | ||||
in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) | in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) | ||||
{ | { | ||||
struct inpcb_iterator inpi = INP_ITERATOR(pcbinfo, INPLOOKUP_RLOCKPCB, | |||||
in6_multi_match, NULL); | |||||
struct inpcb *inp; | struct inpcb *inp; | ||||
struct in6_multi *inm; | struct in6_multi *inm; | ||||
struct in6_mfilter *imf; | struct in6_mfilter *imf; | ||||
struct ip6_moptions *im6o; | struct ip6_moptions *im6o; | ||||
INP_INFO_WLOCK(pcbinfo); | IN6_MULTI_LOCK_ASSERT(); | ||||
CK_LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { | |||||
INP_WLOCK(inp); | while ((inp = inp_next(&inpi)) != NULL) { | ||||
if (__predict_false(inp->inp_flags2 & INP_FREED)) { | INP_RLOCK_ASSERT(inp); | ||||
INP_WUNLOCK(inp); | |||||
continue; | |||||
} | |||||
im6o = inp->in6p_moptions; | im6o = inp->in6p_moptions; | ||||
if ((inp->inp_vflag & INP_IPV6) && im6o != NULL) { | |||||
/* | /* | ||||
* Unselect the outgoing ifp for multicast if it | * Unselect the outgoing ifp for multicast if it | ||||
* is being detached. | * is being detached. | ||||
*/ | */ | ||||
if (im6o->im6o_multicast_ifp == ifp) | if (im6o->im6o_multicast_ifp == ifp) | ||||
im6o->im6o_multicast_ifp = NULL; | im6o->im6o_multicast_ifp = NULL; | ||||
/* | /* | ||||
* Drop multicast group membership if we joined | * Drop multicast group membership if we joined | ||||
* through the interface being detached. | * through the interface being detached. | ||||
*/ | */ | ||||
restart: | restart: | ||||
IP6_MFILTER_FOREACH(imf, &im6o->im6o_head) { | IP6_MFILTER_FOREACH(imf, &im6o->im6o_head) { | ||||
if ((inm = imf->im6f_in6m) == NULL) | if ((inm = imf->im6f_in6m) == NULL) | ||||
continue; | continue; | ||||
if (inm->in6m_ifp != ifp) | if (inm->in6m_ifp != ifp) | ||||
continue; | continue; | ||||
ip6_mfilter_remove(&im6o->im6o_head, imf); | ip6_mfilter_remove(&im6o->im6o_head, imf); | ||||
IN6_MULTI_LOCK_ASSERT(); | |||||
in6_leavegroup_locked(inm, NULL); | in6_leavegroup_locked(inm, NULL); | ||||
ip6_mfilter_free(imf); | ip6_mfilter_free(imf); | ||||
goto restart; | goto restart; | ||||
} | } | ||||
} | } | ||||
INP_WUNLOCK(inp); | |||||
} | } | ||||
INP_INFO_WUNLOCK(pcbinfo); | |||||
} | |||||
/* | /* | ||||
* Check for alternatives when higher level complains | * Check for alternatives when higher level complains | ||||
* about service problems. For now, invalidate cached | * about service problems. For now, invalidate cached | ||||
* routing information. If the route was created dynamically | * routing information. If the route was created dynamically | ||||
* (by a redirect), time to try a default gateway again. | * (by a redirect), time to try a default gateway again. | ||||
*/ | */ | ||||
void | void | ||||
▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static struct inpcb * | static struct inpcb * | ||||
in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, | in6_pcblookup_hash(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, | ||||
u_int fport, struct in6_addr *laddr, u_int lport, int lookupflags, | u_int fport, struct in6_addr *laddr, u_int lport, int lookupflags, | ||||
struct ifnet *ifp, uint8_t numa_domain) | struct ifnet *ifp, uint8_t numa_domain) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
smr_enter(pcbinfo->ipi_smr); | |||||
inp = in6_pcblookup_hash_locked(pcbinfo, faddr, fport, laddr, lport, | inp = in6_pcblookup_hash_locked(pcbinfo, faddr, fport, laddr, lport, | ||||
lookupflags & INPLOOKUP_WILDCARD, ifp, numa_domain); | lookupflags & INPLOOKUP_WILDCARD, ifp, numa_domain); | ||||
if (inp != NULL) { | if (inp != NULL) { | ||||
if (lookupflags & INPLOOKUP_WLOCKPCB) { | if (__predict_false(inp_smr_lock(inp, | ||||
INP_WLOCK(inp); | (lookupflags & INPLOOKUP_LOCKMASK)) == false)) | ||||
} else if (lookupflags & INPLOOKUP_RLOCKPCB) { | |||||
INP_RLOCK(inp); | |||||
} else | |||||
panic("%s: locking bug", __func__); | |||||
if (__predict_false(inp->inp_flags2 & INP_FREED)) { | |||||
INP_UNLOCK(inp); | |||||
inp = NULL; | inp = NULL; | ||||
} | } else | ||||
} | smr_exit(pcbinfo->ipi_smr); | ||||
return (inp); | return (inp); | ||||
} | } | ||||
/* | /* | ||||
* Public inpcb lookup routines, accepting a 4-tuple, and optionally, an mbuf | * Public inpcb lookup routines, accepting a 4-tuple, and optionally, an mbuf | ||||
* from which a pre-calculated hash value may be extracted. | * from which a pre-calculated hash value may be extracted. | ||||
*/ | */ | ||||
struct inpcb * | struct inpcb * | ||||
▲ Show 20 Lines • Show All 43 Lines • Show Last 20 Lines |