summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet')
-rw-r--r--freebsd/sys/netinet/in_mcast.c22
-rw-r--r--freebsd/sys/netinet/ip_carp.c26
-rw-r--r--freebsd/sys/netinet/ip_carp.h4
-rw-r--r--freebsd/sys/netinet/ip_mroute.c26
-rw-r--r--freebsd/sys/netinet/ip_output.c2
-rw-r--r--freebsd/sys/netinet/ip_reass.c56
-rw-r--r--freebsd/sys/netinet/sctp_asconf.c111
-rw-r--r--freebsd/sys/netinet/sctp_dtrace_define.h177
-rw-r--r--freebsd/sys/netinet/sctp_indata.c52
-rw-r--r--freebsd/sys/netinet/sctp_input.c36
-rw-r--r--freebsd/sys/netinet/sctp_os_bsd.h7
-rw-r--r--freebsd/sys/netinet/sctp_output.c13
-rw-r--r--freebsd/sys/netinet/sctp_pcb.c9
-rw-r--r--freebsd/sys/netinet/sctp_pcb.h2
-rw-r--r--freebsd/sys/netinet/sctp_usrreq.c10
-rw-r--r--freebsd/sys/netinet/sctputil.c34
-rw-r--r--freebsd/sys/netinet/sctputil.h2
-rw-r--r--freebsd/sys/netinet/tcp_input.c43
-rw-r--r--freebsd/sys/netinet/tcp_output.c14
-rw-r--r--freebsd/sys/netinet/tcp_subr.c2
-rw-r--r--freebsd/sys/netinet/tcp_timer.c9
-rw-r--r--freebsd/sys/netinet/tcp_timer.h3
-rw-r--r--freebsd/sys/netinet/tcp_usrreq.c106
-rw-r--r--freebsd/sys/netinet/tcp_var.h3
-rw-r--r--freebsd/sys/netinet/udp_usrreq.c11
-rw-r--r--freebsd/sys/netinet/udp_var.h3
26 files changed, 392 insertions, 391 deletions
diff --git a/freebsd/sys/netinet/in_mcast.c b/freebsd/sys/netinet/in_mcast.c
index ff442399..cbb6c6d3 100644
--- a/freebsd/sys/netinet/in_mcast.c
+++ b/freebsd/sys/netinet/in_mcast.c
@@ -2207,7 +2207,11 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt)
__func__);
goto out_inp_locked;
}
- inm_acquire(imf->imf_inm);
+ /*
+ * NOTE: Refcount from in_joingroup_locked()
+ * is protecting membership.
+ */
+ ip_mfilter_insert(&imo->imo_head, imf);
} else {
CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
IN_MULTI_LIST_LOCK();
@@ -2231,8 +2235,6 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt)
goto out_inp_locked;
}
}
- if (is_new)
- ip_mfilter_insert(&imo->imo_head, imf);
imf_commit(imf);
imf = NULL;
@@ -2401,6 +2403,12 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt)
if (is_final) {
ip_mfilter_remove(&imo->imo_head, imf);
imf_leave(imf);
+
+ /*
+ * Give up the multicast address record to which
+ * the membership points.
+ */
+ (void) in_leavegroup_locked(imf->imf_inm, imf);
} else {
if (imf->imf_st[0] == MCAST_EXCLUDE) {
error = EADDRNOTAVAIL;
@@ -2455,14 +2463,8 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt)
out_inp_locked:
INP_WUNLOCK(inp);
- if (is_final && imf) {
- /*
- * Give up the multicast address record to which
- * the membership points.
- */
- (void) in_leavegroup_locked(imf->imf_inm, imf);
+ if (is_final && imf)
ip_mfilter_free(imf);
- }
IN_MULTI_UNLOCK();
return (error);
diff --git a/freebsd/sys/netinet/ip_carp.c b/freebsd/sys/netinet/ip_carp.c
index 02a24bb8..30b09198 100644
--- a/freebsd/sys/netinet/ip_carp.c
+++ b/freebsd/sys/netinet/ip_carp.c
@@ -568,13 +568,16 @@ carp6_input(struct mbuf **mp, int *offp, int proto)
}
/* verify that we have a complete carp packet */
- len = m->m_len;
- IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch));
- if (ch == NULL) {
- CARPSTATS_INC(carps_badlen);
- CARP_DEBUG("%s: packet size %u too small\n", __func__, len);
- return (IPPROTO_DONE);
+ if (m->m_len < *offp + sizeof(*ch)) {
+ len = m->m_len;
+ m = m_pullup(m, *offp + sizeof(*ch));
+ if (m == NULL) {
+ CARPSTATS_INC(carps_badlen);
+ CARP_DEBUG("%s: packet size %u too small\n", __func__, len);
+ return (IPPROTO_DONE);
+ }
}
+ ch = (struct carp_header *)(mtod(m, char *) + *offp);
/* verify the CARP checksum */
@@ -1189,7 +1192,7 @@ carp_iamatch6(struct ifnet *ifp, struct in6_addr *taddr)
return (ifa);
}
-caddr_t
+char *
carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr)
{
struct ifaddr *ifa;
@@ -1231,14 +1234,15 @@ carp_forus(struct ifnet *ifp, u_char *dhost)
CIF_LOCK(ifp->if_carp);
IFNET_FOREACH_CARP(ifp, sc) {
- CARP_LOCK(sc);
+ /*
+ * CARP_LOCK() is not here, since would protect nothing, but
+ * cause deadlock with if_bridge, calling this under its lock.
+ */
if (sc->sc_state == MASTER && !bcmp(dhost, LLADDR(&sc->sc_addr),
ETHER_ADDR_LEN)) {
- CARP_UNLOCK(sc);
CIF_UNLOCK(ifp->if_carp);
return (1);
}
- CARP_UNLOCK(sc);
}
CIF_UNLOCK(ifp->if_carp);
@@ -1848,7 +1852,7 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
carp_carprcp(&carpr, sc, priveleged);
carpr.carpr_count = count;
error = copyout(&carpr,
- (caddr_t)ifr_data_get_ptr(ifr) +
+ (char *)ifr_data_get_ptr(ifr) +
(i * sizeof(carpr)), sizeof(carpr));
if (error) {
CIF_UNLOCK(ifp->if_carp);
diff --git a/freebsd/sys/netinet/ip_carp.h b/freebsd/sys/netinet/ip_carp.h
index fc591ac3..f8ee38dd 100644
--- a/freebsd/sys/netinet/ip_carp.h
+++ b/freebsd/sys/netinet/ip_carp.h
@@ -149,7 +149,7 @@ int carp_output (struct ifnet *, struct mbuf *,
int carp_master(struct ifaddr *);
int carp_iamatch(struct ifaddr *, uint8_t **);
struct ifaddr *carp_iamatch6(struct ifnet *, struct in6_addr *);
-caddr_t carp_macmatch6(struct ifnet *, struct mbuf *, const struct in6_addr *);
+char * carp_macmatch6(struct ifnet *, struct mbuf *, const struct in6_addr *);
int carp_forus(struct ifnet *, u_char *);
/* These are external networking stack hooks for CARP */
@@ -174,7 +174,7 @@ extern int (*carp_iamatch_p)(struct ifaddr *, uint8_t **);
#ifdef INET6
/* netinet6/nd6_nbr.c */
extern struct ifaddr *(*carp_iamatch6_p)(struct ifnet *, struct in6_addr *);
-extern caddr_t (*carp_macmatch6_p)(struct ifnet *, struct mbuf *,
+extern char * (*carp_macmatch6_p)(struct ifnet *, struct mbuf *,
const struct in6_addr *);
#endif
#endif
diff --git a/freebsd/sys/netinet/ip_mroute.c b/freebsd/sys/netinet/ip_mroute.c
index 3dd887f3..3b27781e 100644
--- a/freebsd/sys/netinet/ip_mroute.c
+++ b/freebsd/sys/netinet/ip_mroute.c
@@ -181,10 +181,14 @@ static struct mtx mfc_mtx;
VNET_DEFINE_STATIC(vifi_t, numvifs);
#define V_numvifs VNET(numvifs)
-VNET_DEFINE_STATIC(struct vif, viftable[MAXVIFS]);
+VNET_DEFINE_STATIC(struct vif *, viftable);
#define V_viftable VNET(viftable)
+/*
+ * No one should be able to "query" this before initialisation happened in
+ * vnet_mroute_init(), so we should still be fine.
+ */
SYSCTL_OPAQUE(_net_inet_ip, OID_AUTO, viftable, CTLFLAG_VNET | CTLFLAG_RD,
- &VNET_NAME(viftable), sizeof(V_viftable), "S,vif[MAXVIFS]",
+ &VNET_NAME(viftable), sizeof(*V_viftable) * MAXVIFS, "S,vif[MAXVIFS]",
"IPv4 Multicast Interfaces (struct vif[MAXVIFS], netinet/ip_mroute.h)");
static struct mtx vif_mtx;
@@ -212,7 +216,7 @@ static MALLOC_DEFINE(M_BWMETER, "bwmeter", "multicast upcall bw meters");
* expiration time. Periodically, the entries are analysed and processed.
*/
#define BW_METER_BUCKETS 1024
-VNET_DEFINE_STATIC(struct bw_meter*, bw_meter_timers[BW_METER_BUCKETS]);
+VNET_DEFINE_STATIC(struct bw_meter **, bw_meter_timers);
#define V_bw_meter_timers VNET(bw_meter_timers)
VNET_DEFINE_STATIC(struct callout, bw_meter_ch);
#define V_bw_meter_ch VNET(bw_meter_ch)
@@ -222,7 +226,7 @@ VNET_DEFINE_STATIC(struct callout, bw_meter_ch);
* Pending upcalls are stored in a vector which is flushed when
* full, or periodically
*/
-VNET_DEFINE_STATIC(struct bw_upcall, bw_upcalls[BW_UPCALLS_MAX]);
+VNET_DEFINE_STATIC(struct bw_upcall *, bw_upcalls);
#define V_bw_upcalls VNET(bw_upcalls)
VNET_DEFINE_STATIC(u_int, bw_upcalls_n); /* # of pending upcalls */
#define V_bw_upcalls_n VNET(bw_upcalls_n)
@@ -766,7 +770,7 @@ X_ip_mrouter_done(void)
bzero(V_nexpire, sizeof(V_nexpire[0]) * mfchashsize);
V_bw_upcalls_n = 0;
- bzero(V_bw_meter_timers, sizeof(V_bw_meter_timers));
+ bzero(V_bw_meter_timers, BW_METER_BUCKETS * sizeof(*V_bw_meter_timers));
MFC_UNLOCK();
@@ -2807,7 +2811,14 @@ vnet_mroute_init(const void *unused __unused)
{
V_nexpire = malloc(mfchashsize, M_MRTABLE, M_WAITOK|M_ZERO);
- bzero(V_bw_meter_timers, sizeof(V_bw_meter_timers));
+
+ V_viftable = mallocarray(MAXVIFS, sizeof(*V_viftable),
+ M_MRTABLE, M_WAITOK|M_ZERO);
+ V_bw_meter_timers = mallocarray(BW_METER_BUCKETS,
+ sizeof(*V_bw_meter_timers), M_MRTABLE, M_WAITOK|M_ZERO);
+ V_bw_upcalls = mallocarray(BW_UPCALLS_MAX, sizeof(*V_bw_upcalls),
+ M_MRTABLE, M_WAITOK|M_ZERO);
+
callout_init(&V_expire_upcalls_ch, 1);
callout_init(&V_bw_upcalls_ch, 1);
callout_init(&V_bw_meter_ch, 1);
@@ -2820,6 +2831,9 @@ static void
vnet_mroute_uninit(const void *unused __unused)
{
+ free(V_bw_upcalls, M_MRTABLE);
+ free(V_bw_meter_timers, M_MRTABLE);
+ free(V_viftable, M_MRTABLE);
free(V_nexpire, M_MRTABLE);
V_nexpire = NULL;
}
diff --git a/freebsd/sys/netinet/ip_output.c b/freebsd/sys/netinet/ip_output.c
index c9eb7aa3..343874e5 100644
--- a/freebsd/sys/netinet/ip_output.c
+++ b/freebsd/sys/netinet/ip_output.c
@@ -655,6 +655,7 @@ sendit:
in_pcboutput_txrtlmt(inp, ifp, m);
/* stamp send tag on mbuf */
m->m_pkthdr.snd_tag = inp->inp_snd_tag;
+ m->m_pkthdr.csum_flags |= CSUM_SND_TAG;
} else {
m->m_pkthdr.snd_tag = NULL;
}
@@ -707,6 +708,7 @@ sendit:
in_pcboutput_txrtlmt(inp, ifp, m);
/* stamp send tag on mbuf */
m->m_pkthdr.snd_tag = inp->inp_snd_tag;
+ m->m_pkthdr.csum_flags |= CSUM_SND_TAG;
} else {
m->m_pkthdr.snd_tag = NULL;
}
diff --git a/freebsd/sys/netinet/ip_reass.c b/freebsd/sys/netinet/ip_reass.c
index 70a6edae..036d19fe 100644
--- a/freebsd/sys/netinet/ip_reass.c
+++ b/freebsd/sys/netinet/ip_reass.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/eventhandler.h>
+#include <sys/kernel.h>
#include <sys/hash.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
@@ -48,7 +49,10 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_var.h>
#include <net/rss_config.h>
#include <net/netisr.h>
#include <net/vnet.h>
@@ -182,6 +186,7 @@ ip_reass(struct mbuf *m)
struct ip *ip;
struct mbuf *p, *q, *nq, *t;
struct ipq *fp;
+ struct ifnet *srcifp;
struct ipqhead *head;
int i, hlen, next, tmpmax;
u_int8_t ecn, ecn0;
@@ -242,6 +247,11 @@ ip_reass(struct mbuf *m)
}
/*
+ * Store receive network interface pointer for later.
+ */
+ srcifp = m->m_pkthdr.rcvif;
+
+ /*
* Attempt reassembly; if it succeeds, proceed.
* ip_reass() will return a different mbuf.
*/
@@ -491,8 +501,11 @@ ip_reass(struct mbuf *m)
m->m_len += (ip->ip_hl << 2);
m->m_data -= (ip->ip_hl << 2);
/* some debugging cruft by sklower, below, will go away soon */
- if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */
+ if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
m_fixhdr(m);
+ /* set valid receive interface pointer */
+ m->m_pkthdr.rcvif = srcifp;
+ }
IPSTAT_INC(ips_reassembled);
IPQ_UNLOCK(hash);
@@ -608,6 +621,46 @@ ipreass_drain(void)
}
}
+/*
+ * Drain off all datagram fragments belonging to
+ * the given network interface.
+ */
+static void
+ipreass_cleanup(void *arg __unused, struct ifnet *ifp)
+{
+ struct ipq *fp, *temp;
+ struct mbuf *m;
+ int i;
+
+ KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__));
+
+ CURVNET_SET_QUIET(ifp->if_vnet);
+
+ /*
+ * Skip processing if IPv4 reassembly is not initialised or
+ * torn down by ipreass_destroy().
+ */
+ if (V_ipq_zone == NULL) {
+ CURVNET_RESTORE();
+ return;
+ }
+
+ for (i = 0; i < IPREASS_NHASH; i++) {
+ IPQ_LOCK(i);
+ /* Scan fragment list. */
+ TAILQ_FOREACH_SAFE(fp, &V_ipq[i].head, ipq_list, temp) {
+ for (m = fp->ipq_frags; m != NULL; m = m->m_nextpkt) {
+ /* clear no longer valid rcvif pointer */
+ if (m->m_pkthdr.rcvif == ifp)
+ m->m_pkthdr.rcvif = NULL;
+ }
+ }
+ IPQ_UNLOCK(i);
+ }
+ CURVNET_RESTORE();
+}
+EVENTHANDLER_DEFINE(ifnet_departure_event, ipreass_cleanup, NULL, 0);
+
#ifdef VIMAGE
/*
* Destroy IP reassembly structures.
@@ -618,6 +671,7 @@ ipreass_destroy(void)
ipreass_drain();
uma_zdestroy(V_ipq_zone);
+ V_ipq_zone = NULL;
for (int i = 0; i < IPREASS_NHASH; i++)
mtx_destroy(&V_ipq[i].lock);
}
diff --git a/freebsd/sys/netinet/sctp_asconf.c b/freebsd/sys/netinet/sctp_asconf.c
index 4de01ed7..a13f4040 100644
--- a/freebsd/sys/netinet/sctp_asconf.c
+++ b/freebsd/sys/netinet/sctp_asconf.c
@@ -107,42 +107,47 @@ sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t *error_tlv,
struct mbuf *m_reply = NULL;
struct sctp_asconf_paramhdr *aph;
struct sctp_error_cause *error;
+ size_t buf_len;
+ uint16_t i, param_length, cause_length, padding_length;
uint8_t *tlv;
- m_reply = sctp_get_mbuf_for_msg((sizeof(struct sctp_asconf_paramhdr) +
- tlv_length +
- sizeof(struct sctp_error_cause)),
- 0, M_NOWAIT, 1, MT_DATA);
+ if (error_tlv == NULL) {
+ tlv_length = 0;
+ }
+ cause_length = sizeof(struct sctp_error_cause) + tlv_length;
+ param_length = sizeof(struct sctp_asconf_paramhdr) + cause_length;
+ padding_length = tlv_length % 4;
+ if (padding_length != 0) {
+ padding_length = 4 - padding_length;
+ }
+ buf_len = param_length + padding_length;
+ if (buf_len > MLEN) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1,
+ "asconf_error_response: tlv_length (%xh) too big\n",
+ tlv_length);
+ return (NULL);
+ }
+ m_reply = sctp_get_mbuf_for_msg(buf_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_reply == NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1,
"asconf_error_response: couldn't get mbuf!\n");
return (NULL);
}
aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
- error = (struct sctp_error_cause *)(aph + 1);
-
- aph->correlation_id = id;
aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND);
+ aph->ph.param_length = htons(param_length);
+ aph->correlation_id = id;
+ error = (struct sctp_error_cause *)(aph + 1);
error->code = htons(cause);
- error->length = tlv_length + sizeof(struct sctp_error_cause);
- aph->ph.param_length = error->length +
- sizeof(struct sctp_asconf_paramhdr);
-
- if (aph->ph.param_length > MLEN) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_error_response: tlv_length (%xh) too big\n",
- tlv_length);
- sctp_m_freem(m_reply); /* discard */
- return (NULL);
- }
+ error->length = htons(cause_length);
if (error_tlv != NULL) {
tlv = (uint8_t *)(error + 1);
memcpy(tlv, error_tlv, tlv_length);
+ for (i = 0; i < padding_length; i++) {
+ tlv[tlv_length + i] = 0;
+ }
}
- SCTP_BUF_LEN(m_reply) = aph->ph.param_length;
- error->length = htons(error->length);
- aph->ph.param_length = htons(aph->ph.param_length);
-
+ SCTP_BUF_LEN(m_reply) = buf_len;
return (m_reply);
}
@@ -171,10 +176,16 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
#endif
aparam_length = ntohs(aph->ph.param_length);
+ if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
+ return (NULL);
+ }
ph = (struct sctp_paramhdr *)(aph + 1);
param_type = ntohs(ph->param_type);
#if defined(INET) || defined(INET6)
param_length = ntohs(ph->param_length);
+ if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
+ return (NULL);
+ }
#endif
sa = &store.sa;
switch (param_type) {
@@ -238,6 +249,7 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
"process_asconf_add_ip: using source addr ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
}
+ net = NULL;
/* add the address */
if (bad_address) {
m_reply = sctp_asconf_error_response(aph->correlation_id,
@@ -252,17 +264,19 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
SCTP_CAUSE_RESOURCE_SHORTAGE, (uint8_t *)aph,
aparam_length);
} else {
- /* notify upper layer */
- sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
if (response_required) {
m_reply =
sctp_asconf_success_response(aph->correlation_id);
}
- sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
- stcb, net);
- if (send_hb) {
- sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
+ if (net != NULL) {
+ /* notify upper layer */
+ sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
+ sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
+ sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
+ stcb, net);
+ if (send_hb) {
+ sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
+ }
}
}
return (m_reply);
@@ -271,7 +285,7 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
static int
sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
{
- struct sctp_nets *src_net, *net;
+ struct sctp_nets *src_net, *net, *nnet;
/* make sure the source address exists as a destination net */
src_net = sctp_findnet(stcb, src);
@@ -281,10 +295,9 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
}
/* delete all destination addresses except the source */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) {
if (net != src_net) {
/* delete this address */
- sctp_remove_net(stcb, net);
SCTPDBG(SCTP_DEBUG_ASCONF1,
"asconf_del_remote_addrs_except: deleting ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1,
@@ -292,6 +305,7 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
/* notify upper layer */
sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0,
(struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED);
+ sctp_remove_net(stcb, net);
}
}
return (0);
@@ -322,10 +336,16 @@ sctp_process_asconf_delete_ip(struct sockaddr *src,
#endif
aparam_length = ntohs(aph->ph.param_length);
+ if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
+ return (NULL);
+ }
ph = (struct sctp_paramhdr *)(aph + 1);
param_type = ntohs(ph->param_type);
#if defined(INET) || defined(INET6)
param_length = ntohs(ph->param_length);
+ if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
+ return (NULL);
+ }
#endif
sa = &store.sa;
switch (param_type) {
@@ -453,10 +473,16 @@ sctp_process_asconf_set_primary(struct sockaddr *src,
#endif
aparam_length = ntohs(aph->ph.param_length);
+ if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
+ return (NULL);
+ }
ph = (struct sctp_paramhdr *)(aph + 1);
param_type = ntohs(ph->param_type);
#if defined(INET) || defined(INET6)
param_length = ntohs(ph->param_length);
+ if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
+ return (NULL);
+ }
#endif
sa = &store.sa;
switch (param_type) {
@@ -675,8 +701,8 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
sctp_m_freem(m_ack);
return;
}
- /* param_length is already validated in process_control... */
- offset += ntohs(p_addr->ph.param_length); /* skip lookup addr */
+ /* skip lookup addr */
+ offset += SCTP_SIZE32(ntohs(p_addr->ph.param_length));
/* get pointer to first asconf param in ASCONF */
aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf);
if (aph == NULL) {
@@ -705,6 +731,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
if (param_length <= sizeof(struct sctp_paramhdr)) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) too short\n", param_length);
sctp_m_freem(m_ack);
+ return;
}
/* get the entire parameter */
aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
@@ -760,8 +787,6 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset,
if (m_result != NULL) {
SCTP_BUF_NEXT(m_tail) = m_result;
m_tail = m_result;
- /* update lengths, make sure it's aligned too */
- SCTP_BUF_LEN(m_result) = SCTP_SIZE32(SCTP_BUF_LEN(m_result));
ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result);
/* set flag to force success reports */
error = 1;
@@ -1956,12 +1981,10 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
case AF_INET:
{
struct sockaddr_in *sin;
- struct in6pcb *inp6;
- inp6 = (struct in6pcb *)&inp->ip_inp.inp;
/* invalid if we are a v6 only endpoint */
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp6))
+ SCTP_IPV6_V6ONLY(&inp->ip_inp.inp))
return;
sin = &ifa->address.sin;
@@ -2034,11 +2057,9 @@ sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNU
case AF_INET:
{
/* invalid if we are a v6 only endpoint */
- struct in6pcb *inp6;
- inp6 = (struct in6pcb *)&inp->ip_inp.inp;
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp6)) {
+ SCTP_IPV6_V6ONLY(&inp->ip_inp.inp)) {
cnt_invalid++;
if (asc->cnt == cnt_invalid)
return (1);
@@ -2149,13 +2170,11 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
case AF_INET:
{
/* invalid if we are a v6 only endpoint */
- struct in6pcb *inp6;
struct sockaddr_in *sin;
- inp6 = (struct in6pcb *)&inp->ip_inp.inp;
/* invalid if we are a v6 only endpoint */
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp6))
+ SCTP_IPV6_V6ONLY(&inp->ip_inp.inp))
continue;
sin = &ifa->address.sin;
@@ -2172,7 +2191,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
continue;
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp6)) {
+ SCTP_IPV6_V6ONLY(&inp->ip_inp.inp)) {
cnt_invalid++;
if (asc->cnt == cnt_invalid)
return;
diff --git a/freebsd/sys/netinet/sctp_dtrace_define.h b/freebsd/sys/netinet/sctp_dtrace_define.h
deleted file mode 100644
index ad7c8526..00000000
--- a/freebsd/sys/netinet/sctp_dtrace_define.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
- * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * a) Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * b) Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the distribution.
- *
- * c) Neither the name of Cisco Systems, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#ifndef _NETINET_SCTP_DTRACE_DEFINE_H_
-#define _NETINET_SCTP_DTRACE_DEFINE_H_
-
-#include <sys/kernel.h>
-#include <sys/sdt.h>
-
-SDT_PROVIDER_DECLARE(sctp);
-
-/********************************************************/
-/* Cwnd probe - tracks changes in the congestion window on a netp */
-/********************************************************/
-/* Initial */
-SDT_PROBE_DEFINE5(sctp, cwnd, net, init,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "uintptr_t", /* The pointer to the struct sctp_nets *
- * changing */
- "int", /* The old value of the cwnd */
- "int"); /* The new value of the cwnd */
-
-/* ACK-INCREASE */
-SDT_PROBE_DEFINE5(sctp, cwnd, net, ack,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "uintptr_t", /* The pointer to the struct sctp_nets *
- * changing */
- "int", /* The old value of the cwnd */
- "int"); /* The new value of the cwnd */
-
-/* ACK-INCREASE */
-SDT_PROBE_DEFINE5(sctp, cwnd, net, rttvar,
- "uint64_t", /* The Vtag << 32 | localport << 16 |
- * remoteport */
- "uint64_t", /* obw | nbw */
- "uint64_t", /* bwrtt | newrtt */
- "uint64_t", /* flight */
- "uint64_t"); /* (cwnd << 32) | point << 16 | retval(0/1) */
-
-SDT_PROBE_DEFINE5(sctp, cwnd, net, rttstep,
- "uint64_t", /* The Vtag << 32 | localport << 16 |
- * remoteport */
- "uint64_t", /* obw | nbw */
- "uint64_t", /* bwrtt | newrtt */
- "uint64_t", /* flight */
- "uint64_t"); /* (cwnd << 32) | point << 16 | retval(0/1) */
-
-/* FastRetransmit-DECREASE */
-SDT_PROBE_DEFINE5(sctp, cwnd, net, fr,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "uintptr_t", /* The pointer to the struct sctp_nets *
- * changing */
- "int", /* The old value of the cwnd */
- "int"); /* The new value of the cwnd */
-
-/* TimeOut-DECREASE */
-SDT_PROBE_DEFINE5(sctp, cwnd, net, to,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "uintptr_t", /* The pointer to the struct sctp_nets *
- * changing */
- "int", /* The old value of the cwnd */
- "int"); /* The new value of the cwnd */
-
-/* BurstLimit-DECREASE */
-SDT_PROBE_DEFINE5(sctp, cwnd, net, bl,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "uintptr_t", /* The pointer to the struct sctp_nets *
- * changing */
- "int", /* The old value of the cwnd */
- "int"); /* The new value of the cwnd */
-
-/* ECN-DECREASE */
-SDT_PROBE_DEFINE5(sctp, cwnd, net, ecn,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "uintptr_t", /* The pointer to the struct sctp_nets *
- * changing */
- "int", /* The old value of the cwnd */
- "int"); /* The new value of the cwnd */
-
-/* PacketDrop-DECREASE */
-SDT_PROBE_DEFINE5(sctp, cwnd, net, pd,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "uintptr_t", /* The pointer to the struct sctp_nets *
- * changing */
- "int", /* The old value of the cwnd */
- "int"); /* The new value of the cwnd */
-
-/********************************************************/
-/* Rwnd probe - tracks changes in the receiver window for an assoc */
-/********************************************************/
-SDT_PROBE_DEFINE4(sctp, rwnd, assoc, val,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "int", /* The up/down amount */
- "int"); /* The new value of the cwnd */
-
-/********************************************************/
-/* flight probe - tracks changes in the flight size on a net or assoc */
-/********************************************************/
-SDT_PROBE_DEFINE5(sctp, flightsize, net, val,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "uintptr_t", /* The pointer to the struct sctp_nets *
- * changing */
- "int", /* The up/down amount */
- "int"); /* The new value of the cwnd */
-
-/********************************************************/
-/* The total flight version */
-/********************************************************/
-SDT_PROBE_DEFINE4(sctp, flightsize, assoc, val,
- "uint32_t", /* The Vtag for this end */
- "uint32_t", /* The port number of the local side << 16 |
- * port number of remote in network byte
- * order. */
- "int", /* The up/down amount */
- "int"); /* The new value of the cwnd */
-
-#endif
diff --git a/freebsd/sys/netinet/sctp_indata.c b/freebsd/sys/netinet/sctp_indata.c
index c4a11fec..1b28cc38 100644
--- a/freebsd/sys/netinet/sctp_indata.c
+++ b/freebsd/sys/netinet/sctp_indata.c
@@ -474,6 +474,11 @@ sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control
chk->data = NULL;
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
}
+ sctp_free_remote_addr(control->whoFrom);
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ }
sctp_free_a_readq(stcb, control);
}
@@ -713,6 +718,7 @@ sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m, ui
}
if (control->tail_mbuf == NULL) {
/* TSNH */
+ sctp_m_freem(control->data);
control->data = m;
sctp_setup_tail_pointer(control);
return;
@@ -2116,10 +2122,13 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
struct mbuf *mm;
control->data = dmbuf;
+ control->tail_mbuf = NULL;
for (mm = control->data; mm; mm = mm->m_next) {
control->length += SCTP_BUF_LEN(mm);
+ if (SCTP_BUF_NEXT(mm) == NULL) {
+ control->tail_mbuf = mm;
+ }
}
- control->tail_mbuf = NULL;
control->end_added = 1;
control->last_frag_seen = 1;
control->first_frag_seen = 1;
@@ -3110,13 +3119,12 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
* update RTO too ?
*/
if (tp1->do_rtt) {
- if (*rto_ok) {
- tp1->whoTo->RTO =
- sctp_calculate_rto(stcb,
- &stcb->asoc,
- tp1->whoTo,
- &tp1->sent_rcv_time,
- SCTP_RTT_FROM_DATA);
+ if (*rto_ok &&
+ sctp_calculate_rto(stcb,
+ &stcb->asoc,
+ tp1->whoTo,
+ &tp1->sent_rcv_time,
+ SCTP_RTT_FROM_DATA)) {
*rto_ok = 0;
}
if (tp1->whoTo->rto_needed == 0) {
@@ -4088,16 +4096,12 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
/* update RTO too? */
if (tp1->do_rtt) {
- if (rto_ok) {
- tp1->whoTo->RTO =
- /*
- * sa_ignore
- * NO_NULL_CHK
- */
- sctp_calculate_rto(stcb,
- asoc, tp1->whoTo,
- &tp1->sent_rcv_time,
- SCTP_RTT_FROM_DATA);
+ if (rto_ok &&
+ sctp_calculate_rto(stcb,
+ &stcb->asoc,
+ tp1->whoTo,
+ &tp1->sent_rcv_time,
+ SCTP_RTT_FROM_DATA)) {
rto_ok = 0;
}
if (tp1->whoTo->rto_needed == 0) {
@@ -4706,12 +4710,12 @@ hopeless_peer:
/* update RTO too? */
if (tp1->do_rtt) {
- if (rto_ok) {
- tp1->whoTo->RTO =
- sctp_calculate_rto(stcb,
- asoc, tp1->whoTo,
- &tp1->sent_rcv_time,
- SCTP_RTT_FROM_DATA);
+ if (rto_ok &&
+ sctp_calculate_rto(stcb,
+ &stcb->asoc,
+ tp1->whoTo,
+ &tp1->sent_rcv_time,
+ SCTP_RTT_FROM_DATA)) {
rto_ok = 0;
}
if (tp1->whoTo->rto_needed == 0) {
diff --git a/freebsd/sys/netinet/sctp_input.c b/freebsd/sys/netinet/sctp_input.c
index 3f4e2f5f..4191d24c 100644
--- a/freebsd/sys/netinet/sctp_input.c
+++ b/freebsd/sys/netinet/sctp_input.c
@@ -467,6 +467,10 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
if (!cookie_found) {
uint16_t len;
+ /* Only report the missing cookie parameter */
+ if (op_err != NULL) {
+ sctp_m_freem(op_err);
+ }
len = (uint16_t)(sizeof(struct sctp_error_missing_param) + sizeof(uint16_t));
/* We abort with an error of missing mandatory param */
op_err = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
@@ -550,7 +554,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
asoc->primary_destination, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
/* calculate the RTO */
- net->RTO = sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered,
+ sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered,
SCTP_RTT_FROM_NON_DATA);
retval = sctp_send_cookie_echo(m, offset, initack_limit, stcb, net);
return (retval);
@@ -650,7 +654,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
tv.tv_sec = cp->heartbeat.hb_info.time_value_1;
tv.tv_usec = cp->heartbeat.hb_info.time_value_2;
/* Now lets do a RTO with this */
- r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv,
+ sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv,
SCTP_RTT_FROM_NON_DATA);
if (!(r_net->dest_state & SCTP_ADDR_REACHABLE)) {
r_net->dest_state |= SCTP_ADDR_REACHABLE;
@@ -705,34 +709,37 @@ static int
sctp_handle_nat_colliding_state(struct sctp_tcb *stcb)
{
/*
- * return 0 means we want you to proceed with the abort non-zero
- * means no abort processing
+ * Return 0 means we want you to proceed with the abort non-zero
+ * means no abort processing.
*/
+ uint32_t new_vtag;
struct sctpasochead *head;
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
(SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
+ new_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_INP_INFO_WLOCK();
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ } else {
+ return (0);
}
if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) {
/* generate a new vtag and send init */
LIST_REMOVE(stcb, sctp_asocs);
- stcb->asoc.my_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
+ stcb->asoc.my_vtag = new_vtag;
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))];
/*
* put it in the bucket in the vtag hash of assoc's for the
* system
*/
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
- sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
SCTP_INP_INFO_WUNLOCK();
+ sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
return (1);
- }
- if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) {
+ } else {
/*
* treat like a case where the cookie expired i.e.: - dump
* current cookie. - generate a new vtag. - resend init.
@@ -742,15 +749,15 @@ sctp_handle_nat_colliding_state(struct sctp_tcb *stcb)
SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
sctp_stop_all_cookie_timers(stcb);
sctp_toss_old_cookies(stcb, &stcb->asoc);
- stcb->asoc.my_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
+ stcb->asoc.my_vtag = new_vtag;
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))];
/*
* put it in the bucket in the vtag hash of assoc's for the
* system
*/
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
- sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
SCTP_INP_INFO_WUNLOCK();
+ sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
return (1);
}
return (0);
@@ -1676,8 +1683,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
old.tv_sec = cookie->time_entered.tv_sec;
old.tv_usec = cookie->time_entered.tv_usec;
net->hb_responded = 1;
- net->RTO = sctp_calculate_rto(stcb, asoc, net,
- &old,
+ sctp_calculate_rto(stcb, asoc, net, &old,
SCTP_RTT_FROM_NON_DATA);
if (stcb->asoc.sctp_autoclose_ticks &&
@@ -2401,8 +2407,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
/* calculate the RTT and set the encaps port */
old.tv_sec = cookie->time_entered.tv_sec;
old.tv_usec = cookie->time_entered.tv_usec;
- (*netp)->RTO = sctp_calculate_rto(stcb, asoc, *netp,
- &old, SCTP_RTT_FROM_NON_DATA);
+ sctp_calculate_rto(stcb, asoc, *netp, &old, SCTP_RTT_FROM_NON_DATA);
}
/* respond with a COOKIE-ACK */
sctp_send_cookie_ack(stcb);
@@ -2978,8 +2983,7 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED,
SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
SCTP_STAT_INCR_GAUGE32(sctps_currestab);
if (asoc->overall_error_count == 0) {
- net->RTO = sctp_calculate_rto(stcb, asoc, net,
- &asoc->time_entered,
+ sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered,
SCTP_RTT_FROM_NON_DATA);
}
(void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered);
diff --git a/freebsd/sys/netinet/sctp_os_bsd.h b/freebsd/sys/netinet/sctp_os_bsd.h
index abe8e2c9..3db2d5e2 100644
--- a/freebsd/sys/netinet/sctp_os_bsd.h
+++ b/freebsd/sys/netinet/sctp_os_bsd.h
@@ -97,9 +97,6 @@ __FBSDID("$FreeBSD$");
#include <crypto/sha1.h>
#include <crypto/sha2/sha256.h>
-#ifndef in6pcb
-#define in6pcb inpcb
-#endif
/* Declare all the malloc names for all the various mallocs */
MALLOC_DECLARE(SCTP_M_MAP);
MALLOC_DECLARE(SCTP_M_STRMI);
@@ -368,7 +365,7 @@ typedef struct callout sctp_os_timer_t;
*/
/* get the v6 hop limit */
-#define SCTP_GET_HLIM(inp, ro) in6_selecthlim((struct in6pcb *)&inp->ip_inp.inp, (ro ? (ro->ro_rt ? (ro->ro_rt->rt_ifp) : (NULL)) : (NULL)));
+#define SCTP_GET_HLIM(inp, ro) in6_selecthlim((struct inpcb *)&inp->ip_inp.inp, (ro ? (ro->ro_rt ? (ro->ro_rt->rt_ifp) : (NULL)) : (NULL)));
/* is the endpoint v6only? */
#define SCTP_IPV6_V6ONLY(inp) (((struct inpcb *)inp)->inp_flags & IN6P_IPV6_V6ONLY)
@@ -431,7 +428,7 @@ typedef struct rtentry sctp_rtentry_t;
m_clrprotoflags(o_pak); \
if (local_stcb && local_stcb->sctp_ep) \
result = ip6_output(o_pak, \
- ((struct in6pcb *)(local_stcb->sctp_ep))->in6p_outputopts, \
+ ((struct inpcb *)(local_stcb->sctp_ep))->in6p_outputopts, \
(ro), 0, 0, ifp, NULL); \
else \
result = ip6_output(o_pak, NULL, (ro), 0, 0, ifp, NULL); \
diff --git a/freebsd/sys/netinet/sctp_output.c b/freebsd/sys/netinet/sctp_output.c
index 9221080d..522825da 100644
--- a/freebsd/sys/netinet/sctp_output.c
+++ b/freebsd/sys/netinet/sctp_output.c
@@ -4338,7 +4338,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* at the SCTP layer. So use the value from
* the IP layer.
*/
- flowlabel = ntohl(((struct in6pcb *)inp)->in6p_flowinfo);
+ flowlabel = ntohl(((struct inpcb *)inp)->inp_flow);
}
flowlabel &= 0x000fffff;
len = SCTP_MIN_OVERHEAD;
@@ -4393,7 +4393,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* at the SCTP layer. So use the value from
* the IP layer.
*/
- tos_value = (ntohl(((struct in6pcb *)inp)->in6p_flowinfo) >> 20) & 0xff;
+ tos_value = (ntohl(((struct inpcb *)inp)->inp_flow) >> 20) & 0xff;
}
tos_value &= 0xfc;
if (ecn_ok) {
@@ -7874,8 +7874,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int bundle_at, ctl_cnt, no_data_chunks, eeor_mode;
unsigned int mtu, r_mtu, omtu, mx_mtu, to_out;
int tsns_sent = 0;
- uint32_t auth_offset = 0;
- struct sctp_auth_chunk *auth = NULL;
+ uint32_t auth_offset;
+ struct sctp_auth_chunk *auth;
uint16_t auth_keyid;
int override_ok = 1;
int skip_fill_up = 0;
@@ -8070,6 +8070,8 @@ again_one_more_time:
}
bundle_at = 0;
endoutchain = outchain = NULL;
+ auth = NULL;
+ auth_offset = 0;
no_fragmentflg = 1;
one_chunk = 0;
if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
@@ -9061,8 +9063,7 @@ sctp_send_cookie_echo(struct mbuf *m,
pad = 4 - pad;
}
if (pad > 0) {
- cookie = sctp_pad_lastmbuf(cookie, pad, NULL);
- if (cookie == NULL) {
+ if (sctp_pad_lastmbuf(cookie, pad, NULL) == NULL) {
return (-8);
}
}
diff --git a/freebsd/sys/netinet/sctp_pcb.c b/freebsd/sys/netinet/sctp_pcb.c
index 10e4768e..c72cb5a9 100644
--- a/freebsd/sys/netinet/sctp_pcb.c
+++ b/freebsd/sys/netinet/sctp_pcb.c
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_output.h>
#include <netinet/sctp_timer.h>
#include <netinet/sctp_bsd_addr.h>
-#include <netinet/sctp_dtrace_define.h>
#if defined(INET) || defined(INET6)
#include <netinet/udp.h>
#endif
@@ -3647,12 +3646,8 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
#ifdef INET6
- if (ip_pcb->inp_vflag & INP_IPV6) {
- struct in6pcb *in6p;
-
- in6p = (struct in6pcb *)inp;
- ip6_freepcbopts(in6p->in6p_outputopts);
- }
+ if (ip_pcb->inp_vflag & INP_IPV6)
+ ip6_freepcbopts(((struct inpcb *)inp)->in6p_outputopts);
#endif /* INET6 */
ip_pcb->inp_vflag = 0;
/* free up authentication fields */
diff --git a/freebsd/sys/netinet/sctp_pcb.h b/freebsd/sys/netinet/sctp_pcb.h
index 0f5aca88..cbe51c7d 100644
--- a/freebsd/sys/netinet/sctp_pcb.h
+++ b/freebsd/sys/netinet/sctp_pcb.h
@@ -362,7 +362,7 @@ struct sctp_inpcb {
*/
union {
struct inpcb inp;
- char align[(sizeof(struct in6pcb) + SCTP_ALIGNM1) &
+ char align[(sizeof(struct inpcb) + SCTP_ALIGNM1) &
~SCTP_ALIGNM1];
} ip_inp;
diff --git a/freebsd/sys/netinet/sctp_usrreq.c b/freebsd/sys/netinet/sctp_usrreq.c
index 01759156..0783462a 100644
--- a/freebsd/sys/netinet/sctp_usrreq.c
+++ b/freebsd/sys/netinet/sctp_usrreq.c
@@ -1414,10 +1414,8 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
(num_v4 > 0)) {
- struct in6pcb *inp6;
- inp6 = (struct in6pcb *)inp;
- if (SCTP_IPV6_V6ONLY(inp6)) {
+ if (SCTP_IPV6_V6ONLY(inp)) {
/*
* if IPV6_V6ONLY flag, ignore connections destined
* to a v4 addr or v4-mapped addr
@@ -6918,14 +6916,14 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
#ifdef INET6
case AF_INET6:
{
- struct sockaddr_in6 *sin6p;
+ struct sockaddr_in6 *sin6;
if (addr->sa_len != sizeof(struct sockaddr_in6)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (EINVAL);
}
- sin6p = (struct sockaddr_in6 *)addr;
- if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) {
+ sin6 = (struct sockaddr_in6 *)addr;
+ if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6->sin6_addr)) != 0) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
return (error);
}
diff --git a/freebsd/sys/netinet/sctputil.c b/freebsd/sys/netinet/sctputil.c
index c7d4499c..6ae999b0 100644
--- a/freebsd/sys/netinet/sctputil.c
+++ b/freebsd/sys/netinet/sctputil.c
@@ -2471,25 +2471,24 @@ sctp_mtu_size_reset(struct sctp_inpcb *inp,
/*
- * given an association and starting time of the current RTT period return
- * RTO in number of msecs net should point to the current network
+ * Given an association and starting time of the current RTT period, update
+ * RTO in number of msecs. net should point to the current network.
+ * Return 1, if an RTO update was performed, return 0 if no update was
+ * performed due to invalid starting point.
*/
-uint32_t
+int
sctp_calculate_rto(struct sctp_tcb *stcb,
struct sctp_association *asoc,
struct sctp_nets *net,
struct timeval *old,
int rtt_from_sack)
{
- /*-
- * given an association and the starting time of the current RTT
- * period (in value1/value2) return RTO in number of msecs.
- */
+ struct timeval now;
+ uint64_t rtt_us; /* RTT in us */
int32_t rtt; /* RTT in ms */
uint32_t new_rto;
int first_measure = 0;
- struct timeval now;
/************************/
/* 1. calculate new RTT */
@@ -2500,10 +2499,19 @@ sctp_calculate_rto(struct sctp_tcb *stcb,
} else {
(void)SCTP_GETTIME_TIMEVAL(&now);
}
+ if ((old->tv_sec > now.tv_sec) ||
+ ((old->tv_sec == now.tv_sec) && (old->tv_sec > now.tv_sec))) {
+ /* The starting point is in the future. */
+ return (0);
+ }
timevalsub(&now, old);
+ rtt_us = (uint64_t)1000000 * (uint64_t)now.tv_sec + (uint64_t)now.tv_usec;
+ if (rtt_us > SCTP_RTO_UPPER_BOUND * 1000) {
+ /* The RTT is larger than a sane value. */
+ return (0);
+ }
/* store the current RTT in us */
- net->rtt = (uint64_t)1000000 * (uint64_t)now.tv_sec +
- (uint64_t)now.tv_usec;
+ net->rtt = rtt_us;
/* compute rtt in ms */
rtt = (int32_t)(net->rtt / 1000);
if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) {
@@ -2535,7 +2543,7 @@ sctp_calculate_rto(struct sctp_tcb *stcb,
* Paper "Congestion Avoidance and Control", Annex A.
*
* (net->lastsa >> SCTP_RTT_SHIFT) is the srtt
- * (net->lastsa >> SCTP_RTT_VAR_SHIFT) is the rttvar
+ * (net->lastsv >> SCTP_RTT_VAR_SHIFT) is the rttvar
*/
if (net->RTO_measured) {
rtt -= (net->lastsa >> SCTP_RTT_SHIFT);
@@ -2576,8 +2584,8 @@ sctp_calculate_rto(struct sctp_tcb *stcb,
if (new_rto > stcb->asoc.maxrto) {
new_rto = stcb->asoc.maxrto;
}
- /* we are now returning the RTO */
- return (new_rto);
+ net->RTO = new_rto;
+ return (1);
}
/*
diff --git a/freebsd/sys/netinet/sctputil.h b/freebsd/sys/netinet/sctputil.h
index 690e6125..c67c021f 100644
--- a/freebsd/sys/netinet/sctputil.h
+++ b/freebsd/sys/netinet/sctputil.h
@@ -133,7 +133,7 @@ uint32_t sctp_get_next_mtu(uint32_t);
void
sctp_timeout_handler(void *);
-uint32_t
+int
sctp_calculate_rto(struct sctp_tcb *, struct sctp_association *,
struct sctp_nets *, struct timeval *, int);
diff --git a/freebsd/sys/netinet/tcp_input.c b/freebsd/sys/netinet/tcp_input.c
index 05891306..fc111d9c 100644
--- a/freebsd/sys/netinet/tcp_input.c
+++ b/freebsd/sys/netinet/tcp_input.c
@@ -131,9 +131,9 @@ __FBSDID("$FreeBSD$");
const int tcprexmtthresh = 3;
-int tcp_log_in_vain = 0;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, log_in_vain, CTLFLAG_RW,
- &tcp_log_in_vain, 0,
+VNET_DEFINE(int, tcp_log_in_vain) = 0;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, log_in_vain, CTLFLAG_VNET | CTLFLAG_RW,
+ &VNET_NAME(tcp_log_in_vain), 0,
"Log all incoming TCP segments to closed ports");
VNET_DEFINE(int, blackhole) = 0;
@@ -536,11 +536,19 @@ cc_ecnpkt_handler(struct tcpcb *tp, struct tcphdr *th, uint8_t iptos)
int
tcp6_input(struct mbuf **mp, int *offp, int proto)
{
- struct mbuf *m = *mp;
+ struct mbuf *m;
struct in6_ifaddr *ia6;
struct ip6_hdr *ip6;
- IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE);
+ m = *mp;
+ if (m->m_len < *offp + sizeof(struct tcphdr)) {
+ m = m_pullup(m, *offp + sizeof(struct tcphdr));
+ if (m == NULL) {
+ *mp = m;
+ TCPSTAT_INC(tcps_rcvshort);
+ return (IPPROTO_DONE);
+ }
+ }
/*
* draft-itojun-ipv6-tcp-to-anycast
@@ -549,17 +557,17 @@ tcp6_input(struct mbuf **mp, int *offp, int proto)
ip6 = mtod(m, struct ip6_hdr *);
ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) {
- struct ip6_hdr *ip6;
ifa_free(&ia6->ia_ifa);
- ip6 = mtod(m, struct ip6_hdr *);
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR,
(caddr_t)&ip6->ip6_dst - (caddr_t)ip6);
+ *mp = NULL;
return (IPPROTO_DONE);
}
if (ia6)
ifa_free(&ia6->ia_ifa);
+ *mp = m;
return (tcp_input(mp, offp, proto));
}
#endif /* INET6 */
@@ -618,15 +626,6 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
#ifdef INET6
if (isipv6) {
- /* IP6_EXTHDR_CHECK() is already done at tcp6_input(). */
-
- if (m->m_len < (sizeof(*ip6) + sizeof(*th))) {
- m = m_pullup(m, sizeof(*ip6) + sizeof(*th));
- if (m == NULL) {
- TCPSTAT_INC(tcps_rcvshort);
- return (IPPROTO_DONE);
- }
- }
ip6 = mtod(m, struct ip6_hdr *);
th = (struct tcphdr *)((caddr_t)ip6 + off0);
@@ -735,7 +734,13 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
if (off > sizeof (struct tcphdr)) {
#ifdef INET6
if (isipv6) {
- IP6_EXTHDR_CHECK(m, off0, off, IPPROTO_DONE);
+ if (m->m_len < off0 + off) {
+ m = m_pullup(m, off0 + off);
+ if (m == NULL) {
+ TCPSTAT_INC(tcps_rcvshort);
+ return (IPPROTO_DONE);
+ }
+ }
ip6 = mtod(m, struct ip6_hdr *);
th = (struct tcphdr *)((caddr_t)ip6 + off0);
}
@@ -883,8 +888,8 @@ findpcb:
* Log communication attempts to ports that are not
* in use.
*/
- if ((tcp_log_in_vain == 1 && (thflags & TH_SYN)) ||
- tcp_log_in_vain == 2) {
+ if ((V_tcp_log_in_vain == 1 && (thflags & TH_SYN)) ||
+ V_tcp_log_in_vain == 2) {
if ((s = tcp_log_vain(NULL, th, (void *)ip, ip6)))
log(LOG_INFO, "%s; %s: Connection attempt "
"to closed port\n", s, __func__);
diff --git a/freebsd/sys/netinet/tcp_output.c b/freebsd/sys/netinet/tcp_output.c
index 3e024fdb..dc75c68d 100644
--- a/freebsd/sys/netinet/tcp_output.c
+++ b/freebsd/sys/netinet/tcp_output.c
@@ -933,6 +933,20 @@ send:
if (tp->t_flags & TF_NEEDFIN)
sendalot = 1;
} else {
+ if (optlen + ipoptlen >= tp->t_maxseg) {
+ /*
+ * Since we don't have enough space to put
+ * the IP header chain and the TCP header in
+ * one packet as required by RFC 7112, don't
+ * send it. Also ensure that at least one
+ * byte of the payload can be put into the
+ * TCP segment.
+ */
+ SOCKBUF_UNLOCK(&so->so_snd);
+ error = EMSGSIZE;
+ sack_rxmit = 0;
+ goto out;
+ }
len = tp->t_maxseg - optlen - ipoptlen;
sendalot = 1;
if (dont_sendalot)
diff --git a/freebsd/sys/netinet/tcp_subr.c b/freebsd/sys/netinet/tcp_subr.c
index 44ec38c7..eae696c1 100644
--- a/freebsd/sys/netinet/tcp_subr.c
+++ b/freebsd/sys/netinet/tcp_subr.c
@@ -3114,7 +3114,7 @@ tcp_log_vain(struct in_conninfo *inc, struct tcphdr *th, void *ip4hdr,
{
/* Is logging enabled? */
- if (tcp_log_in_vain == 0)
+ if (V_tcp_log_in_vain == 0)
return (NULL);
return (tcp_log_addr(inc, th, ip4hdr, ip6hdr));
diff --git a/freebsd/sys/netinet/tcp_timer.c b/freebsd/sys/netinet/tcp_timer.c
index cf6ceff5..e1b9ec59 100644
--- a/freebsd/sys/netinet/tcp_timer.c
+++ b/freebsd/sys/netinet/tcp_timer.c
@@ -127,9 +127,10 @@ SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_slop, CTLTYPE_INT|CTLFLAG_RW,
&tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I",
"Retransmission Timer Slop");
-int tcp_always_keepalive = 1;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW,
- &tcp_always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections");
+VNET_DEFINE(int, tcp_always_keepalive) = 1;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_VNET|CTLFLAG_RW,
+ &VNET_NAME(tcp_always_keepalive) , 0,
+ "Assume SO_KEEPALIVE on all TCP connections");
int tcp_fast_finwait2_recycle = 0;
SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW,
@@ -433,7 +434,7 @@ tcp_timer_keep(void *xtp)
TCPSTAT_INC(tcps_keeptimeo);
if (tp->t_state < TCPS_ESTABLISHED)
goto dropit;
- if ((tcp_always_keepalive ||
+ if ((V_tcp_always_keepalive ||
inp->inp_socket->so_options & SO_KEEPALIVE) &&
tp->t_state <= TCPS_CLOSING) {
if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp))
diff --git a/freebsd/sys/netinet/tcp_timer.h b/freebsd/sys/netinet/tcp_timer.h
index 3e985bdf..fe3616c2 100644
--- a/freebsd/sys/netinet/tcp_timer.h
+++ b/freebsd/sys/netinet/tcp_timer.h
@@ -203,10 +203,11 @@ extern int tcp_backoff[];
extern int tcp_totbackoff;
extern int tcp_rexmit_drop_options;
-extern int tcp_always_keepalive;
extern int tcp_finwait2_timeout;
extern int tcp_fast_finwait2_recycle;
+VNET_DECLARE(int, tcp_always_keepalive);
+#define V_tcp_always_keepalive VNET(tcp_always_keepalive)
VNET_DECLARE(int, tcp_pmtud_blackhole_detect);
#define V_tcp_pmtud_blackhole_detect VNET(tcp_pmtud_blackhole_detect)
VNET_DECLARE(int, tcp_pmtud_blackhole_mss);
diff --git a/freebsd/sys/netinet/tcp_usrreq.c b/freebsd/sys/netinet/tcp_usrreq.c
index 809ea35d..eab13eeb 100644
--- a/freebsd/sys/netinet/tcp_usrreq.c
+++ b/freebsd/sys/netinet/tcp_usrreq.c
@@ -346,23 +346,25 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
int error = 0;
struct inpcb *inp;
struct tcpcb *tp = NULL;
- struct sockaddr_in6 *sin6p;
+ struct sockaddr_in6 *sin6;
+ u_char vflagsav;
- sin6p = (struct sockaddr_in6 *)nam;
- if (nam->sa_len != sizeof (*sin6p))
+ sin6 = (struct sockaddr_in6 *)nam;
+ if (nam->sa_len != sizeof (*sin6))
return (EINVAL);
/*
* Must check for multicast addresses and disallow binding
* to them.
*/
- if (sin6p->sin6_family == AF_INET6 &&
- IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
+ if (sin6->sin6_family == AF_INET6 &&
+ IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
return (EAFNOSUPPORT);
TCPDEBUG0;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("tcp6_usr_bind: inp == NULL"));
INP_WLOCK(inp);
+ vflagsav = inp->inp_vflag;
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
error = EINVAL;
goto out;
@@ -374,12 +376,12 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
inp->inp_vflag |= INP_IPV6;
#ifdef INET
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
- if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr))
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
inp->inp_vflag |= INP_IPV4;
- else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
+ else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
- in6_sin6_2_sin(&sin, sin6p);
+ in6_sin6_2_sin(&sin, sin6);
if (IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) {
error = EAFNOSUPPORT;
INP_HASH_WUNLOCK(&V_tcbinfo);
@@ -397,6 +399,8 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
error = in6_pcbbind(inp, nam, td->td_ucred);
INP_HASH_WUNLOCK(&V_tcbinfo);
out:
+ if (error != 0)
+ inp->inp_vflag = vflagsav;
TCPDEBUG2(PRU_BIND);
TCP_PROBE2(debug__user, tp, PRU_BIND);
INP_WUNLOCK(inp);
@@ -459,6 +463,7 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
int error = 0;
struct inpcb *inp;
struct tcpcb *tp = NULL;
+ u_char vflagsav;
TCPDEBUG0;
inp = sotoinpcb(so);
@@ -468,6 +473,7 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
error = EINVAL;
goto out;
}
+ vflagsav = inp->inp_vflag;
tp = intotcpcb(inp);
TCPDEBUG1();
SOCK_LOCK(so);
@@ -493,6 +499,9 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
if (IS_FASTOPEN(tp->t_flags))
tp->t_tfo_pending = tcp_fastopen_alloc_counter();
+ if (error != 0)
+ inp->inp_vflag = vflagsav;
+
out:
TCPDEBUG2(PRU_LISTEN);
TCP_PROBE2(debug__user, tp, PRU_LISTEN);
@@ -568,23 +577,27 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
int error = 0;
struct inpcb *inp;
struct tcpcb *tp = NULL;
- struct sockaddr_in6 *sin6p;
+ struct sockaddr_in6 *sin6;
+ u_int8_t incflagsav;
+ u_char vflagsav;
TCPDEBUG0;
- sin6p = (struct sockaddr_in6 *)nam;
- if (nam->sa_len != sizeof (*sin6p))
+ sin6 = (struct sockaddr_in6 *)nam;
+ if (nam->sa_len != sizeof (*sin6))
return (EINVAL);
/*
* Must disallow TCP ``connections'' to multicast addresses.
*/
- if (sin6p->sin6_family == AF_INET6
- && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
+ if (sin6->sin6_family == AF_INET6
+ && IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
return (EAFNOSUPPORT);
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("tcp6_usr_connect: inp == NULL"));
INP_WLOCK(inp);
+ vflagsav = inp->inp_vflag;
+ incflagsav = inp->inp_inc.inc_flags;
if (inp->inp_flags & INP_TIMEWAIT) {
error = EADDRINUSE;
goto out;
@@ -601,7 +614,7 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
* therefore probably require the hash lock, which isn't held here.
* Is this a significant problem?
*/
- if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) {
@@ -613,16 +626,16 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
goto out;
}
- in6_sin6_2_sin(&sin, sin6p);
+ in6_sin6_2_sin(&sin, sin6);
if (IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) {
error = EAFNOSUPPORT;
goto out;
}
- inp->inp_vflag |= INP_IPV4;
- inp->inp_vflag &= ~INP_IPV6;
if ((error = prison_remote_ip4(td->td_ucred,
&sin.sin_addr)) != 0)
goto out;
+ inp->inp_vflag |= INP_IPV4;
+ inp->inp_vflag &= ~INP_IPV6;
if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0)
goto out;
#ifdef TCP_OFFLOAD
@@ -640,11 +653,11 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
}
}
#endif
+ if ((error = prison_remote_ip6(td->td_ucred, &sin6->sin6_addr)) != 0)
+ goto out;
inp->inp_vflag &= ~INP_IPV4;
inp->inp_vflag |= INP_IPV6;
inp->inp_inc.inc_flags |= INC_ISIPV6;
- if ((error = prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr)) != 0)
- goto out;
if ((error = tcp6_connect(tp, nam, td)) != 0)
goto out;
#ifdef TCP_OFFLOAD
@@ -657,6 +670,15 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
error = tp->t_fb->tfb_tcp_output(tp);
out:
+ /*
+ * If the implicit bind in the connect call fails, restore
+ * the flags we modified.
+ */
+ if (error != 0 && inp->inp_lport == 0) {
+ inp->inp_vflag = vflagsav;
+ inp->inp_inc.inc_flags = incflagsav;
+ }
+
TCPDEBUG2(PRU_CONNECT);
TCP_PROBE2(debug__user, tp, PRU_CONNECT);
INP_WUNLOCK(inp);
@@ -912,6 +934,9 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
#ifdef INET6
int isipv6;
#endif
+ u_int8_t incflagsav;
+ u_char vflagsav;
+ bool restoreflags;
TCPDEBUG0;
/*
@@ -923,6 +948,9 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL"));
INP_WLOCK(inp);
+ vflagsav = inp->inp_vflag;
+ incflagsav = inp->inp_inc.inc_flags;
+ restoreflags = false;
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
if (control)
m_freem(control);
@@ -974,22 +1002,22 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
#ifdef INET6
case AF_INET6:
{
- struct sockaddr_in6 *sin6p;
+ struct sockaddr_in6 *sin6;
- sin6p = (struct sockaddr_in6 *)nam;
- if (sin6p->sin6_len != sizeof(struct sockaddr_in6)) {
+ sin6 = (struct sockaddr_in6 *)nam;
+ if (sin6->sin6_len != sizeof(*sin6)) {
if (m)
m_freem(m);
error = EINVAL;
goto out;
}
- if (IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
+ if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
if (m)
m_freem(m);
error = EAFNOSUPPORT;
goto out;
}
- if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
#ifdef INET
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) {
error = EINVAL;
@@ -1003,9 +1031,10 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
m_freem(m);
goto out;
}
+ restoreflags = true;
inp->inp_vflag &= ~INP_IPV6;
sinp = &sin;
- in6_sin6_2_sin(sinp, sin6p);
+ in6_sin6_2_sin(sinp, sin6);
if (IN_MULTICAST(
ntohl(sinp->sin_addr.s_addr))) {
error = EAFNOSUPPORT;
@@ -1033,10 +1062,11 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
error = EAFNOSUPPORT;
goto out;
}
+ restoreflags = true;
inp->inp_vflag &= ~INP_IPV4;
inp->inp_inc.inc_flags |= INC_ISIPV6;
if ((error = prison_remote_ip6(td->td_ucred,
- &sin6p->sin6_addr))) {
+ &sin6->sin6_addr))) {
if (m)
m_freem(m);
goto out;
@@ -1083,6 +1113,14 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
error = tcp_connect(tp,
(struct sockaddr *)sinp, td);
#endif
+ /*
+ * The bind operation in tcp_connect succeeded. We
+ * no longer want to restore the flags if later
+ * operations fail.
+ */
+ if (error == 0 || inp->inp_lport != 0)
+ restoreflags = false;
+
if (error)
goto out;
if (IS_FASTOPEN(tp->t_flags))
@@ -1153,6 +1191,14 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
error = tcp_connect(tp,
(struct sockaddr *)sinp, td);
#endif
+ /*
+ * The bind operation in tcp_connect succeeded. We
+ * no longer want to restore the flags if later
+ * operations fail.
+ */
+ if (error == 0 || inp->inp_lport != 0)
+ restoreflags = false;
+
if (error)
goto out;
tp->snd_wnd = TTCP_CLIENT_SND_WND;
@@ -1171,6 +1217,14 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
TCP_LOG_USERSEND, error,
0, NULL, false);
out:
+ /*
+ * If the request was unsuccessful and we changed flags,
+ * restore the original flags.
+ */
+ if (error != 0 && restoreflags) {
+ inp->inp_vflag = vflagsav;
+ inp->inp_inc.inc_flags = incflagsav;
+ }
TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB :
((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
TCP_PROBE2(debug__user, tp, (flags & PRUS_OOB) ? PRU_SENDOOB :
diff --git a/freebsd/sys/netinet/tcp_var.h b/freebsd/sys/netinet/tcp_var.h
index cca8623e..13d20294 100644
--- a/freebsd/sys/netinet/tcp_var.h
+++ b/freebsd/sys/netinet/tcp_var.h
@@ -745,7 +745,8 @@ SYSCTL_DECL(_net_inet_tcp_sack);
MALLOC_DECLARE(M_TCPLOG);
#endif
-extern int tcp_log_in_vain;
+VNET_DECLARE(int, tcp_log_in_vain);
+#define V_tcp_log_in_vain VNET(tcp_log_in_vain)
/*
* Global TCP tunables shared between different stacks.
diff --git a/freebsd/sys/netinet/udp_usrreq.c b/freebsd/sys/netinet/udp_usrreq.c
index f89660d6..8462d0ee 100644
--- a/freebsd/sys/netinet/udp_usrreq.c
+++ b/freebsd/sys/netinet/udp_usrreq.c
@@ -122,9 +122,9 @@ VNET_DEFINE(int, udp_cksum) = 1;
SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_VNET | CTLFLAG_RW,
&VNET_NAME(udp_cksum), 0, "compute udp checksum");
-int udp_log_in_vain = 0;
-SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW,
- &udp_log_in_vain, 0, "Log all incoming UDP packets");
+VNET_DEFINE(int, udp_log_in_vain) = 0;
+SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_VNET | CTLFLAG_RW,
+ &VNET_NAME(udp_log_in_vain), 0, "Log all incoming UDP packets");
VNET_DEFINE(int, udp_blackhole) = 0;
SYSCTL_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_VNET | CTLFLAG_RW,
@@ -427,14 +427,13 @@ udp_input(struct mbuf **mp, int *offp, int proto)
/*
* Get IP and UDP header together in first mbuf.
*/
- ip = mtod(m, struct ip *);
if (m->m_len < iphlen + sizeof(struct udphdr)) {
if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == NULL) {
UDPSTAT_INC(udps_hdrops);
return (IPPROTO_DONE);
}
- ip = mtod(m, struct ip *);
}
+ ip = mtod(m, struct ip *);
uh = (struct udphdr *)((caddr_t)ip + iphlen);
cscov_partial = (proto == IPPROTO_UDPLITE) ? 1 : 0;
@@ -695,7 +694,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD |
INPLOOKUP_RLOCKPCB, ifp, m);
if (inp == NULL) {
- if (udp_log_in_vain) {
+ if (V_udp_log_in_vain) {
char src[INET_ADDRSTRLEN];
char dst[INET_ADDRSTRLEN];
diff --git a/freebsd/sys/netinet/udp_var.h b/freebsd/sys/netinet/udp_var.h
index 01545582..ecca2a54 100644
--- a/freebsd/sys/netinet/udp_var.h
+++ b/freebsd/sys/netinet/udp_var.h
@@ -153,9 +153,10 @@ extern u_long udp_sendspace;
extern u_long udp_recvspace;
VNET_DECLARE(int, udp_cksum);
VNET_DECLARE(int, udp_blackhole);
+VNET_DECLARE(int, udp_log_in_vain);
#define V_udp_cksum VNET(udp_cksum)
#define V_udp_blackhole VNET(udp_blackhole)
-extern int udp_log_in_vain;
+#define V_udp_log_in_vain VNET(udp_log_in_vain)
static __inline struct inpcbinfo *
udp_get_inpcbinfo(int protocol)