diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-04-08 15:37:49 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-05-20 09:58:21 +0200 |
commit | 165dd8ea1256d71d6a4f52c0a66dcc2799ef8f99 (patch) | |
tree | c42072a99573d4d7cc03b2263e2c0c6d53f9c691 /freebsd/sys/netinet | |
parent | rtems-bsd-chunk: Include missing header file (diff) | |
download | rtems-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.c | 52 | ||||
-rw-r--r-- | freebsd/sys/netinet/if_ether.c | 8 | ||||
-rw-r--r-- | freebsd/sys/netinet/igmp.c | 9 | ||||
-rw-r--r-- | freebsd/sys/netinet/in.c | 28 | ||||
-rw-r--r-- | freebsd/sys/netinet/ip_output.c | 10 | ||||
-rw-r--r-- | freebsd/sys/netinet/sctp_input.c | 44 | ||||
-rw-r--r-- | freebsd/sys/netinet/sctp_output.c | 8 | ||||
-rw-r--r-- | freebsd/sys/netinet/sctp_sysctl.c | 8 | ||||
-rw-r--r-- | freebsd/sys/netinet/sctp_usrreq.c | 20 | ||||
-rw-r--r-- | freebsd/sys/netinet/tcp_hostcache.c | 24 | ||||
-rw-r--r-- | freebsd/sys/netinet/tcp_input.c | 19 | ||||
-rw-r--r-- | freebsd/sys/netinet/tcp_output.c | 106 | ||||
-rw-r--r-- | freebsd/sys/netinet/tcp_reass.c | 2 | ||||
-rw-r--r-- | freebsd/sys/netinet/tcp_subr.c | 4 | ||||
-rw-r--r-- | freebsd/sys/netinet/tcp_var.h | 6 |
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_ |