diff options
Diffstat (limited to 'freebsd/sys/netinet/ip_output.c')
-rw-r--r-- | freebsd/sys/netinet/ip_output.c | 71 |
1 files changed, 52 insertions, 19 deletions
diff --git a/freebsd/sys/netinet/ip_output.c b/freebsd/sys/netinet/ip_output.c index 792f2311..5f643746 100644 --- a/freebsd/sys/netinet/ip_output.c +++ b/freebsd/sys/netinet/ip_output.c @@ -82,6 +82,10 @@ __FBSDID("$FreeBSD$"); #include <netinet/in_var.h> #include <netinet/ip_var.h> #include <netinet/ip_options.h> + +#include <netinet/udp.h> +#include <netinet/udp_var.h> + #ifdef SCTP #include <netinet/sctp.h> #include <netinet/sctp_crc32.h> @@ -922,24 +926,34 @@ void in_delayed_cksum(struct mbuf *m) { struct ip *ip; - uint16_t csum, offset, ip_len; + struct udphdr *uh; + uint16_t cklen, csum, offset; ip = mtod(m, struct ip *); offset = ip->ip_hl << 2 ; - ip_len = ntohs(ip->ip_len); - csum = in_cksum_skip(m, ip_len, offset); - if (m->m_pkthdr.csum_flags & CSUM_UDP && csum == 0) - csum = 0xffff; - offset += m->m_pkthdr.csum_data; /* checksum offset */ - /* find the mbuf in the chain where the checksum starts*/ - while ((m != NULL) && (offset >= m->m_len)) { - offset -= m->m_len; - m = m->m_next; + if (m->m_pkthdr.csum_flags & CSUM_UDP) { + /* if udp header is not in the first mbuf copy udplen */ + if (offset + sizeof(struct udphdr) > m->m_len) + m_copydata(m, offset + offsetof(struct udphdr, + uh_ulen), sizeof(cklen), (caddr_t)&cklen); + else { + uh = (struct udphdr *)mtodo(m, offset); + cklen = ntohs(uh->uh_ulen); + } + csum = in_cksum_skip(m, cklen + offset, offset); + if (csum == 0) + csum = 0xffff; + } else { + cklen = ntohs(ip->ip_len); + csum = in_cksum_skip(m, cklen, offset); } - KASSERT(m != NULL, ("in_delayed_cksum: checksum outside mbuf chain.")); - KASSERT(offset + sizeof(u_short) <= m->m_len, ("in_delayed_cksum: checksum split between mbufs.")); - *(u_short *)(m->m_data + offset) = csum; + offset += m->m_pkthdr.csum_data; /* checksum offset */ + + if (offset + sizeof(csum) > m->m_len) + m_copyback(m, offset, sizeof(csum), (caddr_t)&csum); + else + *(u_short *)mtodo(m, offset) = csum; } /* @@ -980,6 +994,15 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt) INP_WUNLOCK(inp); error = 0; break; + case SO_REUSEPORT_LB: + INP_WLOCK(inp); + if ((so->so_options & SO_REUSEPORT_LB) != 0) + inp->inp_flags2 |= INP_REUSEPORT_LB; + else + inp->inp_flags2 &= ~INP_REUSEPORT_LB; + INP_WUNLOCK(inp); + error = 0; + break; case SO_SETFIB: INP_WLOCK(inp); inp->inp_inc.inc_fibnum = so->so_fibnum; @@ -1235,13 +1258,23 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt) switch (sopt->sopt_name) { case IP_OPTIONS: case IP_RETOPTS: - if (inp->inp_options) - error = sooptcopyout(sopt, - mtod(inp->inp_options, - char *), - inp->inp_options->m_len); - else + INP_RLOCK(inp); + if (inp->inp_options) { + struct mbuf *options; + + options = m_dup(inp->inp_options, M_NOWAIT); + INP_RUNLOCK(inp); + if (options != NULL) { + error = sooptcopyout(sopt, + mtod(options, char *), + options->m_len); + m_freem(options); + } else + error = ENOMEM; + } else { + INP_RUNLOCK(inp); sopt->sopt_valsize = 0; + } break; case IP_TOS: |