if (!READ_ONCE(tcp_memory_pressure)) return;
val = xchg(&tcp_memory_pressure, 0); if (val)
NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPMEMORYPRESSURESCHRONO,
jiffies_to_msecs(jiffies - val));
}
EXPORT_IPV6_MOD_GPL(tcp_leave_memory_pressure);
/* Convert seconds to retransmits based on initial and max timeout */ static u8 secs_to_retrans(int seconds, int timeout, int rto_max)
{
u8 res = 0;
if (seconds > 0) { int period = timeout;
res = 1; while (seconds > period && res < 255) {
res++;
timeout <<= 1; if (timeout > rto_max)
timeout = rto_max;
period += timeout;
}
} return res;
}
/* Convert retransmits to seconds based on initial and max timeout */ staticint retrans_to_secs(u8 retrans, int timeout, int rto_max)
{ int period = 0;
if (retrans > 0) {
period = timeout; while (--retrans) {
timeout <<= 1; if (timeout > rto_max)
timeout = rto_max;
period += timeout;
}
} return period;
}
/* So many TCP implementations out there (incorrectly) count the *initialSYNframeintheirdelayed-ACKandcongestioncontrol *algorithmsthatwemusthavethefollowingbandaidtotalk *efficientlytothem.-DaveM
*/
tcp_snd_cwnd_set(tp, TCP_INIT_CWND);
/* There's a bubble in the pipe until at least the first ACK. */
tp->app_limited = ~0U;
tp->rate_app_limited = 1;
/* See draft-stevens-tcpca-spec-01 for discussion of the *initializationofthesevalues.
*/
tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
tp->snd_cwnd_clamp = ~0;
tp->mss_cache = TCP_MSS_DEFAULT;
staticinlinevoid tcp_mark_urg(struct tcp_sock *tp, int flags)
{ if (flags & MSG_OOB)
tp->snd_up = tp->write_seq;
}
/* If a not yet filled skb is pushed, do not send it if *wehavedatapacketsinQdiscorNICqueues: *BecauseTXcompletionwillhappenshortly,itgivesachance *tocoalescefuturesendmsg()payloadintothisskb,without *needforatimer,andwithnolatencytradeoff. *Aspacketscontainingdatapayloadhaveabiggertruesize *thanpureacks(dataless)packets,thelastchecksprevent *autocorkingifweonlyhaveanACKinQdisc/NICqueues, *orifTXcompletionwasdelayedafterweprocessedACKpacket.
*/ staticbool tcp_should_autocork(struct sock *sk, struct sk_buff *skb, int size_goal)
{ return skb->len < size_goal &&
READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_autocorking) &&
!tcp_rtx_queue_empty(sk) &&
refcount_read(&sk->sk_wmem_alloc) > skb->truesize &&
tcp_skb_can_collapse_to(skb);
}
void tcp_push(struct sock *sk, int flags, int mss_now, int nonagle, int size_goal)
{ struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb;
skb = tcp_write_queue_tail(sk); if (!skb) return; if (!(flags & MSG_MORE) || forced_push(tp))
tcp_mark_push(tp, skb);
tcp_mark_urg(tp, flags);
if (tcp_should_autocork(sk, skb, size_goal)) {
/* avoid atomic op if TSQ_THROTTLED bit is already set */ if (!test_bit(TSQ_THROTTLED, &sk->sk_tsq_flags)) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAUTOCORKING);
set_bit(TSQ_THROTTLED, &sk->sk_tsq_flags);
smp_mb__after_atomic();
} /* It is possible TX completion already happened *beforewesetTSQ_THROTTLED.
*/ if (refcount_read(&sk->sk_wmem_alloc) > skb->truesize) return;
}
sock_rps_record_flow(sk); /* *Wecan'tseekonasocketinput
*/ if (unlikely(*ppos)) return -ESPIPE;
ret = spliced = 0;
lock_sock(sk);
timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK); while (tss.len) {
ret = __tcp_splice_read(sk, &tss); if (ret < 0) break; elseif (!ret) { if (spliced) break; if (sock_flag(sk, SOCK_DONE)) break; if (sk->sk_err) {
ret = sock_error(sk); break;
} if (sk->sk_shutdown & RCV_SHUTDOWN) break; if (sk->sk_state == TCP_CLOSE) { /* *Thisoccurswhenusertriestoread *fromneverconnectedsocket.
*/
ret = -ENOTCONN; break;
} if (!timeo) {
ret = -EAGAIN; break;
} /* if __tcp_splice_read() got nothing while we have *anskbinreceivequeue,wedonotwanttoloop. *ThismighthappenwithURGdata.
*/ if (!skb_queue_empty(&sk->sk_receive_queue)) break;
ret = sk_wait_data(sk, &timeo, NULL); if (ret < 0) break; if (signal_pending(current)) {
ret = sock_intr_errno(timeo); break;
} continue;
}
tss.len -= ret;
spliced += ret;
if (!tss.len || !timeo) break;
release_sock(sk);
lock_sock(sk);
/* In some cases, sendmsg() could have added an skb to the write queue, *butfailedaddingpayloadonit.Weneedtoremoveittoconsumeless *memory,butmoreimportantlybeabletogenerateEPOLLOUTforEdgeTrigger *epoll()users.Anotherreasonisthattcp_write_xmit()doesnotlike *findinganemptyskbinthewritequeue.
*/ void tcp_remove_empty_skb(struct sock *sk)
{ struct sk_buff *skb = tcp_write_queue_tail(sk);
if (skb && TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) {
tcp_unlink_write_queue(skb, sk); if (tcp_write_queue_empty(sk))
tcp_chrono_stop(sk, TCP_CHRONO_BUSY);
tcp_wmem_free_skb(sk, skb);
}
}
/* skb changing from pure zc to mixed, must charge zc */ staticint tcp_downgrade_zcopy_pure(struct sock *sk, struct sk_buff *skb)
{ if (unlikely(skb_zcopy_pure(skb))) {
u32 extra = skb->truesize -
SKB_TRUESIZE(skb_end_offset(skb));
int tcp_wmem_schedule(struct sock *sk, int copy)
{ int left;
if (likely(sk_wmem_schedule(sk, copy))) return copy;
/* We could be in trouble if we have nothing queued. *Usewhateverisleftinsk->sk_forward_allocandtcp_wmem[0] *toguaranteesomeprogress.
*/
left = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_wmem[0]) - sk->sk_wmem_queued; if (left > 0)
sk_forced_mem_schedule(sk, min(left, copy)); return min(copy, sk->sk_forward_alloc);
}
if (!(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen) &
TFO_CLIENT_ENABLE) ||
(uaddr && msg->msg_namelen >= sizeof(uaddr->sa_family) &&
uaddr->sa_family == AF_UNSPEC)) return -EOPNOTSUPP; if (tp->fastopen_req) return -EALREADY; /* Another Fast Open is in progress */
tcp_rate_check_app_limited(sk); /* is sending application-limited? */
/* Wait for a connection to finish. One exception is TCP Fast Open *(passiveside)wheredataisallowedtobesentbeforeaconnection *isfullyestablished.
*/ if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) &&
!tcp_passive_fastopen(sk)) {
err = sk_stream_wait_connect(sk, &timeo); if (err != 0) goto do_error;
}
if (unlikely(tp->repair)) { if (tp->repair_queue == TCP_RECV_QUEUE) {
copied = tcp_send_rcvq(sk, msg, size); goto out_nopush;
}
err = -EINVAL; if (tp->repair_queue == TCP_NO_QUEUE) goto out_err;
/* 'common' sending to sendq */
}
if (sockc_err) {
err = sockc_err; goto out_err;
}
/* This should be in poll */
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
/* All packets are restored as if they have *alreadybeensent.skb_mstamp_nsisn'tsetto *avoidwrongrttestimation.
*/ if (tp->repair)
TCP_SKB_CB(skb)->sacked |= TCPCB_REPAIRED;
}
/* Try to append data to the end of skb. */ if (copy > msg_data_left(msg))
copy = msg_data_left(msg);
if (zc == 0) { bool merge = true; int i = skb_shinfo(skb)->nr_frags; struct page_frag *pfrag = sk_page_frag(sk);
if (!sk_page_frag_refill(sk, pfrag)) goto wait_for_space;
if (!skb_can_coalesce(skb, i, pfrag->page,
pfrag->offset)) { if (i >= READ_ONCE(net_hotdata.sysctl_max_skb_frags)) {
tcp_mark_push(tp, skb); goto new_segment;
}
merge = false;
}
err = sk_stream_wait_memory(sk, &timeo); if (err != 0) goto do_error;
mss_now = tcp_send_mss(sk, &size_goal, flags);
}
out: if (copied) {
tcp_tx_timestamp(sk, &sockc);
tcp_push(sk, flags, mss_now, tp->nonagle, size_goal);
}
out_nopush: /* msg->msg_ubuf is pinned by the caller so we don't take extra refs */ if (uarg && !msg->msg_ubuf)
net_zcopy_put(uarg); if (binding)
net_devmem_dmabuf_binding_put(binding); return copied + copied_syn;
do_error:
tcp_remove_empty_skb(sk);
if (copied + copied_syn) goto out;
out_err: /* msg->msg_ubuf is pinned by the caller so we don't take extra refs */ if (uarg && !msg->msg_ubuf)
net_zcopy_put_abort(uarg, true);
err = sk_stream_error(sk, flags, err); /* make sure we wake any epoll edge trigger waiter */ if (unlikely(tcp_rtx_and_write_queues_empty(sk) && err == -EAGAIN)) {
sk->sk_write_space(sk);
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
} if (binding)
net_devmem_dmabuf_binding_put(binding);
staticint tcp_recv_urg(struct sock *sk, struct msghdr *msg, int len, int flags)
{ struct tcp_sock *tp = tcp_sk(sk);
/* No URG data to read. */ if (sock_flag(sk, SOCK_URGINLINE) || !tp->urg_data ||
tp->urg_data == TCP_URG_READ) return -EINVAL; /* Yes this is right ! */
if (sk->sk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DONE)) return -ENOTCONN;
if (tp->urg_data & TCP_URG_VALID) { int err = 0; char c = tp->urg_data;
if (!(flags & MSG_PEEK))
WRITE_ONCE(tp->urg_data, TCP_URG_READ);
/* Clean up the receive buffer for full frames taken by the user, *thensendanACKifnecessary.COPIEDisthenumberofbytes *tcp_recvmsghasgiventotheusersofar,itspeedsupthe *calculationofwhetherornotwemustACKforthesakeof *awindowupdate.
*/ void __tcp_cleanup_rbuf(struct sock *sk, int copied)
{ struct tcp_sock *tp = tcp_sk(sk); bool time_to_ack = false;
if (inet_csk_ack_scheduled(sk)) { conststruct inet_connection_sock *icsk = inet_csk(sk);
if (/* Once-per-two-segments ACK was not sent by tcp_input.c */
tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss || /* *Ifthisreademptiedreadbuffer,wesendACK,if *connectionisnotbidirectional,userdrained *receivebufferandtherewasasmallsegment *inqueue.
*/
(copied > 0 &&
((icsk->icsk_ack.pending & ICSK_ACK_PUSHED2) ||
((icsk->icsk_ack.pending & ICSK_ACK_PUSHED) &&
!inet_csk_in_pingpong_mode(sk))) &&
!atomic_read(&sk->sk_rmem_alloc)))
time_to_ack = true;
}
/* We send an ACK if we can now advertise a non-zero window *whichhasbeenraised"significantly". * *Evenifwindowraiseduptoinfinity,donotsendwindowopenACK *instates,wherewewillnotreceivemore.Itisuseless.
*/ if (copied > 0 && !time_to_ack && !(sk->sk_shutdown & RCV_SHUTDOWN)) {
__u32 rcv_window_now = tcp_receive_window(tp);
/* Optimize, __tcp_select_window() is not cheap. */ if (2*rcv_window_now <= tp->window_clamp) {
__u32 new_window = __tcp_select_window(sk);
/* Send ACK now, if this read freed lots of space *inourbuffer.Certainly,new_windowisnewwindow. *Wecanadvertiseitnow,ifitisnotlessthancurrentone. *"Lots"means"atleasttwice"here.
*/ if (new_window && new_window >= 2 * rcv_window_now)
time_to_ack = true;
}
} if (time_to_ack)
tcp_send_ack(sk);
}
if (sk->sk_state == TCP_LISTEN) return -ENOTCONN; while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) { if (offset < skb->len) { int used;
size_t len;
len = skb->len - offset; /* Stop reading if we hit a patch of urgent data */ if (unlikely(tp->urg_data)) {
u32 urg_offset = tp->urg_seq - seq; if (urg_offset < len)
len = urg_offset; if (!len) break;
}
used = recv_actor(desc, skb, offset, len); if (used <= 0) { if (!copied)
copied = used; break;
} if (WARN_ON_ONCE(used > len))
used = len;
seq += used;
copied += used;
offset += used;
/* If recv_actor drops the lock (e.g. TCP splice *receive)theskbpointermightbeinvalidwhen *gettinghere:tcp_collapsemighthavedeletedit *whileaggregatingskbsfromthesocketqueue.
*/
skb = tcp_recv_skb(sk, seq - 1, &offset); if (!skb) break; /* TCP coalescing might have appended data to the skb. *Trytosplicemorefrags
*/ if (offset + 1 != skb->len) continue;
} if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) {
tcp_eat_recv_skb(sk, skb);
++seq; break;
}
tcp_eat_recv_skb(sk, skb); if (!desc->count) break;
WRITE_ONCE(*copied_seq, seq);
}
WRITE_ONCE(*copied_seq, seq);
if (noack) goto out;
tcp_rcv_space_adjust(sk);
/* Clean up data we have read: This will do ACK frames. */ if (copied > 0) {
tcp_recv_skb(sk, seq, &offset);
tcp_cleanup_rbuf(sk, copied);
}
out: return copied;
}
/* Clean up data we have read: This will do ACK frames. */ if (left != len)
tcp_cleanup_rbuf(sk, len - left);
}
EXPORT_SYMBOL(tcp_read_done);
int tcp_peek_len(struct socket *sock)
{ return tcp_inq(sock->sk);
}
EXPORT_IPV6_MOD(tcp_peek_len);
/* Make sure sk_rcvbuf is big enough to satisfy SO_RCVLOWAT hint */ int tcp_set_rcvlowat(struct sock *sk, int val)
{ struct tcp_sock *tp = tcp_sk(sk); int space, cap;
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
cap = sk->sk_rcvbuf >> 1; else
cap = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]) >> 1;
val = min(val, cap);
WRITE_ONCE(sk->sk_rcvlowat, val ? : 1);
/* Check if we need to signal EPOLLIN right now */
tcp_data_ready(sk);
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK) return0;
space = tcp_space_from_win(sk, val); if (space > sk->sk_rcvbuf) {
WRITE_ONCE(sk->sk_rcvbuf, space);
/* worst case: skip to next skb. try to improve on this case below */
zc->recv_skip_hint = skb->len - offset;
/* Find the frag containing this offset (and how far into that frag) */
frag = skb_advance_to_frag(skb, offset, &frag_offset); if (!frag) return;
if (frag_offset) { struct skb_shared_info *info = skb_shinfo(skb);
/* We read part of the last frag, must recvmsg() rest of skb. */ if (frag == &info->frags[info->nr_frags - 1]) return;
/* Else, we must at least read the remainder in this frag. */
partial_frag_remainder = skb_frag_size(frag) - frag_offset;
zc->recv_skip_hint -= partial_frag_remainder;
++frag;
}
/* partial_frag_remainder: If part way through a frag, must read rest. *mappable_offset:Bytestillnextmappablefrag,*not*countingbytes *inpartial_frag_remainder.
*/
mappable_offset = find_next_mappable_frag(frag, zc->recv_skip_hint);
zc->recv_skip_hint = mappable_offset + partial_frag_remainder;
}
staticint tcp_recvmsg_locked(struct sock *sk, struct msghdr *msg, size_t len, int flags, struct scm_timestamping_internal *tss, int *cmsg_flags); staticint receive_fallback_to_copy(struct sock *sk, struct tcp_zerocopy_receive *zc, int inq, struct scm_timestamping_internal *tss)
{ unsignedlong copy_address = (unsignedlong)zc->copybuf_address; struct msghdr msg = {}; int err;
zc->length = 0;
zc->recv_skip_hint = 0;
if (copy_address != zc->copybuf_address) return -EINVAL;
if (!err) { unsignedlong leftover_pages = pages_remaining; int bytes_mapped;
/* We called zap_page_range_single, try to reinsert. */
err = vm_insert_pages(vma, *address,
pending_pages,
&pages_remaining);
bytes_mapped = PAGE_SIZE * (leftover_pages - pages_remaining);
*seq += bytes_mapped;
*address += bytes_mapped;
} if (err) { /* Either we were unable to zap, OR we zapped, retried an *insert,andstillhadanissue.Eitherways,pages_remaining *isthenumberofpageswewereunabletomap,andweunroll *somestatewespeculativelytouchedbefore.
*/ constint bytes_not_mapped = PAGE_SIZE * pages_remaining;
mappable_offset = find_next_mappable_frag(frags,
zc->recv_skip_hint); if (mappable_offset) {
zc->recv_skip_hint = mappable_offset; break;
}
page = skb_frag_page(frags); if (WARN_ON_ONCE(!page)) break;
prefetchw(page);
pages[pages_to_map++] = page;
length += PAGE_SIZE;
zc->recv_skip_hint -= PAGE_SIZE;
frags++; if (pages_to_map == TCP_ZEROCOPY_PAGE_BATCH_SIZE ||
zc->recv_skip_hint < PAGE_SIZE) { /* Either full batch, or we're about to go to next skb *(andwecannotunrollfailedopsacrossskbs).
*/
ret = tcp_zerocopy_vm_insert_batch(vma, pages,
pages_to_map,
&address, &length,
&seq, zc,
total_bytes_to_map); if (ret) goto out;
pages_to_map = 0;
}
} if (pages_to_map) {
ret = tcp_zerocopy_vm_insert_batch(vma, pages, pages_to_map,
&address, &length, &seq,
zc, total_bytes_to_map);
}
out: if (mmap_locked)
mmap_read_unlock(current->mm); else
vma_end_read(vma); /* Try to copy straggler data. */ if (!ret)
copylen = tcp_zc_handle_leftover(zc, sk, skb, &seq, copybuf_len, tss);
if (length + copylen) {
WRITE_ONCE(tp->copied_seq, seq);
tcp_rcv_space_adjust(sk);
/* Clean up data we have read: This will do ACK frames. */
tcp_recv_skb(sk, seq, &offset);
tcp_cleanup_rbuf(sk, length + copylen);
ret = 0; if (length == zc->length)
zc->recv_skip_hint = 0;
} else { if (!zc->recv_skip_hint && sock_flag(sk, SOCK_DONE))
ret = -EIO;
}
zc->length = length; return ret;
} #endif
/* Similar to __sock_recv_timestamp, but does not require an skb */ void tcp_recv_timestamp(struct msghdr *msg, conststruct sock *sk, struct scm_timestamping_internal *tss)
{ int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
u32 tsflags = READ_ONCE(sk->sk_tsflags); bool has_timestamping = false;
staticvoid tcp_xa_pool_commit_locked(struct sock *sk, struct tcp_xa_pool *p)
{ int i;
/* Commit part that has been copied to user space. */ for (i = 0; i < p->idx; i++)
__xa_cmpxchg(&sk->sk_user_frags, p->tokens[i], XA_ZERO_ENTRY,
(__force void *)p->netmems[i], GFP_KERNEL); /* Rollback what has been pre-allocated and is no longer needed. */ for (; i < p->max; i++)
__xa_erase(&sk->sk_user_frags, p->tokens[i]);
for (k = 0; k < max_frags; k++) {
err = __xa_alloc(&sk->sk_user_frags, &p->tokens[k],
XA_ZERO_ENTRY, xa_limit_31b, GFP_KERNEL); if (err) break;
}
xa_unlock_bh(&sk->sk_user_frags);
p->max = k;
p->idx = 0; return k ? 0 : err;
}
/* On error, returns the -errno. On success, returns number of bytes sent to the *user.Maynotconsumeallof@remaining_len.
*/ staticint tcp_recvmsg_dmabuf(struct sock *sk, conststruct sk_buff *skb, unsignedint offset, struct msghdr *msg, int remaining_len)
{ struct dmabuf_cmsg dmabuf_cmsg = { 0 }; struct tcp_xa_pool tcp_xa_pool; unsignedint start; int i, copy, n; int sent = 0; int err = 0;
n = copy_to_iter(skb->data + offset, copy,
&msg->msg_iter); if (n != copy) {
err = -EFAULT; goto out;
}
offset += copy;
remaining_len -= copy;
/* First a dmabuf_cmsg for # bytes copied to user *buffer.
*/
memset(&dmabuf_cmsg, 0, sizeof(dmabuf_cmsg));
dmabuf_cmsg.frag_size = copy;
err = put_cmsg_notrunc(msg, SOL_SOCKET,
SO_DEVMEM_LINEAR, sizeof(dmabuf_cmsg),
&dmabuf_cmsg); if (err) goto out;
sent += copy;
if (remaining_len == 0) goto out;
}
/* after that, send information of dmabuf pages through a *sequenceofcmsg
*/ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; struct net_iov *niov;
u64 frag_offset; int end;
/* !skb_frags_readable() should indicate that ALL the *fragsinthisskbaredmabufnet_iovs.We'rechecking *forthatflagabove,butalsocheckindividualfrags *here.Ifthetcpstackisnotsetting *skb_frags_readable()correctly,westilldon'twant *tocrashhere.
*/ if (!skb_frag_net_iov(frag)) {
net_err_ratelimited("Found non-dmabuf skb with net_iov");
err = -ENODEV; goto out;
}
/* Will perform the exchange later */
dmabuf_cmsg.frag_token = tcp_xa_pool.tokens[tcp_xa_pool.idx];
dmabuf_cmsg.dmabuf_id = net_devmem_iov_binding_id(niov);
tcp_xa_pool_commit(sk, &tcp_xa_pool); if (!remaining_len) goto out;
/* if remaining_len is not satisfied yet, we need to go to the *nextfraginthefrag_listtosatisfyremaining_len.
*/
skb = skb_shinfo(skb)->frag_list ?: skb->next;
offset = offset - start;
} while (skb);
if (remaining_len) {
err = -EFAULT; goto out;
}
out:
tcp_xa_pool_commit(sk, &tcp_xa_pool); if (!sent)
sent = err;
/* Are we at urgent data? Stop if we have read anything or have SIGURG pending. */ if (unlikely(tp->urg_data) && tp->urg_seq == *seq) { if (copied) break; if (signal_pending(current)) {
copied = timeo ? sock_intr_errno(timeo) : -EAGAIN; break;
}
}
/* Next get a buffer. */
last = skb_peek_tail(&sk->sk_receive_queue);
skb_queue_walk(&sk->sk_receive_queue, skb) {
last = skb; /* Now that we have two receive queues this *shouldn'thappen.
*/ if (WARN(before(*seq, TCP_SKB_CB(skb)->seq), "TCP recvmsg seq # bug: copied %X, seq %X, rcvnxt %X, fl %X\n",
*seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt,
flags)) break;
found_ok_skb: /* Ok so how much can we use? */
used = skb->len - offset; if (len < used)
used = len;
/* Do we have urgent data here? */ if (unlikely(tp->urg_data)) {
u32 urg_offset = tp->urg_seq - *seq; if (urg_offset < used) { if (!urg_offset) { if (!sock_flag(sk, SOCK_URGINLINE)) {
WRITE_ONCE(*seq, *seq + 1);
urg_hole++;
offset++;
used--; if (!used) goto skip_copy;
}
} else
used = urg_offset;
}
}
if (!(flags & MSG_TRUNC)) { if (last_copied_dmabuf != -1 &&
last_copied_dmabuf != !skb_frags_readable(skb)) break;
if (skb_frags_readable(skb)) {
err = skb_copy_datagram_msg(skb, offset, msg,
used); if (err) { /* Exception. Bailout! */ if (!copied)
copied = -EFAULT; break;
}
} else { if (!(flags & MSG_SOCK_DEVMEM)) { /* dmabuf skbs can only be received *withtheMSG_SOCK_DEVMEMflag.
*/ if (!copied)
copied = -EFAULT;
break;
}
err = tcp_recvmsg_dmabuf(sk, skb, offset, msg,
used); if (err < 0) { if (!copied)
copied = err;
break;
}
used = err;
}
}
last_copied_dmabuf = !skb_frags_readable(skb);
WRITE_ONCE(*seq, *seq + used);
copied += used;
len -= used; if (flags & MSG_PEEK)
sk_peek_offset_fwd(sk, used); else
sk_peek_offset_bwd(sk, used);
tcp_rcv_space_adjust(sk);
/* Change state AFTER socket is unhashed to avoid closed *socketsittinginhashtables.
*/
inet_sk_state_store(sk, state);
}
EXPORT_SYMBOL_GPL(tcp_set_state);
void tcp_shutdown(struct sock *sk, int how)
{ /* We need to grab some memory, and put together a FIN, *andthenputitintothequeuetobesent. *TimMacKenzie(tym@dibbler.cs.monash.edu.au)4Dec'92.
*/ if (!(how & SEND_SHUTDOWN)) return;
/* If we've already sent a FIN, or it's a closed state, skip this. */ if ((1 << sk->sk_state) &
(TCPF_ESTABLISHED | TCPF_SYN_SENT |
TCPF_CLOSE_WAIT)) { /* Clear out any half completed packets. FIN if needed. */ if (tcp_close_state(sk))
tcp_send_fin(sk);
}
}
EXPORT_IPV6_MOD(tcp_shutdown);
int tcp_orphan_count_sum(void)
{ int i, total = 0;
for_each_possible_cpu(i)
total += per_cpu(tcp_orphan_count, i);
if (too_many_orphans)
net_info_ratelimited("too many orphaned sockets\n"); if (out_of_socket_memory)
net_info_ratelimited("out of memory -- consider tuning tcp_mem\n"); return too_many_orphans || out_of_socket_memory;
}
void __tcp_close(struct sock *sk, long timeout)
{ bool data_was_unread = false; struct sk_buff *skb; int state;
WRITE_ONCE(sk->sk_shutdown, SHUTDOWN_MASK);
if (sk->sk_state == TCP_LISTEN) {
tcp_set_state(sk, TCP_CLOSE);
/* Special case. */
inet_csk_listen_stop(sk);
goto adjudge_to_death;
}
/* We need to flush the recv. buffs. We do this only on the *descriptorclose,notprotocol-sourcedcloses,becausethe *readerprocessmaynothavedrainedthedatayet!
*/ while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
u32 end_seq = TCP_SKB_CB(skb)->end_seq;
if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
end_seq--; if (after(end_seq, tcp_sk(sk)->copied_seq))
data_was_unread = true;
__kfree_skb(skb);
}
/* If socket has been already reset (e.g. in tcp_reset()) - kill it. */ if (sk->sk_state == TCP_CLOSE) goto adjudge_to_death;
/* As outlined in RFC 2525, section 2.17, we send a RST here because *datawaslost.Towitnesstheawfuleffectsoftheoldbehaviorof *alwaysdoingaFIN,runanolder2.1.xkernelor2.0.x,startabulk *GETinanFTPclient,suspendtheprocess,waitfortheclientto *advertiseazerowindow,thenkill-9theFTPclient,wheee... *Note:timeoutisalwayszeroinsuchacase.
*/ if (unlikely(tcp_sk(sk)->repair)) {
sk->sk_prot->disconnect(sk, 0);
} elseif (data_was_unread) { /* Unread data was tossed, zap the connection. */
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
tcp_set_state(sk, TCP_CLOSE);
tcp_send_active_reset(sk, sk->sk_allocation,
SK_RST_REASON_TCP_ABORT_ON_CLOSE);
} elseif (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { /* Check zero linger _after_ checking for unread data. */
sk->sk_prot->disconnect(sk, 0);
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA);
} elseif (tcp_close_state(sk)) { /* We FIN if the application ate all the data before *zappingtheconnection.
*/
adjudge_to_death:
state = sk->sk_state;
sock_hold(sk);
sock_orphan(sk);
local_bh_disable();
bh_lock_sock(sk); /* remove backlog if any, without releasing ownership. */
__release_sock(sk);
this_cpu_inc(tcp_orphan_count);
/* Have we already been destroyed by a softirq or backlog? */ if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE) goto out;
/* This is a (useful) BSD violating of the RFC. There is a *problemwithTCPasspecifiedinthattheotherendcould *keepasocketopenforeverwithnoapplicationleftthisend. *Weusea1minutetimeout(aboutthesameasBSD)thenkill *ourend.Iftheysendafterthatthentough-BUT:longenough *thatwewon'tmaketheold4*rto=almostnotime-whoops *resetmistake. * *Nope,itwasnotmistake.Itisreallydesiredbehaviour *f.e.onhttpservers,whensuchsocketsareuseless,but *consumesignificantresources.Let'sdoitwithspecial *linger2option.--ANK
*/
if (tmo > TCP_TIMEWAIT_LEN) {
tcp_reset_keepalive_timer(sk,
tmo - TCP_TIMEWAIT_LEN);
} else {
tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); goto out;
}
}
} if (sk->sk_state != TCP_CLOSE) { if (tcp_check_oom(sk, 0)) {
tcp_set_state(sk, TCP_CLOSE);
tcp_send_active_reset(sk, GFP_ATOMIC,
SK_RST_REASON_TCP_ABORT_ON_MEMORY);
__NET_INC_STATS(sock_net(sk),
LINUX_MIB_TCPABORTONMEMORY);
} elseif (!check_net(sock_net(sk))) { /* Not possible to send reset; just close */
tcp_set_state(sk, TCP_CLOSE);
}
}
if (sk->sk_state == TCP_CLOSE) { struct request_sock *req;
req = rcu_dereference_protected(tcp_sk(sk)->fastopen_rsk,
lockdep_sock_is_held(sk)); /* We could get here with a non-NULL req if the socket is *aborted(e.g.,closedwithunreaddata)before3WHS *finishes.
*/ if (req)
reqsk_fastopen_remove(sk, req, false);
inet_csk_destroy_sock(sk);
} /* Otherwise, socket is reprieved until protocol close. */
out:
bh_unlock_sock(sk);
local_bh_enable();
}
void tcp_close(struct sock *sk, long timeout)
{
lock_sock(sk);
__tcp_close(sk, timeout);
release_sock(sk); if (!sk->sk_net_refcnt)
inet_csk_clear_xmit_timers_sync(sk);
sock_put(sk);
}
EXPORT_SYMBOL(tcp_close);
/* These states need RST on ABORT according to RFC793 */
p = rb_next(p); /* Since we are deleting whole queue, no need to *list_del(&skb->tcp_tsorted_anchor)
*/
tcp_rtx_queue_unlink(skb, sk);
tcp_wmem_free_skb(sk, skb);
}
}
int tcp_sock_set_user_timeout(struct sock *sk, int val)
{ /* Cap the max time in ms TCP will retry or probe the window *beforegivingupandaborting(ETIMEDOUT)aconnection.
*/ if (val < 0) return -EINVAL;
if (new_window_clamp == old_window_clamp) return0;
WRITE_ONCE(tp->window_clamp, new_window_clamp);
/* Need to apply the reserved mem provisioning only *whenshrinkingthewindowclamp.
*/ if (new_window_clamp < old_window_clamp) {
__tcp_adjust_rcv_ssthresh(sk, new_window_clamp);
} else {
new_rcv_ssthresh = min(tp->rcv_wnd, new_window_clamp);
tp->rcv_ssthresh = max(new_rcv_ssthresh, tp->rcv_ssthresh);
} return0;
}
int tcp_sock_set_maxseg(struct sock *sk, int val)
{ /* Values greater than interface MTU won't take effect. However *atthepointwhenthiscallisdonewetypicallydon'tyet *knowwhichinterfaceisgoingtobeused
*/ if (val && (val < TCP_MIN_MSS || val > MAX_TCP_WINDOW)) return -EINVAL;
tcp_sk(sk)->rx_opt.user_mss = val; return0;
}
/* *SocketoptioncodeforTCP.
*/ int do_tcp_setsockopt(struct sock *sk, int level, int optname,
sockptr_t optval, unsignedint optlen)
{ struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); struct net *net = sock_net(sk); int val; int err = 0;
/* These are data/string values, all the others are ints */ switch (optname) { case TCP_CONGESTION: { char name[TCP_CA_NAME_MAX];
if (optlen < 1) return -EINVAL;
val = strncpy_from_sockptr(name, optval,
min_t(long, TCP_CA_NAME_MAX-1, optlen)); if (val < 0) return -EFAULT;
name[val] = 0;
/* Allow a backup key as well to facilitate key rotation *Firstkeyistheactiveone.
*/ if (optlen != TCP_FASTOPEN_KEY_LENGTH &&
optlen != TCP_FASTOPEN_KEY_BUF_LENGTH) return -EINVAL;
if (copy_from_sockptr(key, optval, optlen)) return -EFAULT;
if (optlen == TCP_FASTOPEN_KEY_BUF_LENGTH)
backup_key = key + TCP_FASTOPEN_KEY_LENGTH;
if (copy_from_sockptr(&val, optval, sizeof(val))) return -EFAULT;
/* Handle options that can be set without locking the socket. */ switch (optname) { case TCP_SYNCNT: return tcp_sock_set_syncnt(sk, val); case TCP_USER_TIMEOUT: return tcp_sock_set_user_timeout(sk, val); case TCP_KEEPINTVL: return tcp_sock_set_keepintvl(sk, val); case TCP_KEEPCNT: return tcp_sock_set_keepcnt(sk, val); case TCP_LINGER2: if (val < 0)
WRITE_ONCE(tp->linger2, -1); elseif (val > TCP_FIN_TIMEOUT_MAX / HZ)
WRITE_ONCE(tp->linger2, TCP_FIN_TIMEOUT_MAX); else
WRITE_ONCE(tp->linger2, val * HZ); return0; case TCP_DEFER_ACCEPT: /* Translate value in seconds to number of retransmits */
WRITE_ONCE(icsk->icsk_accept_queue.rskq_defer_accept,
secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ,
TCP_RTO_MAX / HZ)); return0; case TCP_RTO_MAX_MS: if (val < MSEC_PER_SEC || val > TCP_RTO_MAX_SEC * MSEC_PER_SEC) return -EINVAL;
WRITE_ONCE(inet_csk(sk)->icsk_rto_max, msecs_to_jiffies(val)); return0; case TCP_RTO_MIN_US: { int rto_min = usecs_to_jiffies(val);
if (rto_min > TCP_RTO_MIN || rto_min < TCP_TIMEOUT_MIN) return -EINVAL;
WRITE_ONCE(inet_csk(sk)->icsk_rto_min, rto_min); return0;
} case TCP_DELACK_MAX_US: { int delack_max = usecs_to_jiffies(val);
/* segs_in and data_segs_in can be updated from tcp_segs_in() from BH */
info->tcpi_segs_in = READ_ONCE(tp->segs_in);
info->tcpi_data_segs_in = READ_ONCE(tp->data_segs_in);
int do_tcp_getsockopt(struct sock *sk, int level, int optname, sockptr_t optval, sockptr_t optlen)
{ struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); struct net *net = sock_net(sk); int val, len;
if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT;
if (len < 0) return -EINVAL;
len = min_t(unsignedint, len, sizeof(int));
switch (optname) { case TCP_MAXSEG:
val = tp->mss_cache; if (tp->rx_opt.user_mss &&
((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))
val = tp->rx_opt.user_mss; if (tp->repair)
val = tp->rx_opt.mss_clamp; break; case TCP_NODELAY:
val = !!(tp->nonagle&TCP_NAGLE_OFF); break; case TCP_CORK:
val = !!(tp->nonagle&TCP_NAGLE_CORK); break; case TCP_KEEPIDLE:
val = keepalive_time_when(tp) / HZ; break; case TCP_KEEPINTVL:
val = keepalive_intvl_when(tp) / HZ; break; case TCP_KEEPCNT:
val = keepalive_probes(tp); break; case TCP_SYNCNT:
val = READ_ONCE(icsk->icsk_syn_retries) ? :
READ_ONCE(net->ipv4.sysctl_tcp_syn_retries); break; case TCP_LINGER2:
val = READ_ONCE(tp->linger2); if (val >= 0)
val = (val ? : READ_ONCE(net->ipv4.sysctl_tcp_fin_timeout)) / HZ; break; case TCP_DEFER_ACCEPT:
val = READ_ONCE(icsk->icsk_accept_queue.rskq_defer_accept);
val = retrans_to_secs(val, TCP_TIMEOUT_INIT / HZ,
TCP_RTO_MAX / HZ); break; case TCP_WINDOW_CLAMP:
val = READ_ONCE(tp->window_clamp); break; case TCP_INFO: { struct tcp_info info;
if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT;
tcp_get_info(sk, &info);
len = min_t(unsignedint, len, sizeof(info)); if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT; if (copy_to_sockptr(optval, &info, len)) return -EFAULT; return0;
} case TCP_CC_INFO: { conststruct tcp_congestion_ops *ca_ops; union tcp_cc_info info;
size_t sz = 0; int attr;
if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT;
len = min_t(unsignedint, len, sz); if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT; if (copy_to_sockptr(optval, &info, len)) return -EFAULT; return0;
} case TCP_QUICKACK:
val = !inet_csk_in_pingpong_mode(sk); break;
case TCP_CONGESTION: if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT;
len = min_t(unsignedint, len, TCP_CA_NAME_MAX); if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT; if (copy_to_sockptr(optval, icsk->icsk_ca_ops->name, len)) return -EFAULT; return0;
case TCP_ULP: if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT;
len = min_t(unsignedint, len, TCP_ULP_NAME_MAX); if (!icsk->icsk_ulp_ops) {
len = 0; if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT; return0;
} if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT; if (copy_to_sockptr(optval, icsk->icsk_ulp_ops->name, len)) return -EFAULT; return0;
case TCP_FASTOPEN_KEY: {
u64 key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(u64)]; unsignedint key_len;
if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT;
key_len = tcp_fastopen_get_cipher(net, icsk, key) *
TCP_FASTOPEN_KEY_LENGTH;
len = min_t(unsignedint, len, key_len); if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT; if (copy_to_sockptr(optval, key, len)) return -EFAULT; return0;
} case TCP_THIN_LINEAR_TIMEOUTS:
val = tp->thin_lto; break;
case TCP_THIN_DUPACK:
val = 0; break;
case TCP_REPAIR:
val = tp->repair; break;
case TCP_REPAIR_QUEUE: if (tp->repair)
val = tp->repair_queue; else return -EINVAL; break;
case TCP_REPAIR_WINDOW: { struct tcp_repair_window opt;
if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT;
if (copy_to_sockptr(optval, &opt, len)) return -EFAULT; return0;
} case TCP_QUEUE_SEQ: if (tp->repair_queue == TCP_SEND_QUEUE)
val = tp->write_seq; elseif (tp->repair_queue == TCP_RECV_QUEUE)
val = tp->rcv_nxt; else return -EINVAL; break;
case TCP_USER_TIMEOUT:
val = READ_ONCE(icsk->icsk_user_timeout); break;
case TCP_FASTOPEN:
val = READ_ONCE(icsk->icsk_accept_queue.fastopenq.max_qlen); break;
case TCP_FASTOPEN_CONNECT:
val = tp->fastopen_connect; break;
case TCP_FASTOPEN_NO_COOKIE:
val = tp->fastopen_no_cookie; break;
case TCP_TX_DELAY:
val = READ_ONCE(tp->tcp_tx_delay); break;
case TCP_TIMESTAMP:
val = tcp_clock_ts(tp->tcp_usec_ts) + READ_ONCE(tp->tsoffset); if (tp->tcp_usec_ts)
val |= 1; else
val &= ~1; break; case TCP_NOTSENT_LOWAT:
val = READ_ONCE(tp->notsent_lowat); break; case TCP_INQ:
val = tp->recvmsg_inq; break; case TCP_SAVE_SYN:
val = tp->save_syn; break; case TCP_SAVED_SYN: { if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT;
sockopt_lock_sock(sk); if (tp->saved_syn) { if (len < tcp_saved_syn_len(tp->saved_syn)) {
len = tcp_saved_syn_len(tp->saved_syn); if (copy_to_sockptr(optlen, &len, sizeof(int))) {
sockopt_release_sock(sk); return -EFAULT;
}
sockopt_release_sock(sk); return -EINVAL;
}
len = tcp_saved_syn_len(tp->saved_syn); if (copy_to_sockptr(optlen, &len, sizeof(int))) {
sockopt_release_sock(sk); return -EFAULT;
} if (copy_to_sockptr(optval, tp->saved_syn->data, len)) {
sockopt_release_sock(sk); return -EFAULT;
}
tcp_saved_syn_free(tp);
sockopt_release_sock(sk);
} else {
sockopt_release_sock(sk);
len = 0; if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT;
} return0;
} #ifdef CONFIG_MMU case TCP_ZEROCOPY_RECEIVE: { struct scm_timestamping_internal tss; struct tcp_zerocopy_receive zc = {}; int err;
if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT; if (len < 0 ||
len < offsetofend(struct tcp_zerocopy_receive, length)) return -EINVAL; if (unlikely(len > sizeof(zc))) {
err = check_zeroed_sockptr(optval, sizeof(zc),
len - sizeof(zc)); if (err < 1) return err == 0 ? -EINVAL : err;
len = sizeof(zc); if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT;
} if (copy_from_sockptr(&zc, optval, len)) return -EFAULT; if (zc.reserved) return -EINVAL; if (zc.msg_flags & ~(TCP_VALID_ZC_MSG_FLAGS)) return -EINVAL;
sockopt_lock_sock(sk);
err = tcp_zerocopy_receive(sk, &zc, &tss);
err = BPF_CGROUP_RUN_PROG_GETSOCKOPT_KERN(sk, level, optname,
&zc, &len, err);
sockopt_release_sock(sk); if (len >= offsetofend(struct tcp_zerocopy_receive, msg_flags)) goto zerocopy_rcv_cmsg; switch (len) { case offsetofend(struct tcp_zerocopy_receive, msg_flags): goto zerocopy_rcv_cmsg; case offsetofend(struct tcp_zerocopy_receive, msg_controllen): case offsetofend(struct tcp_zerocopy_receive, msg_control): case offsetofend(struct tcp_zerocopy_receive, flags): case offsetofend(struct tcp_zerocopy_receive, copybuf_len): case offsetofend(struct tcp_zerocopy_receive, copybuf_address): case offsetofend(struct tcp_zerocopy_receive, err): goto zerocopy_rcv_sk_err; case offsetofend(struct tcp_zerocopy_receive, inq): goto zerocopy_rcv_inq; case offsetofend(struct tcp_zerocopy_receive, length): default: goto zerocopy_rcv_out;
}
zerocopy_rcv_cmsg: if (zc.msg_flags & TCP_CMSG_TS)
tcp_zc_finalize_rx_tstamp(sk, &zc, &tss); else
zc.msg_flags = 0;
zerocopy_rcv_sk_err: if (!err)
zc.err = sock_error(sk);
zerocopy_rcv_inq:
zc.inq = tcp_inq_hint(sk);
zerocopy_rcv_out: if (!err && copy_to_sockptr(optval, &zc, len))
err = -EFAULT; return err;
} #endif case TCP_AO_REPAIR: if (!tcp_can_repair_sock(sk)) return -EPERM; return tcp_ao_get_repair(sk, optval, optlen); case TCP_AO_GET_KEYS: case TCP_AO_INFO: { int err;
return err;
} case TCP_IS_MPTCP:
val = 0; break; case TCP_RTO_MAX_MS:
val = jiffies_to_msecs(tcp_rto_max(sk)); break; case TCP_RTO_MIN_US:
val = jiffies_to_usecs(READ_ONCE(inet_csk(sk)->icsk_rto_min)); break; case TCP_DELACK_MAX_US:
val = jiffies_to_usecs(READ_ONCE(inet_csk(sk)->icsk_delack_max)); break; default: return -ENOPROTOOPT;
}
if (copy_to_sockptr(optlen, &len, sizeof(int))) return -EFAULT; if (copy_to_sockptr(optval, &val, len)) return -EFAULT; return0;
}
bool tcp_bpf_bypass_getsockopt(int level, int optname)
{ /* TCP do_tcp_getsockopt has optimized getsockopt implementation *toavoidextrasocketlockforTCP_ZEROCOPY_RECEIVE.
*/ if (level == SOL_TCP && optname == TCP_ZEROCOPY_RECEIVE) returntrue;
int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen)
{ struct inet_connection_sock *icsk = inet_csk(sk);
if (level != SOL_TCP) /* Paired with WRITE_ONCE() in do_ipv6_setsockopt() and tcp_v6_connect() */ return READ_ONCE(icsk->icsk_af_ops)->getsockopt(sk, level, optname,
optval, optlen); return do_tcp_getsockopt(sk, level, optname, USER_SOCKPTR(optval),
USER_SOCKPTR(optlen));
}
EXPORT_IPV6_MOD(tcp_getsockopt);
#ifdef CONFIG_TCP_MD5SIG int tcp_md5_sigpool_id = -1;
EXPORT_IPV6_MOD_GPL(tcp_md5_sigpool_id);
int tcp_md5_alloc_sigpool(void)
{
size_t scratch_size; int ret;
scratch_size = sizeof(union tcp_md5sum_block) + sizeof(struct tcphdr);
ret = tcp_sigpool_alloc_ahash("md5", scratch_size); if (ret >= 0) { /* As long as any md5 sigpool was allocated, the return *idwouldstaythesame.Re-writetheidonlyforthecase *whenpreviouslyallMD5keysweredeletedandthiscall *allocatesthefirstMD5key,whichmayreturnadifferent *sigpoolidthanwasusedpreviously.
*/
WRITE_ONCE(tcp_md5_sigpool_id, ret); /* Avoids the compiler potentially being smart here */ return0;
} return ret;
}
/* We use data_race() because tcp_md5_do_add() might change *key->keyunderus
*/ return data_race(crypto_ahash_update(hp->req));
}
EXPORT_IPV6_MOD(tcp_md5_hash_key);
/* Called with rcu_read_lock() */ staticenum skb_drop_reason
tcp_inbound_md5_hash(conststruct sock *sk, conststruct sk_buff *skb, constvoid *saddr, constvoid *daddr, int family, int l3index, const __u8 *hash_location)
{ /* This gets called for each TCP segment that has TCP-MD5 option. *Wehave3dropcases: *oNoMD5hashandoneexpected. *oMD5hashandwe'renotexpectingone. *oMD5hashanditswrong.
*/ conststruct tcp_sock *tp = tcp_sk(sk); struct tcp_md5sig_key *key;
u8 newhash[16]; int genhash;
/* Called with rcu_read_lock() */ enum skb_drop_reason
tcp_inbound_hash(struct sock *sk, conststruct request_sock *req, conststruct sk_buff *skb, constvoid *saddr, constvoid *daddr, int family, int dif, int sdif)
{ conststruct tcphdr *th = tcp_hdr(skb); conststruct tcp_ao_hdr *aoh; const __u8 *md5_location; int l3index;
/* Invalid option or two times meet any of auth options */ if (tcp_parse_auth_options(th, &md5_location, &aoh)) {
trace_tcp_hash_bad_header(sk, skb); return SKB_DROP_REASON_TCP_AUTH_HDR;
}
if (req) { if (tcp_rsk_used_ao(req) != !!aoh) {
u8 keyid, rnext, maclen;
/* We might be called with a new socket, after *inet_csk_prepare_forced_close()hasbeencalled *sowecannotuselockdep_sock_is_held(sk)
*/
req = rcu_dereference_protected(tcp_sk(sk)->fastopen_rsk, 1);
if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS);
tcp_set_state(sk, TCP_CLOSE);
tcp_clear_xmit_timers(sk); if (req)
reqsk_fastopen_remove(sk, req, false);
WRITE_ONCE(sk->sk_shutdown, SHUTDOWN_MASK);
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_state_change(sk); else
inet_csk_destroy_sock(sk);
}
EXPORT_SYMBOL_GPL(tcp_done);
int tcp_abort(struct sock *sk, int err)
{ int state = inet_sk_state_load(sk);
if (state == TCP_NEW_SYN_RECV) { struct request_sock *req = inet_reqsk(sk);
/* Size and allocate the main established and bind bucket *hashtables. * *Themethodologyissimilartothatofthebuffercache.
*/
tcp_hashinfo.ehash =
alloc_large_system_hash("TCP established", sizeof(struct inet_ehash_bucket),
thash_entries, 17, /* one slot per 128 KB of memory */ 0,
NULL,
&tcp_hashinfo.ehash_mask, 0,
thash_entries ? 0 : 512 * 1024); for (i = 0; i <= tcp_hashinfo.ehash_mask; i++)
INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i);
if (inet_ehash_locks_alloc(&tcp_hashinfo))
panic("TCP: failed to alloc ehash_locks");
tcp_hashinfo.bhash =
alloc_large_system_hash("TCP bind", 2 * sizeof(struct inet_bind_hashbucket),
tcp_hashinfo.ehash_mask + 1, 17, /* one slot per 128 KB of memory */ 0,
&tcp_hashinfo.bhash_size,
NULL, 0, 64 * 1024);
tcp_hashinfo.bhash_size = 1U << tcp_hashinfo.bhash_size;
tcp_hashinfo.bhash2 = tcp_hashinfo.bhash + tcp_hashinfo.bhash_size; for (i = 0; i < tcp_hashinfo.bhash_size; i++) {
spin_lock_init(&tcp_hashinfo.bhash[i].lock);
INIT_HLIST_HEAD(&tcp_hashinfo.bhash[i].chain);
spin_lock_init(&tcp_hashinfo.bhash2[i].lock);
INIT_HLIST_HEAD(&tcp_hashinfo.bhash2[i].chain);
}
tcp_init_mem(); /* Set per-socket limits to no more than 1/128 the pressure threshold */
limit = nr_free_buffer_pages() << (PAGE_SHIFT - 7);
max_wshare = min(4UL*1024*1024, limit);
max_rshare = min(32UL*1024*1024, limit);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.570Bemerkung:
(vorverarbeitet am 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.