diff --git a/sys/dev/wg/if_wg.c b/sys/dev/wg/if_wg.c --- a/sys/dev/wg/if_wg.c +++ b/sys/dev/wg/if_wg.c @@ -943,34 +943,52 @@ struct mbuf *control = NULL; int ret = 0; size_t len = m->m_pkthdr.len; + sa_family_t rfamily; - /* Get local control address before locking */ - if (e->e_remote.r_sa.sa_family == AF_INET) { + /* Get remote address, local control address before locking. */ + sa = &e->e_remote.r_sa; + rfamily = sa->sa_family; + if (rfamily == AF_INET) { if (e->e_local.l_in.s_addr != INADDR_ANY) control = sbcreatecontrol((caddr_t)&e->e_local.l_in, sizeof(struct in_addr), IP_SENDSRCADDR, IPPROTO_IP, M_NOWAIT); #ifdef INET6 - } else if (e->e_remote.r_sa.sa_family == AF_INET6) { + } else if (rfamily == AF_INET6) { if (!IN6_IS_ADDR_UNSPECIFIED(&e->e_local.l_in6)) control = sbcreatecontrol((caddr_t)&e->e_local.l_pktinfo6, sizeof(struct in6_pktinfo), IPV6_PKTINFO, IPPROTO_IPV6, M_NOWAIT); #endif } else { + if (rfamily == 0) { + /* + * wg_peer_set_endpoint() will assert if we managed to + * set a bogus endpoint, so we can conclude that the + * endpoint simply isn't set. One likely candidate for + * hitting this is having set persistent-keepalive on + * a peer without an endpoint: for simplicity, we start + * the timer and just let those packets get dropped + * after this. That setup likely doesn't make much + * sense, but it is a valid configuration. + */ + DPRINTF(sc, "Endpoint is not set\n"); + } else { + DPRINTF(sc, + "Endpoint has unsupported address family %d\n", + rfamily); + } + m_freem(m); return (EAFNOSUPPORT); } - /* Get remote address */ - sa = &e->e_remote.r_sa; - NET_EPOCH_ENTER(et); so4 = atomic_load_ptr(&so->so_so4); so6 = atomic_load_ptr(&so->so_so6); - if (e->e_remote.r_sa.sa_family == AF_INET && so4 != NULL) + if (rfamily == AF_INET && so4 != NULL) ret = sosend(so4, sa, NULL, m, control, 0, curthread); - else if (e->e_remote.r_sa.sa_family == AF_INET6 && so6 != NULL) + else if (rfamily == AF_INET6 && so6 != NULL) ret = sosend(so6, sa, NULL, m, control, 0, curthread); else { ret = ENOTCONN;