From 6426d56d30272ef64d032e196f014b7342f52d9c Mon Sep 17 00:00:00 2001 From: bluhm Date: Thu, 7 Dec 2023 16:08:30 +0000 Subject: [PATCH] Inpcb table mutex protects addr and port during bind(2) and connect(2). in_pcbbind(), in_pcbconnect(), and in6_pcbconnect() have to set addresses and ports within the same critical section as the inpcb hash table calculation. Also lookup and address selection have to be protected to avoid bindings and connections that are not unique. For that in_pcbpickport() and in_pcbbind_locked() expect that the table mutex is already taken. The functions in_pcblookup_lock(), in_pcblookup_local_lock(), and in_pcbaddrisavail_lock() grab the mutex iff the lock parameter is IN_PCBLOCK_GRAB. Otherwise the parameter is IN_PCBLOCK_HOLD has the lock has to be taken already. Note that in_pcblookup_lock() and in_pcblookup_local() return an inp with increased reference iff they take and release the lock. Otherwise the caller protects the life time of the inp. This gives enough flexibility that in_pcbbind() and in_pcbconnect() can hold the table mutex when they need it. The public inpcb API does not change. OK sashan@ mvs@ --- sys/netinet/in_pcb.c | 147 +++++++++++++++++++++++++++++------------ sys/netinet/in_pcb.h | 16 +++-- sys/netinet6/in6_pcb.c | 82 ++++++++++++++++------- 3 files changed, 173 insertions(+), 72 deletions(-) diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 35cd333de29..67e80baa79c 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.281 2023/12/03 20:24:17 bluhm Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.282 2023/12/07 16:08:30 bluhm Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -131,6 +131,13 @@ uint64_t in_pcbhash(struct inpcbtable *, u_int, const struct in_addr *, u_short, const struct in_addr *, u_short); uint64_t in_pcblhash(struct inpcbtable *, u_int, u_short); +struct inpcb *in_pcblookup_lock(struct inpcbtable *, struct in_addr, u_int, + struct in_addr, u_int, u_int, int); +int in_pcbaddrisavail_lock(struct inpcb *, struct sockaddr_in *, int, + struct proc *, int); +int in_pcbpickport(u_int16_t *, const void *, int, const struct inpcb *, + struct proc *); + /* * in_pcb is used for inet and inet6. in6_pcb only contains special * IPv6 cases. So the internet initializer is used for both domains. @@ -269,9 +276,8 @@ in_pcballoc(struct socket *so, struct inpcbtable *table, int wait) } int -in_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p) +in_pcbbind_locked(struct inpcb *inp, struct mbuf *nam, struct proc *p) { - struct inpcbtable *table = inp->inp_table; struct socket *so = inp->inp_socket; u_int16_t lport = 0; int wild = 0; @@ -297,7 +303,8 @@ in_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p) if ((error = in6_nam2sin6(nam, &sin6))) return (error); - if ((error = in6_pcbaddrisavail(inp, sin6, wild, p))) + if ((error = in6_pcbaddrisavail_lock(inp, sin6, wild, + p, IN_PCBLOCK_HOLD))) return (error); laddr = &sin6->sin6_addr; lport = sin6->sin6_port; @@ -313,7 +320,8 @@ in_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p) if ((error = in_nam2sin(nam, &sin))) return (error); - if ((error = in_pcbaddrisavail(inp, sin, wild, p))) + if ((error = in_pcbaddrisavail_lock(inp, sin, wild, + p, IN_PCBLOCK_HOLD))) return (error); laddr = &sin->sin_addr; lport = sin->sin_port; @@ -337,16 +345,28 @@ in_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p) inp->inp_laddr = *(struct in_addr *)laddr; } inp->inp_lport = lport; - mtx_enter(&table->inpt_mtx); in_pcbrehash(inp); - mtx_leave(&table->inpt_mtx); return (0); } int -in_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in *sin, int wild, - struct proc *p) +in_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p) +{ + struct inpcbtable *table = inp->inp_table; + int error; + + /* keep lookup, modification, and rehash in sync */ + mtx_enter(&table->inpt_mtx); + error = in_pcbbind_locked(inp, nam, p); + mtx_leave(&table->inpt_mtx); + + return error; +} + +int +in_pcbaddrisavail_lock(struct inpcb *inp, struct sockaddr_in *sin, int wild, + struct proc *p, int lock) { struct socket *so = inp->inp_socket; struct inpcbtable *table = inp->inp_table; @@ -393,19 +413,21 @@ in_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in *sin, int wild, int error = 0; if (so->so_euid && !IN_MULTICAST(sin->sin_addr.s_addr)) { - t = in_pcblookup_local(table, &sin->sin_addr, lport, - INPLOOKUP_WILDCARD, inp->inp_rtableid); + t = in_pcblookup_local_lock(table, &sin->sin_addr, + lport, INPLOOKUP_WILDCARD, inp->inp_rtableid, lock); if (t && (so->so_euid != t->inp_socket->so_euid)) error = EADDRINUSE; - in_pcbunref(t); + if (lock == IN_PCBLOCK_GRAB) + in_pcbunref(t); if (error) return (error); } - t = in_pcblookup_local(table, &sin->sin_addr, lport, - wild, inp->inp_rtableid); + t = in_pcblookup_local_lock(table, &sin->sin_addr, lport, + wild, inp->inp_rtableid, lock); if (t && (reuseport & t->inp_socket->so_options) == 0) error = EADDRINUSE; - in_pcbunref(t); + if (lock == IN_PCBLOCK_GRAB) + in_pcbunref(t); if (error) return (error); } @@ -413,6 +435,13 @@ in_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in *sin, int wild, return (0); } +int +in_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in *sin, int wild, + struct proc *p) +{ + return in_pcbaddrisavail_lock(inp, sin, wild, p, IN_PCBLOCK_GRAB); +} + int in_pcbpickport(u_int16_t *lport, const void *laddr, int wild, const struct inpcb *inp, struct proc *p) @@ -423,6 +452,8 @@ in_pcbpickport(u_int16_t *lport, const void *laddr, int wild, u_int16_t first, last, lower, higher, candidate, localport; int count; + MUTEX_ASSERT_LOCKED(&table->inpt_mtx); + if (inp->inp_flags & INP_HIGHPORT) { first = ipport_hifirstauto; /* sysctl */ last = ipport_hilastauto; @@ -451,9 +482,7 @@ in_pcbpickport(u_int16_t *lport, const void *laddr, int wild, count = higher - lower; candidate = lower + arc4random_uniform(count); - t = NULL; do { - in_pcbunref(t); do { if (count-- < 0) /* completely used? */ return (EADDRNOTAVAIL); @@ -462,8 +491,8 @@ in_pcbpickport(u_int16_t *lport, const void *laddr, int wild, candidate = lower; localport = htons(candidate); } while (in_baddynamic(candidate, so->so_proto->pr_protocol)); - t = in_pcblookup_local(table, laddr, localport, wild, - inp->inp_rtableid); + t = in_pcblookup_local_lock(table, laddr, localport, wild, + inp->inp_rtableid, IN_PCBLOCK_HOLD); } while (t != NULL); *lport = localport; @@ -498,10 +527,13 @@ in_pcbconnect(struct inpcb *inp, struct mbuf *nam) if (error) return (error); - t = in_pcblookup(inp->inp_table, sin->sin_addr, sin->sin_port, - ina, inp->inp_lport, inp->inp_rtableid); + /* keep lookup, modification, and rehash in sync */ + mtx_enter(&table->inpt_mtx); + + t = in_pcblookup_lock(inp->inp_table, sin->sin_addr, sin->sin_port, + ina, inp->inp_lport, inp->inp_rtableid, IN_PCBLOCK_HOLD); if (t != NULL) { - in_pcbunref(t); + mtx_leave(&table->inpt_mtx); return (EADDRINUSE); } @@ -509,15 +541,17 @@ in_pcbconnect(struct inpcb *inp, struct mbuf *nam) if (inp->inp_laddr.s_addr == INADDR_ANY) { if (inp->inp_lport == 0) { - error = in_pcbbind(inp, NULL, curproc); - if (error) + error = in_pcbbind_locked(inp, NULL, curproc); + if (error) { + mtx_leave(&table->inpt_mtx); return (error); - t = in_pcblookup(inp->inp_table, sin->sin_addr, + } + t = in_pcblookup_lock(inp->inp_table, sin->sin_addr, sin->sin_port, ina, inp->inp_lport, - inp->inp_rtableid); + inp->inp_rtableid, IN_PCBLOCK_HOLD); if (t != NULL) { inp->inp_lport = 0; - in_pcbunref(t); + mtx_leave(&table->inpt_mtx); return (EADDRINUSE); } } @@ -525,8 +559,8 @@ in_pcbconnect(struct inpcb *inp, struct mbuf *nam) } inp->inp_faddr = sin->sin_addr; inp->inp_fport = sin->sin_port; - mtx_enter(&table->inpt_mtx); in_pcbrehash(inp); + mtx_leave(&table->inpt_mtx); #if NSTOEPLITZ > 0 @@ -539,6 +573,11 @@ in_pcbconnect(struct inpcb *inp, struct mbuf *nam) void in_pcbdisconnect(struct inpcb *inp) { + /* + * XXXSMP pf lock sleeps, so we cannot use table->inpt_mtx + * to keep inp_pf_sk in sync with pcb. Use net lock for now. + */ + NET_ASSERT_LOCKED_EXCLUSIVE(); #if NPF > 0 if (inp->inp_pf_sk) { pf_remove_divert_state(inp->inp_pf_sk); @@ -576,6 +615,12 @@ in_pcbdetach(struct inpcb *inp) } else #endif ip_freemoptions(inp->inp_moptions); + + /* + * XXXSMP pf lock sleeps, so we cannot use table->inpt_mtx + * to keep inp_pf_sk in sync with pcb. Use net lock for now. + */ + NET_ASSERT_LOCKED_EXCLUSIVE(); #if NPF > 0 if (inp->inp_pf_sk) { pf_remove_divert_state(inp->inp_pf_sk); @@ -791,8 +836,8 @@ in_rtchange(struct inpcb *inp, int errno) } struct inpcb * -in_pcblookup_local(struct inpcbtable *table, const void *laddrp, - u_int lport_arg, int flags, u_int rtable) +in_pcblookup_local_lock(struct inpcbtable *table, const void *laddrp, + u_int lport_arg, int flags, u_int rtable, int lock) { struct inpcb *inp, *match = NULL; int matchwild = 3, wildcard; @@ -808,7 +853,12 @@ in_pcblookup_local(struct inpcbtable *table, const void *laddrp, rdomain = rtable_l2(rtable); lhash = in_pcblhash(table, rdomain, lport); - mtx_enter(&table->inpt_mtx); + if (lock == IN_PCBLOCK_GRAB) { + mtx_enter(&table->inpt_mtx); + } else { + KASSERT(lock == IN_PCBLOCK_HOLD); + MUTEX_ASSERT_LOCKED(&table->inpt_mtx); + } head = &table->inpt_lhashtbl[lhash & table->inpt_lmask]; LIST_FOREACH(inp, head, inp_lhash) { if (rtable_l2(inp->inp_rtableid) != rdomain) @@ -859,8 +909,10 @@ in_pcblookup_local(struct inpcbtable *table, const void *laddrp, break; } } - in_pcbref(match); - mtx_leave(&table->inpt_mtx); + if (lock == IN_PCBLOCK_GRAB) { + in_pcbref(match); + mtx_leave(&table->inpt_mtx); + } return (match); } @@ -1029,10 +1081,6 @@ in_pcbselsrc(struct in_addr *insrc, struct sockaddr_in *sin, void in_pcbrehash(struct inpcb *inp) { - struct inpcbtable *table = inp->inp_table; - - MUTEX_ASSERT_LOCKED(&table->inpt_mtx); - LIST_REMOVE(inp, inp_lhash); LIST_REMOVE(inp, inp_hash); in_pcbhash_insert(inp); @@ -1154,8 +1202,8 @@ int in_pcbnotifymiss = 0; * After those two lookups no other are necessary. */ struct inpcb * -in_pcblookup(struct inpcbtable *table, struct in_addr faddr, - u_int fport, struct in_addr laddr, u_int lport, u_int rtable) +in_pcblookup_lock(struct inpcbtable *table, struct in_addr faddr, + u_int fport, struct in_addr laddr, u_int lport, u_int rtable, int lock) { struct inpcb *inp; uint64_t hash; @@ -1164,11 +1212,18 @@ in_pcblookup(struct inpcbtable *table, struct in_addr faddr, rdomain = rtable_l2(rtable); hash = in_pcbhash(table, rdomain, &faddr, fport, &laddr, lport); - mtx_enter(&table->inpt_mtx); + if (lock == IN_PCBLOCK_GRAB) { + mtx_enter(&table->inpt_mtx); + } else { + KASSERT(lock == IN_PCBLOCK_HOLD); + MUTEX_ASSERT_LOCKED(&table->inpt_mtx); + } inp = in_pcbhash_lookup(table, hash, rdomain, &faddr, fport, &laddr, lport); - in_pcbref(inp); - mtx_leave(&table->inpt_mtx); + if (lock == IN_PCBLOCK_GRAB) { + in_pcbref(inp); + mtx_leave(&table->inpt_mtx); + } #ifdef DIAGNOSTIC if (inp == NULL && in_pcbnotifymiss) { @@ -1180,6 +1235,14 @@ in_pcblookup(struct inpcbtable *table, struct in_addr faddr, return (inp); } +struct inpcb * +in_pcblookup(struct inpcbtable *table, struct in_addr faddr, + u_int fport, struct in_addr laddr, u_int lport, u_int rtable) +{ + return in_pcblookup_lock(table, faddr, fport, laddr, lport, rtable, + IN_PCBLOCK_GRAB); +} + /* * The in(6)_pcblookup_listen functions are used to locate listening * sockets quickly. This are sockets with unspecified foreign address diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index c300b8ab0f5..9c15b41382d 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.h,v 1.142 2023/12/03 20:24:17 bluhm Exp $ */ +/* $OpenBSD: in_pcb.h,v 1.143 2023/12/07 16:08:30 bluhm Exp $ */ /* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */ /* @@ -268,6 +268,9 @@ struct baddynamicports { #ifdef _KERNEL +#define IN_PCBLOCK_HOLD 1 +#define IN_PCBLOCK_GRAB 2 + extern struct inpcbtable rawcbtable, rawin6pcbtable; extern struct baddynamicports baddynamicports; extern struct baddynamicports rootonlyports; @@ -276,6 +279,7 @@ extern int in_pcbnotifymiss; void in_init(void); void in_losing(struct inpcb *); int in_pcballoc(struct socket *, struct inpcbtable *, int); +int in_pcbbind_locked(struct inpcb *, struct mbuf *, struct proc *); int in_pcbbind(struct inpcb *, struct mbuf *, struct proc *); int in_pcbaddrisavail(struct inpcb *, struct sockaddr_in *, int, struct proc *); @@ -296,10 +300,12 @@ uint64_t in6_pcbhash(struct inpcbtable *, u_int, const struct in6_addr *, u_short, const struct in6_addr *, u_short); struct inpcb * in6_pcblookup(struct inpcbtable *, const struct in6_addr *, - u_int, const struct in6_addr *, u_int, u_int); + u_int, const struct in6_addr *, u_int, u_int); struct inpcb * in6_pcblookup_listen(struct inpcbtable *, struct in6_addr *, u_int, struct mbuf *, u_int); +int in6_pcbaddrisavail_lock(struct inpcb *, struct sockaddr_in6 *, int, + struct proc *, int); int in6_pcbaddrisavail(struct inpcb *, struct sockaddr_in6 *, int, struct proc *); int in6_pcbconnect(struct inpcb *, struct mbuf *); @@ -310,8 +316,8 @@ int in6_peeraddr(struct socket *, struct mbuf *); #endif /* INET6 */ void in_pcbinit(struct inpcbtable *, int); struct inpcb * - in_pcblookup_local(struct inpcbtable *, const void *, u_int, int, - u_int); + in_pcblookup_local_lock(struct inpcbtable *, const void *, u_int, int, + u_int, int); void in_pcbnotifyall(struct inpcbtable *, struct sockaddr *, u_int, int, void (*)(struct inpcb *, int)); void in_pcbrehash(struct inpcb *); @@ -331,8 +337,6 @@ void in6_pcbnotify(struct inpcbtable *, struct sockaddr_in6 *, u_int, const struct sockaddr_in6 *, u_int, u_int, int, void *, void (*)(struct inpcb *, int)); int in6_selecthlim(struct inpcb *); -int in_pcbpickport(u_int16_t *, const void *, int, const struct inpcb *, - struct proc *); int in_pcbset_rtableid(struct inpcb *, u_int); void in_pcbset_laddr(struct inpcb *, const struct sockaddr *, u_int); void in_pcbunset_faddr(struct inpcb *); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index b0c30bfff4d..a1bd2bdd1dd 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_pcb.c,v 1.130 2023/12/03 20:36:24 bluhm Exp $ */ +/* $OpenBSD: in6_pcb.c,v 1.131 2023/12/07 16:08:30 bluhm Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -129,6 +129,9 @@ const struct in6_addr zeroin6_addr; struct inpcb *in6_pcbhash_lookup(struct inpcbtable *, uint64_t, u_int, const struct in6_addr *, u_short, const struct in6_addr *, u_short); +struct inpcb * in6_pcblookup_lock(struct inpcbtable *, const struct in6_addr *, + u_int, const struct in6_addr *, u_int, u_int, int); + uint64_t in6_pcbhash(struct inpcbtable *table, u_int rdomain, const struct in6_addr *faddr, u_short fport, @@ -147,8 +150,8 @@ in6_pcbhash(struct inpcbtable *table, u_int rdomain, } int -in6_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in6 *sin6, int wild, - struct proc *p) +in6_pcbaddrisavail_lock(struct inpcb *inp, struct sockaddr_in6 *sin6, int wild, + struct proc *p, int lock) { struct socket *so = inp->inp_socket; struct inpcbtable *table = inp->inp_table; @@ -214,26 +217,35 @@ in6_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in6 *sin6, int wild, int error = 0; if (so->so_euid && !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { - t = in_pcblookup_local(table, &sin6->sin6_addr, lport, - INPLOOKUP_WILDCARD | INPLOOKUP_IPV6, - inp->inp_rtableid); + t = in_pcblookup_local_lock(table, &sin6->sin6_addr, + lport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6, + inp->inp_rtableid, lock); if (t && (so->so_euid != t->inp_socket->so_euid)) error = EADDRINUSE; - in_pcbunref(t); + if (lock == IN_PCBLOCK_GRAB) + in_pcbunref(t); if (error) return (error); } - t = in_pcblookup_local(table, &sin6->sin6_addr, lport, - wild, inp->inp_rtableid); + t = in_pcblookup_local_lock(table, &sin6->sin6_addr, lport, + wild, inp->inp_rtableid, lock); if (t && (reuseport & t->inp_socket->so_options) == 0) error = EADDRINUSE; - in_pcbunref(t); + if (lock == IN_PCBLOCK_GRAB) + in_pcbunref(t); if (error) return (error); } return (0); } +int +in6_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in6 *sin6, int wild, + struct proc *p) +{ + return in6_pcbaddrisavail_lock(inp, sin6, wild, p, IN_PCBLOCK_GRAB); +} + /* * Connect from a socket to a specified address. * Both address and port must be specified in argument sin6. @@ -285,11 +297,15 @@ in6_pcbconnect(struct inpcb *inp, struct mbuf *nam) inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp); - t = in6_pcblookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port, + /* keep lookup, modification, and rehash in sync */ + mtx_enter(&table->inpt_mtx); + + t = in6_pcblookup_lock(inp->inp_table, &sin6->sin6_addr, + sin6->sin6_port, IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) ? in6a : &inp->inp_laddr6, - inp->inp_lport, inp->inp_rtableid); + inp->inp_lport, inp->inp_rtableid, IN_PCBLOCK_HOLD); if (t != NULL) { - in_pcbunref(t); + mtx_leave(&table->inpt_mtx); return (EADDRINUSE); } @@ -297,15 +313,17 @@ in6_pcbconnect(struct inpcb *inp, struct mbuf *nam) if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) { if (inp->inp_lport == 0) { - error = in_pcbbind(inp, NULL, curproc); - if (error) + error = in_pcbbind_locked(inp, NULL, curproc); + if (error) { + mtx_leave(&table->inpt_mtx); return (error); - t = in6_pcblookup(inp->inp_table, &sin6->sin6_addr, + } + t = in6_pcblookup_lock(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port, in6a, inp->inp_lport, - inp->inp_rtableid); + inp->inp_rtableid, IN_PCBLOCK_HOLD); if (t != NULL) { inp->inp_lport = 0; - in_pcbunref(t); + mtx_leave(&table->inpt_mtx); return (EADDRINUSE); } } @@ -313,8 +331,8 @@ in6_pcbconnect(struct inpcb *inp, struct mbuf *nam) } inp->inp_faddr6 = sin6->sin6_addr; inp->inp_fport = sin6->sin6_port; - mtx_enter(&table->inpt_mtx); in_pcbrehash(inp); + mtx_leave(&table->inpt_mtx); inp->inp_flowinfo &= ~IPV6_FLOWLABEL_MASK; @@ -580,8 +598,9 @@ in6_pcbhash_lookup(struct inpcbtable *table, uint64_t hash, u_int rdomain, } struct inpcb * -in6_pcblookup(struct inpcbtable *table, const struct in6_addr *faddr, - u_int fport, const struct in6_addr *laddr, u_int lport, u_int rtable) +in6_pcblookup_lock(struct inpcbtable *table, const struct in6_addr *faddr, + u_int fport, const struct in6_addr *laddr, u_int lport, u_int rtable, + int lock) { struct inpcb *inp; uint64_t hash; @@ -590,11 +609,18 @@ in6_pcblookup(struct inpcbtable *table, const struct in6_addr *faddr, rdomain = rtable_l2(rtable); hash = in6_pcbhash(table, rdomain, faddr, fport, laddr, lport); - mtx_enter(&table->inpt_mtx); + if (lock == IN_PCBLOCK_GRAB) { + mtx_enter(&table->inpt_mtx); + } else { + KASSERT(lock == IN_PCBLOCK_HOLD); + MUTEX_ASSERT_LOCKED(&table->inpt_mtx); + } inp = in6_pcbhash_lookup(table, hash, rdomain, faddr, fport, laddr, lport); - in_pcbref(inp); - mtx_leave(&table->inpt_mtx); + if (lock == IN_PCBLOCK_GRAB) { + in_pcbref(inp); + mtx_leave(&table->inpt_mtx); + } #ifdef DIAGNOSTIC if (inp == NULL && in_pcbnotifymiss) { @@ -605,6 +631,14 @@ in6_pcblookup(struct inpcbtable *table, const struct in6_addr *faddr, return (inp); } +struct inpcb * +in6_pcblookup(struct inpcbtable *table, const struct in6_addr *faddr, + u_int fport, const struct in6_addr *laddr, u_int lport, u_int rtable) +{ + return in6_pcblookup_lock(table, faddr, fport, laddr, lport, rtable, + IN_PCBLOCK_GRAB); +} + struct inpcb * in6_pcblookup_listen(struct inpcbtable *table, struct in6_addr *laddr, u_int lport, struct mbuf *m, u_int rtable) -- 2.20.1