summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2015-04-08 15:37:49 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-05-20 09:58:21 +0200
commit165dd8ea1256d71d6a4f52c0a66dcc2799ef8f99 (patch)
treec42072a99573d4d7cc03b2263e2c0c6d53f9c691 /freebsd/sys/netinet
parentrtems-bsd-chunk: Include missing header file (diff)
downloadrtems-libbsd-165dd8ea1256d71d6a4f52c0a66dcc2799ef8f99.tar.bz2
Update to FreeBSD Stable/9 2015-04-08
Diffstat (limited to 'freebsd/sys/netinet')
-rw-r--r--freebsd/sys/netinet/cc/cc.c52
-rw-r--r--freebsd/sys/netinet/if_ether.c8
-rw-r--r--freebsd/sys/netinet/igmp.c9
-rw-r--r--freebsd/sys/netinet/in.c28
-rw-r--r--freebsd/sys/netinet/ip_output.c10
-rw-r--r--freebsd/sys/netinet/sctp_input.c44
-rw-r--r--freebsd/sys/netinet/sctp_output.c8
-rw-r--r--freebsd/sys/netinet/sctp_sysctl.c8
-rw-r--r--freebsd/sys/netinet/sctp_usrreq.c20
-rw-r--r--freebsd/sys/netinet/tcp_hostcache.c24
-rw-r--r--freebsd/sys/netinet/tcp_input.c19
-rw-r--r--freebsd/sys/netinet/tcp_output.c106
-rw-r--r--freebsd/sys/netinet/tcp_reass.c2
-rw-r--r--freebsd/sys/netinet/tcp_subr.c4
-rw-r--r--freebsd/sys/netinet/tcp_var.h6
15 files changed, 242 insertions, 106 deletions
diff --git a/freebsd/sys/netinet/cc/cc.c b/freebsd/sys/netinet/cc/cc.c
index 8aea8dd2..4be9a63b 100644
--- a/freebsd/sys/netinet/cc/cc.c
+++ b/freebsd/sys/netinet/cc/cc.c
@@ -94,33 +94,33 @@ cc_default_algo(SYSCTL_HANDLER_ARGS)
{
char default_cc[TCP_CA_NAME_MAX];
struct cc_algo *funcs;
- int err, found;
-
- err = found = 0;
-
- if (req->newptr == NULL) {
- /* Just print the current default. */
- CC_LIST_RLOCK();
- strlcpy(default_cc, CC_DEFAULT()->name, TCP_CA_NAME_MAX);
- CC_LIST_RUNLOCK();
- err = sysctl_handle_string(oidp, default_cc, 1, req);
- } else {
- /* Find algo with specified name and set it to default. */
- CC_LIST_RLOCK();
- STAILQ_FOREACH(funcs, &cc_list, entries) {
- if (strncmp((char *)req->newptr, funcs->name,
- TCP_CA_NAME_MAX) == 0) {
- found = 1;
- V_default_cc_ptr = funcs;
- }
- }
- CC_LIST_RUNLOCK();
+ int error;
- if (!found)
- err = ESRCH;
- }
+ /* Get the current default: */
+ CC_LIST_RLOCK();
+ strlcpy(default_cc, CC_DEFAULT()->name, sizeof(default_cc));
+ CC_LIST_RUNLOCK();
- return (err);
+ error = sysctl_handle_string(oidp, default_cc, sizeof(default_cc), req);
+
+ /* Check for error or no change */
+ if (error != 0 || req->newptr == NULL)
+ goto done;
+
+ error = ESRCH;
+
+ /* Find algo with specified name and set it to default. */
+ CC_LIST_RLOCK();
+ STAILQ_FOREACH(funcs, &cc_list, entries) {
+ if (strncmp(default_cc, funcs->name, sizeof(default_cc)))
+ continue;
+ V_default_cc_ptr = funcs;
+ error = 0;
+ break;
+ }
+ CC_LIST_RUNLOCK();
+done:
+ return (error);
}
#ifndef __rtems__
@@ -169,7 +169,7 @@ cc_list_available(SYSCTL_HANDLER_ARGS)
if (!err) {
sbuf_finish(s);
- err = sysctl_handle_string(oidp, sbuf_data(s), 1, req);
+ err = sysctl_handle_string(oidp, sbuf_data(s), 0, req);
}
sbuf_delete(s);
diff --git a/freebsd/sys/netinet/if_ether.c b/freebsd/sys/netinet/if_ether.c
index e4f76fee..eec06dd8 100644
--- a/freebsd/sys/netinet/if_ether.c
+++ b/freebsd/sys/netinet/if_ether.c
@@ -156,10 +156,10 @@ arp_ifscrub(struct ifnet *ifp, uint32_t addr)
addr4.sin_len = sizeof(addr4);
addr4.sin_family = AF_INET;
addr4.sin_addr.s_addr = addr;
- IF_AFDATA_RLOCK(ifp);
+ IF_AFDATA_WLOCK(ifp);
lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR),
(struct sockaddr *)&addr4);
- IF_AFDATA_RUNLOCK(ifp);
+ IF_AFDATA_WUNLOCK(ifp);
}
#endif
@@ -328,8 +328,8 @@ retry:
if (la == NULL) {
if (flags & LLE_CREATE)
log(LOG_DEBUG,
- "arpresolve: can't allocate llinfo for %s\n",
- inet_ntoa(SIN(dst)->sin_addr));
+ "arpresolve: can't allocate llinfo for %s on %s\n",
+ inet_ntoa(SIN(dst)->sin_addr), ifp->if_xname);
m_freem(m);
return (EINVAL);
}
diff --git a/freebsd/sys/netinet/igmp.c b/freebsd/sys/netinet/igmp.c
index 3056fa3a..78d9685b 100644
--- a/freebsd/sys/netinet/igmp.c
+++ b/freebsd/sys/netinet/igmp.c
@@ -1535,8 +1535,7 @@ igmp_input(struct mbuf *m, int off)
case IGMP_VERSION_3: {
struct igmpv3 *igmpv3;
uint16_t igmpv3len;
- uint16_t srclen;
- int nsrc;
+ uint16_t nsrc;
IGMPSTAT_INC(igps_rcv_v3_queries);
igmpv3 = (struct igmpv3 *)igmp;
@@ -1544,8 +1543,8 @@ igmp_input(struct mbuf *m, int off)
* Validate length based on source count.
*/
nsrc = ntohs(igmpv3->igmp_numsrc);
- srclen = sizeof(struct in_addr) * nsrc;
- if (nsrc * sizeof(in_addr_t) > srclen) {
+ if (nsrc * sizeof(in_addr_t) >
+ UINT16_MAX - iphlen - IGMP_V3_QUERY_MINLEN) {
IGMPSTAT_INC(igps_rcv_tooshort);
return;
}
@@ -1554,7 +1553,7 @@ igmp_input(struct mbuf *m, int off)
* this scope.
*/
igmpv3len = iphlen + IGMP_V3_QUERY_MINLEN +
- srclen;
+ sizeof(struct in_addr) * nsrc;
if ((m->m_flags & M_EXT ||
m->m_len < igmpv3len) &&
(m = m_pullup(m, igmpv3len)) == NULL) {
diff --git a/freebsd/sys/netinet/in.c b/freebsd/sys/netinet/in.c
index bc7323e3..653580c7 100644
--- a/freebsd/sys/netinet/in.c
+++ b/freebsd/sys/netinet/in.c
@@ -970,7 +970,7 @@ in_addprefix(struct in_ifaddr *target, int flags)
{
struct in_ifaddr *ia;
struct in_addr prefix, mask, p, m;
- int error, fibnum;
+ int error;
if ((flags & RTF_HOST) != 0) {
prefix = target->ia_dstaddr.sin_addr;
@@ -981,9 +981,8 @@ in_addprefix(struct in_ifaddr *target, int flags)
prefix.s_addr &= mask.s_addr;
}
- fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS : target->ia_ifp->if_fib;
-
IN_IFADDR_RLOCK();
+ /* Look for an existing address with the same prefix, mask, and fib */
TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
if (rtinitflags(ia)) {
p = ia->ia_dstaddr.sin_addr;
@@ -999,6 +998,8 @@ in_addprefix(struct in_ifaddr *target, int flags)
mask.s_addr != m.s_addr)
continue;
}
+ if (target->ia_ifp->if_fib != ia->ia_ifp->if_fib)
+ continue;
/*
* If we got a matching prefix route inserted by other
@@ -1019,6 +1020,10 @@ in_addprefix(struct in_ifaddr *target, int flags)
IN_IFADDR_RUNLOCK();
return (EEXIST);
} else {
+ int fibnum;
+
+ fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS :
+ target->ia_ifp->if_fib;
rt_addrmsg(RTM_ADD, &target->ia_ifa, fibnum);
IN_IFADDR_RUNLOCK();
return (0);
@@ -1048,11 +1053,9 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
{
struct in_ifaddr *ia;
struct in_addr prefix, mask, p;
- int error = 0, fibnum;
+ int error = 0;
struct sockaddr_in prefix0, mask0;
- fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS : target->ia_ifp->if_fib;
-
/*
* Remove the loopback route to the interface address.
* The "useloopback" setting is not consulted because if the
@@ -1068,10 +1071,12 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
(target->ia_flags & IFA_RTSELF)) {
struct route ia_ro;
int freeit = 0;
+ int fibnum;
bzero(&ia_ro, sizeof(ia_ro));
*((struct sockaddr_in *)(&ia_ro.ro_dst)) = target->ia_addr;
- rtalloc_ign_fib(&ia_ro, 0, 0);
+ fibnum = target->ia_ifp->if_fib;
+ rtalloc_ign_fib(&ia_ro, 0, fibnum);
if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) &&
(ia_ro.ro_rt->rt_ifp == V_loif)) {
RT_LOCK(ia_ro.ro_rt);
@@ -1104,6 +1109,10 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
}
if ((target->ia_flags & IFA_ROUTE) == 0) {
+ int fibnum;
+
+ fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS :
+ target->ia_ifp->if_fib;
rt_addrmsg(RTM_DELETE, &target->ia_ifa, fibnum);
return (0);
}
@@ -1368,8 +1377,9 @@ in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr
KASSERT(l3addr->sa_family == AF_INET,
("sin_family %d", l3addr->sa_family));
- /* XXX rtalloc1 should take a const param */
- rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
+ /* XXX rtalloc1_fib should take a const param */
+ rt = rtalloc1_fib(__DECONST(struct sockaddr *, l3addr), 0, 0,
+ ifp->if_fib);
if (rt == NULL)
return (EINVAL);
diff --git a/freebsd/sys/netinet/ip_output.c b/freebsd/sys/netinet/ip_output.c
index 93ebf4d6..a06fed68 100644
--- a/freebsd/sys/netinet/ip_output.c
+++ b/freebsd/sys/netinet/ip_output.c
@@ -743,10 +743,8 @@ ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu,
* be less than the receiver's page size ?
*/
int newlen;
- struct mbuf *m;
- for (m = m0, off = 0; m && (off+m->m_len) <= mtu; m = m->m_next)
- off += m->m_len;
+ off = MIN(mtu, m0->m_pkthdr.len);
/*
* firstlen (off - hlen) must be aligned on an
@@ -789,7 +787,11 @@ smart_frag_failure:
IPSTAT_INC(ips_odropped);
goto done;
}
- m->m_flags |= (m0->m_flags & M_MCAST) | M_FRAG;
+ /* copy multicast and flowid flag, if any */
+ m->m_flags |= (m0->m_flags & (M_FLOWID | M_MCAST)) | M_FRAG;
+ /* make sure the flowid is the same for the fragmented mbufs */
+ M_HASHTYPE_SET(m, M_HASHTYPE_GET(m0));
+ m->m_pkthdr.flowid = m0->m_pkthdr.flowid;
/*
* In the first mbuf, leave room for the link header, then
* copy the original IP header including options. The payload
diff --git a/freebsd/sys/netinet/sctp_input.c b/freebsd/sys/netinet/sctp_input.c
index baf25af8..9e35c882 100644
--- a/freebsd/sys/netinet/sctp_input.c
+++ b/freebsd/sys/netinet/sctp_input.c
@@ -3664,6 +3664,9 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
/* huh ? */
return (0);
}
+ if (ntohs(respin->ph.param_length) < sizeof(struct sctp_stream_reset_response_tsn)) {
+ return (0);
+ }
if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) {
resp = (struct sctp_stream_reset_response_tsn *)respin;
asoc->stream_reset_outstanding--;
@@ -4052,7 +4055,7 @@ __attribute__((noinline))
sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset,
struct sctp_chunkhdr *ch_req)
{
- int chk_length, param_len, ptype;
+ uint16_t remaining_length, param_len, ptype;
struct sctp_paramhdr pstore;
uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE];
uint32_t seq = 0;
@@ -4065,7 +4068,7 @@ __attribute__((noinline))
int num_param = 0;
/* now it may be a reset or a reset-response */
- chk_length = ntohs(ch_req->chunk_length);
+ remaining_length = ntohs(ch_req->chunk_length) - sizeof(struct sctp_chunkhdr);
/* setup for adding the response */
sctp_alloc_a_chunk(stcb, chk);
@@ -4101,20 +4104,27 @@ strres_nochunk:
ch->chunk_length = htons(chk->send_size);
SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size);
offset += sizeof(struct sctp_chunkhdr);
- while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) {
+ while (remaining_length >= sizeof(struct sctp_paramhdr)) {
ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(pstore), (uint8_t *) & pstore);
- if (ph == NULL)
+ if (ph == NULL) {
+ /* TSNH */
break;
+ }
param_len = ntohs(ph->param_length);
- if (param_len < (int)sizeof(struct sctp_stream_reset_tsn_request)) {
- /* bad param */
+ if ((param_len > remaining_length) ||
+ (param_len < (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)))) {
+ /* bad parameter length */
break;
}
- ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, (int)sizeof(cstore)),
+ ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, sizeof(cstore)),
(uint8_t *) & cstore);
+ if (ph == NULL) {
+ /* TSNH */
+ break;
+ }
ptype = ntohs(ph->param_type);
num_param++;
- if (param_len > (int)sizeof(cstore)) {
+ if (param_len > sizeof(cstore)) {
trunc = 1;
} else {
trunc = 0;
@@ -4126,6 +4136,9 @@ strres_nochunk:
if (ptype == SCTP_STR_RESET_OUT_REQUEST) {
struct sctp_stream_reset_out_request *req_out;
+ if (param_len < sizeof(struct sctp_stream_reset_out_request)) {
+ break;
+ }
req_out = (struct sctp_stream_reset_out_request *)ph;
num_req++;
if (stcb->asoc.stream_reset_outstanding) {
@@ -4139,12 +4152,18 @@ strres_nochunk:
} else if (ptype == SCTP_STR_RESET_ADD_OUT_STREAMS) {
struct sctp_stream_reset_add_strm *str_add;
+ if (param_len < sizeof(struct sctp_stream_reset_add_strm)) {
+ break;
+ }
str_add = (struct sctp_stream_reset_add_strm *)ph;
num_req++;
sctp_handle_str_reset_add_strm(stcb, chk, str_add);
} else if (ptype == SCTP_STR_RESET_ADD_IN_STREAMS) {
struct sctp_stream_reset_add_strm *str_add;
+ if (param_len < sizeof(struct sctp_stream_reset_add_strm)) {
+ break;
+ }
str_add = (struct sctp_stream_reset_add_strm *)ph;
num_req++;
sctp_handle_str_reset_add_out_strm(stcb, chk, str_add);
@@ -4169,6 +4188,9 @@ strres_nochunk:
struct sctp_stream_reset_response *resp;
uint32_t result;
+ if (param_len < sizeof(struct sctp_stream_reset_response)) {
+ break;
+ }
resp = (struct sctp_stream_reset_response *)ph;
seq = ntohl(resp->response_seq);
result = ntohl(resp->result);
@@ -4180,7 +4202,11 @@ strres_nochunk:
break;
}
offset += SCTP_SIZE32(param_len);
- chk_length -= SCTP_SIZE32(param_len);
+ if (remaining_length >= SCTP_SIZE32(param_len)) {
+ remaining_length -= SCTP_SIZE32(param_len);
+ } else {
+ remaining_length = 0;
+ }
}
if (num_req == 0) {
/* we have no response free the stuff */
diff --git a/freebsd/sys/netinet/sctp_output.c b/freebsd/sys/netinet/sctp_output.c
index f3cb4b44..cbc25b9c 100644
--- a/freebsd/sys/netinet/sctp_output.c
+++ b/freebsd/sys/netinet/sctp_output.c
@@ -12059,8 +12059,8 @@ sctp_copy_resume(struct uio *uio,
m = m_uiotombuf(uio, M_WAITOK, max_send_len, 0,
(M_PKTHDR | (user_marks_eor ? M_EOR : 0)));
if (m == NULL) {
- SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
- *error = ENOMEM;
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
+ *error = ENOBUFS;
} else {
*sndout = m_length(m, NULL);
*new_tail = m_last(m);
@@ -12079,8 +12079,8 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp,
sp->data = m_uiotombuf(uio, M_WAITOK, sp->length,
resv_upfront, 0);
if (sp->data == NULL) {
- SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
- return (ENOMEM);
+ SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
+ return (ENOBUFS);
}
sp->tail_mbuf = m_last(sp->data);
return (0);
diff --git a/freebsd/sys/netinet/sctp_sysctl.c b/freebsd/sys/netinet/sctp_sysctl.c
index ba7a00bf..d0da7a6f 100644
--- a/freebsd/sys/netinet/sctp_sysctl.c
+++ b/freebsd/sys/netinet/sctp_sysctl.c
@@ -686,14 +686,18 @@ static int
sysctl_stat_get(SYSCTL_HANDLER_ARGS)
{
int cpu, error;
- struct sctpstat sb, *sarry, *cpin = NULL;
+ struct sctpstat sb, sb_temp, *sarry, *cpin = NULL;
if ((req->newptr) && (req->newlen == sizeof(struct sctpstat))) {
/*
* User wants us to clear or at least reset the counters to
* the specified values.
*/
- cpin = (struct sctpstat *)req->newptr;
+ cpin = &sb_temp;
+ memset(&sb_temp, 0, sizeof(sb_temp));
+ error = SYSCTL_IN(req, &sb_temp, sizeof(sb_temp));
+ if (error != 0)
+ return (error);
} else if (req->newptr) {
/* Must be a stat structure */
return (EINVAL);
diff --git a/freebsd/sys/netinet/sctp_usrreq.c b/freebsd/sys/netinet/sctp_usrreq.c
index e2bbced4..b19a7499 100644
--- a/freebsd/sys/netinet/sctp_usrreq.c
+++ b/freebsd/sys/netinet/sctp_usrreq.c
@@ -1856,8 +1856,9 @@ flags_out:
SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize);
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
if (stcb) {
- if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
- &av->stream_value) < 0) {
+ if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
+ (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
+ &av->stream_value) < 0)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
} else {
@@ -3662,8 +3663,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize);
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
if (stcb) {
- if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
- av->stream_value) < 0) {
+ if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
+ (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
+ av->stream_value) < 0)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
@@ -3673,10 +3675,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
- stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
- &stcb->asoc,
- &stcb->asoc.strmout[av->stream_id],
- av->stream_value);
+ if (av->stream_id < stcb->asoc.streamoutcnt) {
+ stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
+ &stcb->asoc,
+ &stcb->asoc.strmout[av->stream_id],
+ av->stream_value);
+ }
SCTP_TCB_UNLOCK(stcb);
}
SCTP_INP_RUNLOCK(inp);
diff --git a/freebsd/sys/netinet/tcp_hostcache.c b/freebsd/sys/netinet/tcp_hostcache.c
index ee98af3f..260d161d 100644
--- a/freebsd/sys/netinet/tcp_hostcache.c
+++ b/freebsd/sys/netinet/tcp_hostcache.c
@@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
#include <sys/malloc.h>
+#include <sys/sbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
@@ -594,30 +595,27 @@ tcp_hc_update(struct in_conninfo *inc, struct hc_metrics_lite *hcml)
static int
sysctl_tcp_hc_list(SYSCTL_HANDLER_ARGS)
{
- int bufsize;
int linesize = 128;
- char *p, *buf;
- int len, i, error;
+ struct sbuf sb;
+ int i, error;
struct hc_metrics *hc_entry;
#ifdef INET6
char ip6buf[INET6_ADDRSTRLEN];
#endif
- bufsize = linesize * (V_tcp_hostcache.cache_count + 1);
+ sbuf_new(&sb, NULL, linesize * (V_tcp_hostcache.cache_count + 1),
+ SBUF_FIXEDLEN);
- p = buf = (char *)malloc(bufsize, M_TEMP, M_WAITOK|M_ZERO);
-
- len = snprintf(p, linesize,
- "\nIP address MTU SSTRESH RTT RTTVAR BANDWIDTH "
+ sbuf_printf(&sb,
+ "\nIP address MTU SSTRESH RTT RTTVAR BANDWIDTH "
" CWND SENDPIPE RECVPIPE HITS UPD EXP\n");
- p += len;
#define msec(u) (((u) + 500) / 1000)
for (i = 0; i < V_tcp_hostcache.hashsize; i++) {
THC_LOCK(&V_tcp_hostcache.hashbase[i].hch_mtx);
TAILQ_FOREACH(hc_entry, &V_tcp_hostcache.hashbase[i].hch_bucket,
rmx_q) {
- len = snprintf(p, linesize,
+ sbuf_printf(&sb,
"%-15s %5lu %8lu %6lums %6lums %9lu %8lu %8lu %8lu "
"%4lu %4lu %4i\n",
hc_entry->ip4.s_addr ? inet_ntoa(hc_entry->ip4) :
@@ -639,13 +637,13 @@ sysctl_tcp_hc_list(SYSCTL_HANDLER_ARGS)
hc_entry->rmx_hits,
hc_entry->rmx_updates,
hc_entry->rmx_expire);
- p += len;
}
THC_UNLOCK(&V_tcp_hostcache.hashbase[i].hch_mtx);
}
#undef msec
- error = SYSCTL_OUT(req, buf, p - buf);
- free(buf, M_TEMP);
+ sbuf_finish(&sb);
+ error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
+ sbuf_delete(&sb);
return(error);
}
diff --git a/freebsd/sys/netinet/tcp_input.c b/freebsd/sys/netinet/tcp_input.c
index 20d645f0..f9512eb3 100644
--- a/freebsd/sys/netinet/tcp_input.c
+++ b/freebsd/sys/netinet/tcp_input.c
@@ -504,10 +504,13 @@ do { \
* the ack that opens up a 0-sized window and
* - delayed acks are enabled or
* - this is a half-synchronized T/TCP connection.
+ * - the segment size is not larger than the MSS and LRO wasn't used
+ * for this segment.
*/
-#define DELAY_ACK(tp) \
+#define DELAY_ACK(tp, tlen) \
((!tcp_timer_active(tp, TT_DELACK) && \
(tp->t_flags & TF_RXWIN0SENT) == 0) && \
+ (tlen <= tp->t_maxopd) && \
(V_tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN)))
/*
@@ -1852,7 +1855,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
}
/* NB: sorwakeup_locked() does an implicit unlock. */
sorwakeup_locked(so);
- if (DELAY_ACK(tp)) {
+ if (DELAY_ACK(tp, tlen)) {
tp->t_flags |= TF_DELACK;
} else {
tp->t_flags |= TF_ACKNOW;
@@ -1940,7 +1943,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
* If there's data, delay ACK; if there's also a FIN
* ACKNOW will be turned on later.
*/
- if (DELAY_ACK(tp) && tlen != 0)
+ if (DELAY_ACK(tp, tlen) && tlen != 0)
tcp_timer_activate(tp, TT_DELACK,
tcp_delacktime);
else
@@ -2183,11 +2186,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
todrop = tp->rcv_nxt - th->th_seq;
if (todrop > 0) {
- /*
- * If this is a duplicate SYN for our current connection,
- * advance over it and pretend and it's not a SYN.
- */
- if (thflags & TH_SYN && th->th_seq == tp->irs) {
+ if (thflags & TH_SYN) {
thflags &= ~TH_SYN;
th->th_seq++;
if (th->th_urp > 1)
@@ -2907,7 +2906,7 @@ dodata: /* XXX */
if (th->th_seq == tp->rcv_nxt &&
LIST_EMPTY(&tp->t_segq) &&
TCPS_HAVEESTABLISHED(tp->t_state)) {
- if (DELAY_ACK(tp))
+ if (DELAY_ACK(tp, tlen))
tp->t_flags |= TF_DELACK;
else
tp->t_flags |= TF_ACKNOW;
@@ -3631,6 +3630,8 @@ tcp_mss(struct tcpcb *tp, int offer)
if (cap.ifcap & CSUM_TSO) {
tp->t_flags |= TF_TSO;
tp->t_tsomax = cap.tsomax;
+ tp->t_tsomaxsegcount = cap.tsomaxsegcount;
+ tp->t_tsomaxsegsize = cap.tsomaxsegsize;
}
}
diff --git a/freebsd/sys/netinet/tcp_output.c b/freebsd/sys/netinet/tcp_output.c
index 6215c4e2..550af64f 100644
--- a/freebsd/sys/netinet/tcp_output.c
+++ b/freebsd/sys/netinet/tcp_output.c
@@ -767,28 +767,112 @@ send:
flags &= ~TH_FIN;
if (tso) {
+ u_int if_hw_tsomax;
+ u_int if_hw_tsomaxsegcount;
+ u_int if_hw_tsomaxsegsize;
+ struct mbuf *mb;
+ u_int moff;
+ int max_len;
+
+ /* extract TSO information */
+ if_hw_tsomax = tp->t_tsomax;
+ if_hw_tsomaxsegcount = tp->t_tsomaxsegcount;
+ if_hw_tsomaxsegsize = tp->t_tsomaxsegsize;
+
+ /*
+ * Limit a TSO burst to prevent it from
+ * overflowing or exceeding the maximum length
+ * allowed by the network interface:
+ */
KASSERT(ipoptlen == 0,
("%s: TSO can't do IP options", __func__));
/*
- * Limit a burst to t_tsomax minus IP,
- * TCP and options length to keep ip->ip_len
- * from overflowing or exceeding the maximum
- * length allowed by the network interface.
+ * Check if we should limit by maximum payload
+ * length:
*/
- if (len > tp->t_tsomax - hdrlen) {
- len = tp->t_tsomax - hdrlen;
- sendalot = 1;
+ if (if_hw_tsomax != 0) {
+ /* compute maximum TSO length */
+ max_len = (if_hw_tsomax - hdrlen);
+ if (max_len <= 0) {
+ len = 0;
+ } else if (len > max_len) {
+ sendalot = 1;
+ len = max_len;
+ }
+ }
+
+ /*
+ * Check if we should limit by maximum segment
+ * size and count:
+ */
+ if (if_hw_tsomaxsegcount != 0 &&
+ if_hw_tsomaxsegsize != 0) {
+ max_len = 0;
+ mb = sbsndmbuf(&so->so_snd, off, &moff);
+
+ while (mb != NULL && max_len < len) {
+ u_int mlen;
+ u_int frags;
+
+ /*
+ * Get length of mbuf fragment
+ * and how many hardware frags,
+ * rounded up, it would use:
+ */
+ mlen = (mb->m_len - moff);
+ frags = howmany(mlen,
+ if_hw_tsomaxsegsize);
+
+ /* Handle special case: Zero Length Mbuf */
+ if (frags == 0)
+ frags = 1;
+
+ /*
+ * Check if the fragment limit
+ * will be reached or exceeded:
+ */
+ if (frags >= if_hw_tsomaxsegcount) {
+ max_len += min(mlen,
+ if_hw_tsomaxsegcount *
+ if_hw_tsomaxsegsize);
+ break;
+ }
+ max_len += mlen;
+ if_hw_tsomaxsegcount -= frags;
+ moff = 0;
+ mb = mb->m_next;
+ }
+ if (max_len <= 0) {
+ len = 0;
+ } else if (len > max_len) {
+ sendalot = 1;
+ len = max_len;
+ }
}
/*
* Prevent the last segment from being
- * fractional unless the send sockbuf can
- * be emptied.
+ * fractional unless the send sockbuf can be
+ * emptied:
+ */
+ max_len = (tp->t_maxopd - optlen);
+ if ((off + len) < so->so_snd.sb_cc) {
+ moff = len % max_len;
+ if (moff != 0) {
+ len -= moff;
+ sendalot = 1;
+ }
+ }
+
+ /*
+ * In case there are too many small fragments
+ * don't use TSO:
*/
- if (sendalot && off + len < so->so_snd.sb_cc) {
- len -= len % (tp->t_maxopd - optlen);
+ if (len <= max_len) {
+ len = max_len;
sendalot = 1;
+ tso = 0;
}
/*
diff --git a/freebsd/sys/netinet/tcp_reass.c b/freebsd/sys/netinet/tcp_reass.c
index d4f0bcde..2570a5f3 100644
--- a/freebsd/sys/netinet/tcp_reass.c
+++ b/freebsd/sys/netinet/tcp_reass.c
@@ -94,7 +94,7 @@ SYSCTL_VNET_PROC(_net_inet_tcp_reass, OID_AUTO, cursegments,
static VNET_DEFINE(int, tcp_reass_overflows) = 0;
#define V_tcp_reass_overflows VNET(tcp_reass_overflows)
SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, overflows,
- CTLTYPE_INT | CTLFLAG_RD,
+ CTLFLAG_RD,
&VNET_NAME(tcp_reass_overflows), 0,
"Global number of TCP Segment Reassembly Queue Overflows");
diff --git a/freebsd/sys/netinet/tcp_subr.c b/freebsd/sys/netinet/tcp_subr.c
index d577f18f..b175c0c0 100644
--- a/freebsd/sys/netinet/tcp_subr.c
+++ b/freebsd/sys/netinet/tcp_subr.c
@@ -1750,6 +1750,8 @@ tcp_maxmtu(struct in_conninfo *inc, struct tcp_ifcap *cap)
ifp->if_hwassist & CSUM_TSO) {
cap->ifcap |= CSUM_TSO;
cap->tsomax = ifp->if_hw_tsomax;
+ cap->tsomaxsegcount = ifp->if_hw_tsomaxsegcount;
+ cap->tsomaxsegsize = ifp->if_hw_tsomaxsegsize;
}
}
RTFREE(sro.ro_rt);
@@ -1789,6 +1791,8 @@ tcp_maxmtu6(struct in_conninfo *inc, struct tcp_ifcap *cap)
ifp->if_hwassist & CSUM_TSO) {
cap->ifcap |= CSUM_TSO;
cap->tsomax = ifp->if_hw_tsomax;
+ cap->tsomaxsegcount = ifp->if_hw_tsomaxsegcount;
+ cap->tsomaxsegsize = ifp->if_hw_tsomaxsegsize;
}
}
RTFREE(sro6.ro_rt);
diff --git a/freebsd/sys/netinet/tcp_var.h b/freebsd/sys/netinet/tcp_var.h
index 171eafb6..dbd9ed11 100644
--- a/freebsd/sys/netinet/tcp_var.h
+++ b/freebsd/sys/netinet/tcp_var.h
@@ -212,7 +212,9 @@ struct tcpcb {
uint32_t t_ispare[7]; /* 5 UTO, 2 TBD */
void *t_pspare2[4]; /* 4 TBD */
- uint64_t _pad[6]; /* 6 TBD (1-2 CC/RTT?) */
+ uint64_t _pad[5]; /* 5 TBD (1-2 CC/RTT?) */
+ uint32_t t_tsomaxsegcount; /* TSO maximum segment count */
+ uint32_t t_tsomaxsegsize; /* TSO maximum segment size in bytes */
};
/*
@@ -333,6 +335,8 @@ struct hc_metrics_lite { /* must stay in sync with hc_metrics */
struct tcp_ifcap {
int ifcap;
u_int tsomax;
+ u_int tsomaxsegcount;
+ u_int tsomaxsegsize;
};
#ifndef _NETINET_IN_PCB_H_