Use their reference counter in more places.
The in_pcb lookup functions hold the PCBs in hash tables protected
by table->inpt_mtx mutex. Whenever a result is returned, increment
the ref count before releasing the mutex. Then the inp can be used
as long as neccessary. Unref it at the end of all functions that
call in_pcb lookup.
As a shortcut, pf may also hold a reference to the PCB. When
pf_inp_lookup() returns it, it also incements the ref count and the
caller can handle it like the inp from table lookup.
OK sashan@
-/* $OpenBSD: pf.c,v 1.1136 2022/07/20 09:33:11 mbuhl Exp $ */
+/* $OpenBSD: pf.c,v 1.1137 2022/08/08 12:06:30 bluhm Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
pd->lookup.uid = inp->inp_socket->so_euid;
pd->lookup.gid = inp->inp_socket->so_egid;
pd->lookup.pid = inp->inp_socket->so_cpid;
+ in_pcbunref(inp);
return (1);
}
if (inp && inp->inp_pf_sk)
KASSERT(m->m_pkthdr.pf.statekey == inp->inp_pf_sk);
+ in_pcbref(inp);
return (inp);
}
-/* $OpenBSD: in_pcb.c,v 1.269 2022/08/06 15:57:59 bluhm Exp $ */
+/* $OpenBSD: in_pcb.c,v 1.270 2022/08/08 12:06:30 bluhm Exp $ */
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
/*
}
if (lport) {
struct inpcb *t;
+ 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);
if (t && (so->so_euid != t->inp_socket->so_euid))
- return (EADDRINUSE);
+ error = EADDRINUSE;
+ in_pcbunref(t);
+ if (error)
+ return (error);
}
t = in_pcblookup_local(table, &sin->sin_addr, lport,
wild, inp->inp_rtableid);
if (t && (reuseport & t->inp_socket->so_options) == 0)
- return (EADDRINUSE);
+ error = EADDRINUSE;
+ in_pcbunref(t);
+ if (error)
+ return (error);
}
return (0);
{
struct socket *so = inp->inp_socket;
struct inpcbtable *table = inp->inp_table;
+ struct inpcb *t;
u_int16_t first, last, lower, higher, candidate, localport;
int count;
count = higher - lower;
candidate = lower + arc4random_uniform(count);
+ t = NULL;
do {
- if (count-- < 0) /* completely used? */
- return (EADDRNOTAVAIL);
- ++candidate;
- if (candidate < lower || candidate > higher)
- candidate = lower;
- localport = htons(candidate);
- } while (in_baddynamic(candidate, so->so_proto->pr_protocol) ||
- in_pcblookup_local(table, laddr, localport, wild,
- inp->inp_rtableid));
+ in_pcbunref(t);
+ do {
+ if (count-- < 0) /* completely used? */
+ return (EADDRNOTAVAIL);
+ ++candidate;
+ if (candidate < lower || candidate > higher)
+ 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);
+ } while (t != NULL);
*lport = localport;
return (0);
{
struct in_addr ina;
struct sockaddr_in *sin;
+ struct inpcb *t;
int error;
#ifdef INET6
if (error)
return (error);
- if (in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port,
- ina, inp->inp_lport, inp->inp_rtableid) != NULL)
+ t = in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port,
+ ina, inp->inp_lport, inp->inp_rtableid);
+ if (t != NULL) {
+ in_pcbunref(t);
return (EADDRINUSE);
+ }
KASSERT(inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_lport);
error = in_pcbbind(inp, NULL, curproc);
if (error)
return (error);
- if (in_pcbhashlookup(inp->inp_table, sin->sin_addr,
+ t = in_pcbhashlookup(inp->inp_table, sin->sin_addr,
sin->sin_port, ina, inp->inp_lport,
- inp->inp_rtableid) != NULL) {
+ inp->inp_rtableid);
+ if (t != NULL) {
inp->inp_lport = 0;
+ in_pcbunref(t);
return (EADDRINUSE);
}
}
struct inpcb *
in_pcbref(struct inpcb *inp)
{
- if (inp != NULL)
- refcnt_take(&inp->inp_refcnt);
+ if (inp == NULL)
+ return NULL;
+ refcnt_take(&inp->inp_refcnt);
return inp;
}
void
in_pcbunref(struct inpcb *inp)
{
- if (refcnt_rele(&inp->inp_refcnt)) {
- KASSERT((LIST_NEXT(inp, inp_hash) == NULL) ||
- (LIST_NEXT(inp, inp_hash) == _Q_INVALID));
- KASSERT((LIST_NEXT(inp, inp_lhash) == NULL) ||
- (LIST_NEXT(inp, inp_lhash) == _Q_INVALID));
- KASSERT((TAILQ_NEXT(inp, inp_queue) == NULL) ||
- (TAILQ_NEXT(inp, inp_queue) == _Q_INVALID));
- pool_put(&inpcb_pool, inp);
- }
+ if (inp == NULL)
+ return;
+ if (refcnt_rele(&inp->inp_refcnt) == 0)
+ return;
+ KASSERT((LIST_NEXT(inp, inp_hash) == NULL) ||
+ (LIST_NEXT(inp, inp_hash) == _Q_INVALID));
+ KASSERT((LIST_NEXT(inp, inp_lhash) == NULL) ||
+ (LIST_NEXT(inp, inp_lhash) == _Q_INVALID));
+ KASSERT((TAILQ_NEXT(inp, inp_queue) == NULL) ||
+ (TAILQ_NEXT(inp, inp_queue) == _Q_INVALID));
+ pool_put(&inpcb_pool, inp);
}
void
break;
}
}
+ in_pcbref(match);
mtx_leave(&table->inpt_mtx);
return (match);
break;
}
}
+ in_pcbref(inp);
mtx_leave(&table->inpt_mtx);
#ifdef DIAGNOSTIC
if (inp == NULL && in_pcbnotifymiss) {
LIST_REMOVE(inp, inp_hash);
LIST_INSERT_HEAD(head, inp, inp_hash);
}
+ in_pcbref(inp);
mtx_leave(&table->inpt_mtx);
#ifdef DIAGNOSTIC
if (inp == NULL && in_pcbnotifymiss) {
-/* $OpenBSD: tcp_input.c,v 1.375 2022/01/04 06:32:39 yasuoka Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.376 2022/08/08 12:06:30 bluhm Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
* full-blown connection.
*/
tp = NULL;
- inp = sotoinpcb(so);
+ in_pcbunref(inp);
+ inp = in_pcbref(sotoinpcb(so));
tp = intotcpcb(inp);
if (tp == NULL)
goto badsyn; /*XXX*/
tcpstat_inc(tcps_dropsyn);
goto drop;
}
+ in_pcbunref(inp);
return IPPROTO_DONE;
}
}
if (so->so_snd.sb_cc ||
tp->t_flags & TF_NEEDOUTPUT)
(void) tcp_output(tp);
+ in_pcbunref(inp);
return IPPROTO_DONE;
}
} else if (th->th_ack == tp->snd_una &&
tp->t_flags &= ~TF_BLOCKOUTPUT;
if (tp->t_flags & (TF_ACKNOW|TF_NEEDOUTPUT))
(void) tcp_output(tp);
+ in_pcbunref(inp);
return IPPROTO_DONE;
}
}
((arc4random() & 0x7fffffff) | 0x8000);
reuse = &iss;
tp = tcp_close(tp);
+ in_pcbunref(inp);
inp = NULL;
goto findpcb;
}
*/
if (tp->t_flags & (TF_ACKNOW|TF_NEEDOUTPUT))
(void) tcp_output(tp);
+ in_pcbunref(inp);
return IPPROTO_DONE;
badsyn:
m_freem(m);
tp->t_flags |= TF_ACKNOW;
(void) tcp_output(tp);
+ in_pcbunref(inp);
return IPPROTO_DONE;
dropwithreset_ratelim:
(tcp_seq)0, TH_RST|TH_ACK, m->m_pkthdr.ph_rtableid);
}
m_freem(m);
+ in_pcbunref(inp);
return IPPROTO_DONE;
drop:
tcp_trace(TA_DROP, ostate, tp, otp, saveti, 0, tlen);
m_freem(m);
+ in_pcbunref(inp);
return IPPROTO_DONE;
}
-/* $OpenBSD: tcp_subr.c,v 1.184 2022/03/02 12:53:15 bluhm Exp $ */
+/* $OpenBSD: tcp_subr.c,v 1.185 2022/08/08 12:06:30 bluhm Exp $ */
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
/*
* corresponding routing entry, or
* - ignore the MTU change notification.
*/
- icmp6_mtudisc_update((struct ip6ctlparam *)d, inp != NULL);
+ icmp6_mtudisc_update((struct ip6ctlparam *)d,
+ inp != NULL);
+ in_pcbunref(inp);
return;
}
if (inp) {
inet6ctlerrmap[cmd] == EHOSTDOWN)
syn_cache_unreach((struct sockaddr *)sa6_src,
sa, &th, rdomain);
+ in_pcbunref(inp);
} else {
in6_pcbnotify(&tcbtable, sa6, 0,
sa6_src, 0, rdomain, cmd, NULL, notify);
* ever sent, drop the message.
*/
mtu = (u_int)ntohs(icp->icmp_nextmtu);
- if (mtu >= tp->t_pmtud_mtu_sent)
+ if (mtu >= tp->t_pmtud_mtu_sent) {
+ in_pcbunref(inp);
return;
+ }
if (mtu >= tcp_hdrsz(tp) + tp->t_pmtud_mss_acked) {
/*
* Calculate new MTU, and create corresponding
* refers to an older TCP segment
*/
if (tp->t_flags & TF_PMTUD_PEND) {
- if (SEQ_LT(tp->t_pmtud_th_seq, seq))
+ if (SEQ_LT(tp->t_pmtud_th_seq, seq)) {
+ in_pcbunref(inp);
return;
+ }
} else
tp->t_flags |= TF_PMTUD_PEND;
tp->t_pmtud_th_seq = seq;
tp->t_pmtud_nextmtu = icp->icmp_nextmtu;
tp->t_pmtud_ip_len = icp->icmp_ip.ip_len;
tp->t_pmtud_ip_hl = icp->icmp_ip.ip_hl;
+ in_pcbunref(inp);
return;
}
} else {
/* ignore if we don't have a matching connection */
+ in_pcbunref(inp);
return;
}
+ in_pcbunref(inp);
notify = tcp_mtudisc, ip = 0;
} else if (cmd == PRC_MTUINC)
notify = tcp_mtudisc_increase, ip = 0;
sin.sin_addr = ip->ip_src;
syn_cache_unreach(sintosa(&sin), sa, th, rdomain);
}
+ in_pcbunref(inp);
} else
in_pcbnotifyall(&tcbtable, sa, rdomain, errno, notify);
}
-/* $OpenBSD: tcp_usrreq.c,v 1.183 2022/02/25 23:51:03 guenther Exp $ */
+/* $OpenBSD: tcp_usrreq.c,v 1.184 2022/08/08 12:06:30 bluhm Exp $ */
/* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */
/*
tp = tcp_drop(tp, ECONNABORTED);
else
error = ESRCH;
+ in_pcbunref(inp);
return (error);
}
*oldlenp = sizeof (tir);
error = copyout((void *)&tir, oldp, sizeof (tir));
+ in_pcbunref(inp);
return (error);
}
-/* $OpenBSD: udp_usrreq.c,v 1.280 2022/08/06 15:57:59 bluhm Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.281 2022/08/08 12:06:30 bluhm Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
m = *mp = pipex_l2tp_input(m, off, session,
ipsecflowinfo);
pipex_rele_session(session);
-
- if (m == NULL)
+ if (m == NULL) {
+ in_pcbunref(inp);
return IPPROTO_DONE;
+ }
}
}
#endif
udp_sbappend(inp, m, ip, ip6, iphlen, uh, &srcsa.sa, ipsecflowinfo);
+ in_pcbunref(inp);
return IPPROTO_DONE;
bad:
m_freem(m);
+ in_pcbunref(inp);
return IPPROTO_DONE;
}
u_int16_t uh_sport;
u_int16_t uh_dport;
} *uhp;
+ struct inpcb *inp;
void (*notify)(struct inpcb *, int) = udp_notify;
if (sa == NULL)
}
if (cmd == PRC_MSGSIZE) {
- int valid = 0;
-
/*
* Check to see if we have a valid UDP socket
* corresponding to the address in the ICMPv6 message
* payload.
*/
- if (in6_pcbhashlookup(&udbtable, &sa6.sin6_addr,
+ inp = in6_pcbhashlookup(&udbtable, &sa6.sin6_addr,
uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport,
- rdomain))
- valid = 1;
+ rdomain);
#if 0
/*
* As the use of sendto(2) is fairly popular,
* We should at least check if the local address (= s)
* is really ours.
*/
- else if (in6_pcblookup_listen(&udbtable,
- &sa6_src.sin6_addr, uh.uh_sport, NULL,
- rdomain))
- valid = 1;
+ if (inp == NULL) {
+ inp = in6_pcblookup_listen(&udbtable,
+ &sa6_src.sin6_addr, uh.uh_sport, NULL,
+ rdomain))
+ }
#endif
/*
* corresponding routing entry, or
* - ignore the MTU change notification.
*/
- icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
+ icmp6_mtudisc_update((struct ip6ctlparam *)d,
+ inp != NULL);
+ in_pcbunref(inp);
/*
* regardless of if we called icmp6_mtudisc_update(),
rdomain);
if (inp && inp->inp_socket != NULL)
notify(inp, errno);
+ in_pcbunref(inp);
} else
in_pcbnotifyall(&udbtable, sa, rdomain, errno, notify);
}
-/* $OpenBSD: in6_pcb.c,v 1.118 2022/08/06 15:57:59 bluhm Exp $ */
+/* $OpenBSD: in6_pcb.c,v 1.119 2022/08/08 12:06:31 bluhm Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
}
if (lport) {
struct inpcb *t;
+ 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);
if (t && (so->so_euid != t->inp_socket->so_euid))
- return (EADDRINUSE);
+ error = EADDRINUSE;
+ in_pcbunref(t);
+ if (error)
+ return (error);
}
t = in_pcblookup_local(table, &sin6->sin6_addr, lport,
wild, inp->inp_rtableid);
if (t && (reuseport & t->inp_socket->so_options) == 0)
- return (EADDRINUSE);
+ error = EADDRINUSE;
+ in_pcbunref(t);
+ if (error)
+ return (error);
}
return (0);
}
{
struct in6_addr *in6a = NULL;
struct sockaddr_in6 *sin6;
+ struct inpcb *t;
int error;
struct sockaddr_in6 tmp;
inp->inp_ipv6.ip6_hlim = (u_int8_t)in6_selecthlim(inp);
- if (in6_pcbhashlookup(inp->inp_table, &sin6->sin6_addr, sin6->sin6_port,
+ t = in6_pcbhashlookup(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) != NULL) {
+ inp->inp_lport, inp->inp_rtableid);
+ if (t != NULL) {
+ in_pcbunref(t);
return (EADDRINUSE);
}
error = in_pcbbind(inp, NULL, curproc);
if (error)
return (error);
- if (in6_pcbhashlookup(inp->inp_table, &sin6->sin6_addr,
+ t = in6_pcbhashlookup(inp->inp_table, &sin6->sin6_addr,
sin6->sin6_port, in6a, inp->inp_lport,
- inp->inp_rtableid) != NULL) {
+ inp->inp_rtableid);
+ if (t != NULL) {
inp->inp_lport = 0;
+ in_pcbunref(t);
return (EADDRINUSE);
}
}
break;
}
}
+ in_pcbref(inp);
mtx_leave(&table->inpt_mtx);
#ifdef DIAGNOSTIC
if (inp == NULL && in_pcbnotifymiss) {
LIST_REMOVE(inp, inp_hash);
LIST_INSERT_HEAD(head, inp, inp_hash);
}
+ in_pcbref(inp);
mtx_leave(&table->inpt_mtx);
#ifdef DIAGNOSTIC
if (inp == NULL && in_pcbnotifymiss) {
-/* $OpenBSD: raw_ip6.c,v 1.148 2022/08/06 15:57:59 bluhm Exp $ */
+/* $OpenBSD: raw_ip6.c,v 1.149 2022/08/08 12:06:31 bluhm Exp $ */
/* $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $ */
/*
if (in6p && in6p->inp_ipv6.ip6_nxt &&
in6p->inp_ipv6.ip6_nxt == nxt)
- valid++;
+ valid = 1;
/*
* Depending on the value of "valid" and routing table
* - ignore the MTU change notification.
*/
icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
+ in_pcbunref(in6p);
/*
* regardless of if we called icmp6_mtudisc_update(),