#define _sock_locks(x) \
x "AF_UNSPEC", x "AF_UNIX" , x "AF_INET" , \
x "AF_AX25" , x "AF_IPX" , x "AF_APPLETALK", \
x "AF_NETROM", x "AF_BRIDGE" , x "AF_ATMPVC" , \
x "AF_X25" , x "AF_INET6" , x "AF_ROSE" , \
x "AF_DECnet", x "AF_NETBEUI" , x "AF_SECURITY" , \
x "AF_KEY" , x "AF_NETLINK" , x "AF_PACKET" , \
x "AF_ASH" , x "AF_ECONET" , x "AF_ATMSVC" , \
x "AF_RDS" , x "AF_SNA" , x "AF_IRDA" , \
x "AF_PPPOX" , x "AF_WANPIPE" , x "AF_LLC" , \
x "27" , x "28" , x "AF_CAN" , \
x "AF_TIPC" , x "AF_BLUETOOTH", x "IUCV" , \
x "AF_RXRPC" , x "AF_ISDN" , x "AF_PHONET" , \
x "AF_IEEE802154", x "AF_CAIF" , x "AF_ALG" , \
x "AF_NFC" , x "AF_VSOCK" , x "AF_KCM" , \
x "AF_QIPCRTR", x "AF_SMC" , x "AF_XDP" , \
x "AF_MCTP" , \
x "AF_MAX"
staticint sock_bindtoindex_locked(struct sock *sk, int ifindex)
{ int ret = -ENOPROTOOPT; #ifdef CONFIG_NETDEVICES struct net *net = sock_net(sk);
/* Sorry... */
ret = -EPERM; if (sk->sk_bound_dev_if && !ns_capable(net->user_ns, CAP_NET_RAW)) goto out;
ret = -EINVAL; if (ifindex < 0) goto out;
/* Paired with all READ_ONCE() done locklessly. */
WRITE_ONCE(sk->sk_bound_dev_if, ifindex);
if (sk->sk_prot->rehash)
sk->sk_prot->rehash(sk);
sk_dst_reset(sk);
ret = 0;
out: #endif
return ret;
}
int sock_bindtoindex(struct sock *sk, int ifindex, bool lock_sk)
{ int ret;
if (lock_sk)
lock_sock(sk);
ret = sock_bindtoindex_locked(sk, ifindex); if (lock_sk)
release_sock(sk);
return ret;
}
EXPORT_SYMBOL(sock_bindtoindex);
staticint sock_setbindtodevice(struct sock *sk, sockptr_t optval, int optlen)
{ int ret = -ENOPROTOOPT; #ifdef CONFIG_NETDEVICES struct net *net = sock_net(sk); char devname[IFNAMSIZ]; int index;
ret = -EINVAL; if (optlen < 0) goto out;
/* Bind this socket to a particular device like "eth0", *asspecifiedinthepassedinterfacename.Ifthe *nameis""ortheoptionlengthiszerothesocket *isnotbound.
*/ if (optlen > IFNAMSIZ - 1)
optlen = IFNAMSIZ - 1;
memset(devname, 0, sizeof(devname));
ret = -EFAULT; if (copy_from_sockptr(devname, optval, optlen)) goto out;
index = 0; if (devname[0] != '\0') { struct net_device *dev;
rcu_read_lock();
dev = dev_get_by_name_rcu(net, devname); if (dev)
index = dev->ifindex;
rcu_read_unlock();
ret = -ENODEV; if (!dev) goto out;
}
sockopt_lock_sock(sk);
ret = sock_bindtoindex_locked(sk, index);
sockopt_release_sock(sk);
out: #endif
return ret;
}
staticint sock_getbindtodevice(struct sock *sk, sockptr_t optval,
sockptr_t optlen, int len)
{ int ret = -ENOPROTOOPT; #ifdef CONFIG_NETDEVICES int bound_dev_if = READ_ONCE(sk->sk_bound_dev_if); struct net *net = sock_net(sk); char devname[IFNAMSIZ];
if (bound_dev_if == 0) {
len = 0; goto zero;
}
ret = -EINVAL; if (len < IFNAMSIZ) goto out;
ret = netdev_get_name(net, devname, bound_dev_if); if (ret) goto out;
len = strlen(devname) + 1;
ret = -EFAULT; if (copy_to_sockptr(optval, devname, len)) goto out;
zero:
ret = -EFAULT; if (copy_to_sockptr(optlen, &len, sizeof(int))) goto out;
ret = 0;
out: #endif
return ret;
}
bool sk_mc_loop(conststruct sock *sk)
{ if (dev_recursion_level()) returnfalse; if (!sk) returntrue; /* IPV6_ADDRFORM can change sk->sk_family under us. */ switch (READ_ONCE(sk->sk_family)) { case AF_INET: return inet_test_bit(MC_LOOP, sk); #if IS_ENABLED(CONFIG_IPV6) case AF_INET6: return inet6_test_bit(MC6_LOOP, sk); #endif
}
WARN_ON_ONCE(1); returntrue;
}
EXPORT_SYMBOL(sk_mc_loop);
void sock_set_timestamp(struct sock *sk, int optname, bool valbool)
{ switch (optname) { case SO_TIMESTAMP_OLD:
__sock_set_timestamps(sk, valbool, false, false); break; case SO_TIMESTAMP_NEW:
__sock_set_timestamps(sk, valbool, true, false); break; case SO_TIMESTAMPNS_OLD:
__sock_set_timestamps(sk, valbool, false, true); break; case SO_TIMESTAMPNS_NEW:
__sock_set_timestamps(sk, valbool, true, true); break;
}
}
staticint sock_timestamping_bind_phc(struct sock *sk, int phc_index)
{ struct net *net = sock_net(sk); struct net_device *dev = NULL; bool match = false; int *vclock_index; int i, num;
if (sk->sk_bound_dev_if)
dev = dev_get_by_index(net, sk->sk_bound_dev_if);
if (!dev) {
pr_err("%s: sock not bind to device\n", __func__); return -EOPNOTSUPP;
}
num = ethtool_get_phc_vclocks(dev, &vclock_index);
dev_put(dev);
for (i = 0; i < num; i++) { if (*(vclock_index + i) == phc_index) {
match = true; break;
}
}
if (num > 0)
kfree(vclock_index);
if (!match) return -EINVAL;
WRITE_ONCE(sk->sk_bind_phc, phc_index);
return0;
}
int sock_set_timestamping(struct sock *sk, int optname, struct so_timestamping timestamping)
{ int val = timestamping.flags; int ret;
if (val & ~SOF_TIMESTAMPING_MASK) return -EINVAL;
if (val & SOF_TIMESTAMPING_OPT_ID_TCP &&
!(val & SOF_TIMESTAMPING_OPT_ID)) return -EINVAL;
if (val & SOF_TIMESTAMPING_OPT_ID &&
!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) { if (sk_is_tcp(sk)) { if ((1 << sk->sk_state) &
(TCPF_CLOSE | TCPF_LISTEN)) return -EINVAL; if (val & SOF_TIMESTAMPING_OPT_ID_TCP)
atomic_set(&sk->sk_tskey, tcp_sk(sk)->write_seq); else
atomic_set(&sk->sk_tskey, tcp_sk(sk)->snd_una);
} else {
atomic_set(&sk->sk_tskey, 0);
}
}
if (val & SOF_TIMESTAMPING_OPT_STATS &&
!(val & SOF_TIMESTAMPING_OPT_TSONLY)) return -EINVAL;
if (val & SOF_TIMESTAMPING_BIND_PHC) {
ret = sock_timestamping_bind_phc(sk, timestamping.bind_phc); if (ret) return ret;
}
staticvoid __sock_set_rcvbuf(struct sock *sk, int val)
{ /* Ensure val * 2 fits into an int, to prevent max_t() from treating it *asanegativevalue.
*/
val = min_t(int, val, INT_MAX / 2);
sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
/* We double it on the way in to account for "struct sk_buff" etc. *overhead.ApplicationsassumethattheSO_RCVBUFsettingtheymake *willallowthatmuchactualdatatobereceivedonthatsocket. * *Applicationsareunawarethat"structsk_buff"andotheroverheads *allocatefromthereceivebufferduringsocketbufferallocation. * *Andafterconsideringthepossiblealternatives,returningthevalue *weactuallyusedingetsockoptisthemostdesirablebehavior.
*/
WRITE_ONCE(sk->sk_rcvbuf, max_t(int, val * 2, SOCK_MIN_RCVBUF));
}
staticvoid sock_release_reserved_memory(struct sock *sk, int bytes)
{ /* Round down bytes to multiple of pages */
bytes = round_down(bytes, PAGE_SIZE);
staticint sock_reserve_memory(struct sock *sk, int bytes)
{ long allocated; bool charged; int pages;
if (!mem_cgroup_sockets_enabled || !sk->sk_memcg || !sk_has_account(sk)) return -EOPNOTSUPP;
if (!bytes) return0;
pages = sk_mem_pages(bytes);
/* pre-charge to memcg */
charged = mem_cgroup_charge_skmem(sk->sk_memcg, pages,
GFP_KERNEL | __GFP_RETRY_MAYFAIL); if (!charged) return -ENOMEM;
/* pre-charge to forward_alloc */
sk_memory_allocated_add(sk, pages);
allocated = sk_memory_allocated(sk); /* If the system goes into memory pressure with this *precharge,giveupandreturnerror.
*/ if (allocated > sk_prot_mem_limits(sk, 1)) {
sk_memory_allocated_sub(sk, pages);
mem_cgroup_uncharge_skmem(sk->sk_memcg, pages); return -ENOMEM;
}
sk_forward_alloc_add(sk, pages << PAGE_SHIFT);
/* This is the number of tokens and frags that the user can SO_DEVMEM_DONTNEED *in1syscall.Thelimitexiststolimittheamountofmemorythekernel *allocatestocopythesetokens,andtopreventloopingoverthefragsfor *toolong.
*/ #define MAX_DONTNEED_TOKENS 128 #define MAX_DONTNEED_FRAGS 1024
static noinline_for_stack int
sock_devmem_dontneed(struct sock *sk, sockptr_t optval, unsignedint optlen)
{ unsignedint num_tokens, i, j, k, netmem_num = 0; struct dmabuf_token *tokens; int ret = 0, num_frags = 0;
netmem_ref netmems[16];
if (copy_from_sockptr(tokens, optval, optlen)) {
kvfree(tokens); return -EFAULT;
}
xa_lock_bh(&sk->sk_user_frags); for (i = 0; i < num_tokens; i++) { for (j = 0; j < tokens[i].token_count; j++) { if (++num_frags > MAX_DONTNEED_FRAGS) goto frag_limit_reached;
if (!netmem || WARN_ON_ONCE(!netmem_is_net_iov(netmem))) continue;
netmems[netmem_num++] = netmem; if (netmem_num == ARRAY_SIZE(netmems)) {
xa_unlock_bh(&sk->sk_user_frags); for (k = 0; k < netmem_num; k++)
WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
netmem_num = 0;
xa_lock_bh(&sk->sk_user_frags);
}
ret++;
}
}
frag_limit_reached:
xa_unlock_bh(&sk->sk_user_frags); for (k = 0; k < netmem_num; k++)
WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
kvfree(tokens); return ret;
} #endif
void sockopt_lock_sock(struct sock *sk)
{ /* When current->bpf_ctx is set, the setsockopt is called from *abpfprog.bpfhasensuredthesklockhasbeen *acquiredbeforecallingsetsockopt().
*/ if (has_current_bpf_ctx()) return;
int sk_setsockopt(struct sock *sk, int level, int optname,
sockptr_t optval, unsignedint optlen)
{ struct so_timestamping timestamping; struct socket *sock = sk->sk_socket; struct sock_txtime sk_txtime; int val; int valbool; struct linger ling; int ret = 0;
/* *Optionswithoutarguments
*/
if (optname == SO_BINDTODEVICE) return sock_setbindtodevice(sk, optval, optlen);
if (optlen < sizeof(int)) return -EINVAL;
if (copy_from_sockptr(&val, optval, sizeof(val))) return -EFAULT;
valbool = val ? 1 : 0;
/* handle options which do not require locking the socket. */ switch (optname) { case SO_PRIORITY: if (sk_set_prio_allowed(sk, val)) {
sock_set_priority(sk, val); return0;
} return -EPERM; case SO_TYPE: case SO_PROTOCOL: case SO_DOMAIN: case SO_ERROR: return -ENOPROTOOPT; #ifdef CONFIG_NET_RX_BUSY_POLL case SO_BUSY_POLL: if (val < 0) return -EINVAL;
WRITE_ONCE(sk->sk_ll_usec, val); return0; case SO_PREFER_BUSY_POLL: if (valbool && !sockopt_capable(CAP_NET_ADMIN)) return -EPERM;
WRITE_ONCE(sk->sk_prefer_busy_poll, valbool); return0; case SO_BUSY_POLL_BUDGET: if (val > READ_ONCE(sk->sk_busy_poll_budget) &&
!sockopt_capable(CAP_NET_ADMIN)) return -EPERM; if (val < 0 || val > U16_MAX) return -EINVAL;
WRITE_ONCE(sk->sk_busy_poll_budget, val); return0; #endif case SO_MAX_PACING_RATE:
{ unsignedlong ulval = (val == ~0U) ? ~0UL : (unsignedint)val; unsignedlong pacing_rate;
if (sizeof(ulval) != sizeof(val) &&
optlen >= sizeof(ulval) &&
copy_from_sockptr(&ulval, optval, sizeof(ulval))) { return -EFAULT;
} if (ulval != ~0UL)
cmpxchg(&sk->sk_pacing_status,
SK_PACING_NONE,
SK_PACING_NEEDED); /* Pairs with READ_ONCE() from sk_getsockopt() */
WRITE_ONCE(sk->sk_max_pacing_rate, ulval);
pacing_rate = READ_ONCE(sk->sk_pacing_rate); if (ulval < pacing_rate)
WRITE_ONCE(sk->sk_pacing_rate, ulval); return0;
} case SO_TXREHASH: if (!sk_is_tcp(sk)) return -EOPNOTSUPP; if (val < -1 || val > 1) return -EINVAL; if ((u8)val == SOCK_TXREHASH_DEFAULT)
val = READ_ONCE(sock_net(sk)->core.sysctl_txrehash); /* Paired with READ_ONCE() in tcp_rtx_synack() *andsk_getsockopt().
*/
WRITE_ONCE(sk->sk_txrehash, (u8)val); return0; case SO_PEEK_OFF:
{ int (*set_peek_off)(struct sock *sk, int val);
set_peek_off = READ_ONCE(sock->ops)->set_peek_off; if (set_peek_off)
ret = set_peek_off(sk, val); else
ret = -EOPNOTSUPP; return ret;
} #ifdef CONFIG_PAGE_POOL case SO_DEVMEM_DONTNEED: return sock_devmem_dontneed(sk, optval, optlen); #endif case SO_SNDTIMEO_OLD: case SO_SNDTIMEO_NEW: return sock_set_timeout(&sk->sk_sndtimeo, optval,
optlen, optname == SO_SNDTIMEO_OLD); case SO_RCVTIMEO_OLD: case SO_RCVTIMEO_NEW: return sock_set_timeout(&sk->sk_rcvtimeo, optval,
optlen, optname == SO_RCVTIMEO_OLD);
}
sockopt_lock_sock(sk);
switch (optname) { case SO_DEBUG: if (val && !sockopt_capable(CAP_NET_ADMIN))
ret = -EACCES; else
sock_valbool_flag(sk, SOCK_DBG, valbool); break; case SO_REUSEADDR:
sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE); break; case SO_REUSEPORT: if (valbool && !sk_is_inet(sk))
ret = -EOPNOTSUPP; else
sk->sk_reuseport = valbool; break; case SO_DONTROUTE:
sock_valbool_flag(sk, SOCK_LOCALROUTE, valbool);
sk_dst_reset(sk); break; case SO_BROADCAST:
sock_valbool_flag(sk, SOCK_BROADCAST, valbool); break; case SO_SNDBUF: /* Don't error on this BSD doesn't and if you think *aboutitthisisright.Otherwiseappshaveto *play'guessthebiggestsize'games.RCVBUF/SNDBUF *aretreatedinBSDashints
*/
val = min_t(u32, val, READ_ONCE(sysctl_wmem_max));
set_sndbuf: /* Ensure val * 2 fits into an int, to prevent max_t() *fromtreatingitasanegativevalue.
*/
val = min_t(int, val, INT_MAX / 2);
sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
WRITE_ONCE(sk->sk_sndbuf,
max_t(int, val * 2, SOCK_MIN_SNDBUF)); /* Wake up sending tasks if we upped the value. */
sk->sk_write_space(sk); break;
case SO_SNDBUFFORCE: if (!sockopt_capable(CAP_NET_ADMIN)) {
ret = -EPERM; break;
}
/* No negative values (to prevent underflow, as val will be *multipliedby2).
*/ if (val < 0)
val = 0; goto set_sndbuf;
case SO_RCVBUF: /* Don't error on this BSD doesn't and if you think *aboutitthisisright.Otherwiseappshaveto *play'guessthebiggestsize'games.RCVBUF/SNDBUF *aretreatedinBSDashints
*/
__sock_set_rcvbuf(sk, min_t(u32, val, READ_ONCE(sysctl_rmem_max))); break;
case SO_RCVBUFFORCE: if (!sockopt_capable(CAP_NET_ADMIN)) {
ret = -EPERM; break;
}
/* No negative values (to prevent underflow, as val will be *multipliedby2).
*/
__sock_set_rcvbuf(sk, max(val, 0)); break;
case SO_KEEPALIVE: if (sk->sk_prot->keepalive)
sk->sk_prot->keepalive(sk, valbool);
sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool); break;
case SO_OOBINLINE:
sock_valbool_flag(sk, SOCK_URGINLINE, valbool); break;
case SO_NO_CHECK:
sk->sk_no_check_tx = valbool; break;
case SO_LINGER: if (optlen < sizeof(ling)) {
ret = -EINVAL; /* 1003.1g */ break;
} if (copy_from_sockptr(&ling, optval, sizeof(ling))) {
ret = -EFAULT; break;
} if (!ling.l_onoff) {
sock_reset_flag(sk, SOCK_LINGER);
} else { unsignedlong t_sec = ling.l_linger;
case SO_TIMESTAMP_OLD: case SO_TIMESTAMP_NEW: case SO_TIMESTAMPNS_OLD: case SO_TIMESTAMPNS_NEW:
sock_set_timestamp(sk, optname, valbool); break;
case SO_TIMESTAMPING_NEW: case SO_TIMESTAMPING_OLD: if (optlen == sizeof(timestamping)) { if (copy_from_sockptr(×tamping, optval, sizeof(timestamping))) {
ret = -EFAULT; break;
}
} else {
memset(×tamping, 0, sizeof(timestamping));
timestamping.flags = val;
}
ret = sock_set_timestamping(sk, optname, timestamping); break;
case SO_RCVLOWAT:
{ int (*set_rcvlowat)(struct sock *sk, int val) = NULL;
if (val < 0)
val = INT_MAX; if (sock)
set_rcvlowat = READ_ONCE(sock->ops)->set_rcvlowat; if (set_rcvlowat)
ret = set_rcvlowat(sk, val); else
WRITE_ONCE(sk->sk_rcvlowat, val ? : 1); break;
} case SO_ATTACH_FILTER: { struct sock_fprog fprog;
ret = copy_bpf_fprog_from_user(&fprog, optval, optlen); if (!ret)
ret = sk_attach_filter(&fprog, sk); break;
} case SO_ATTACH_BPF:
ret = -EINVAL; if (optlen == sizeof(u32)) {
u32 ufd;
ret = -EFAULT; if (copy_from_sockptr(&ufd, optval, sizeof(ufd))) break;
ret = sk_attach_bpf(ufd, sk);
} break;
case SO_ATTACH_REUSEPORT_CBPF: { struct sock_fprog fprog;
ret = copy_bpf_fprog_from_user(&fprog, optval, optlen); if (!ret)
ret = sk_reuseport_attach_filter(&fprog, sk); break;
} case SO_ATTACH_REUSEPORT_EBPF:
ret = -EINVAL; if (optlen == sizeof(u32)) {
u32 ufd;
ret = -EFAULT; if (copy_from_sockptr(&ufd, optval, sizeof(ufd))) break;
ret = sk_reuseport_attach_bpf(ufd, sk);
} break;
case SO_DETACH_REUSEPORT_BPF:
ret = reuseport_detach_prog(sk); break;
case SO_DETACH_FILTER:
ret = sk_detach_filter(sk); break;
case SO_LOCK_FILTER: if (sock_flag(sk, SOCK_FILTER_LOCKED) && !valbool)
ret = -EPERM; else
sock_valbool_flag(sk, SOCK_FILTER_LOCKED, valbool); break;
case SO_MARK: if (!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
ret = -EPERM; break;
}
__sock_set_mark(sk, val); break; case SO_RCVMARK:
sock_valbool_flag(sk, SOCK_RCVMARK, valbool); break;
case SO_RCVPRIORITY:
sock_valbool_flag(sk, SOCK_RCVPRIORITY, valbool); break;
case SO_RXQ_OVFL:
sock_valbool_flag(sk, SOCK_RXQ_OVFL, valbool); break;
case SO_WIFI_STATUS:
sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool); break;
case SO_NOFCS:
sock_valbool_flag(sk, SOCK_NOFCS, valbool); break;
case SO_SELECT_ERR_QUEUE:
sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool); break;
case SO_PASSCRED: if (sk_may_scm_recv(sk))
sk->sk_scm_credentials = valbool; else
ret = -EOPNOTSUPP; break;
case SO_PASSSEC: if (IS_ENABLED(CONFIG_SECURITY_NETWORK) && sk_may_scm_recv(sk))
sk->sk_scm_security = valbool; else
ret = -EOPNOTSUPP; break;
case SO_PASSPIDFD: if (sk_is_unix(sk))
sk->sk_scm_pidfd = valbool; else
ret = -EOPNOTSUPP; break;
case SO_PASSRIGHTS: if (sk_is_unix(sk))
sk->sk_scm_rights = valbool; else
ret = -EOPNOTSUPP; break;
case SO_INCOMING_CPU:
reuseport_update_incoming_cpu(sk, val); break;
case SO_CNX_ADVICE: if (val == 1)
dst_negative_advice(sk); break;
case SO_ZEROCOPY: if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6) { if (!(sk_is_tcp(sk) ||
(sk->sk_type == SOCK_DGRAM &&
sk->sk_protocol == IPPROTO_UDP)))
ret = -EOPNOTSUPP;
} elseif (sk->sk_family != PF_RDS) {
ret = -EOPNOTSUPP;
} if (!ret) { if (val < 0 || val > 1)
ret = -EINVAL; else
sock_valbool_flag(sk, SOCK_ZEROCOPY, valbool);
} break;
case SO_TXTIME: if (optlen != sizeof(struct sock_txtime)) {
ret = -EINVAL; break;
} elseif (copy_from_sockptr(&sk_txtime, optval, sizeof(struct sock_txtime))) {
ret = -EFAULT; break;
} elseif (sk_txtime.flags & ~SOF_TXTIME_FLAGS_MASK) {
ret = -EINVAL; break;
} /* CLOCK_MONOTONIC is only used by sch_fq, and this packet *schedulerhasenoughsafeguards.
*/ if (sk_txtime.clockid != CLOCK_MONOTONIC &&
!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
ret = -EPERM; break;
}
ret = sockopt_validate_clockid(sk_txtime.clockid); if (ret) break;
case SO_TIMESTAMPNS_OLD:
v.val = sock_flag(sk, SOCK_RCVTSTAMPNS) && !sock_flag(sk, SOCK_TSTAMP_NEW); break;
case SO_TIMESTAMP_NEW:
v.val = sock_flag(sk, SOCK_RCVTSTAMP) && sock_flag(sk, SOCK_TSTAMP_NEW); break;
case SO_TIMESTAMPNS_NEW:
v.val = sock_flag(sk, SOCK_RCVTSTAMPNS) && sock_flag(sk, SOCK_TSTAMP_NEW); break;
case SO_TIMESTAMPING_OLD: case SO_TIMESTAMPING_NEW:
lv = sizeof(v.timestamping); /* For the later-added case SO_TIMESTAMPING_NEW: Be strict about only *returningtheflagswhentheyweresetthroughthesameoption. *Don'tchangethebeviourfortheoldcaseSO_TIMESTAMPING_OLD.
*/ if (optname == SO_TIMESTAMPING_OLD || sock_flag(sk, SOCK_TSTAMP_NEW)) {
v.timestamping.flags = READ_ONCE(sk->sk_tsflags);
v.timestamping.bind_phc = READ_ONCE(sk->sk_bind_phc);
} break;
case SO_RCVTIMEO_OLD: case SO_RCVTIMEO_NEW:
lv = sock_get_timeout(READ_ONCE(sk->sk_rcvtimeo), &v,
SO_RCVTIMEO_OLD == optname); break;
case SO_SNDTIMEO_OLD: case SO_SNDTIMEO_NEW:
lv = sock_get_timeout(READ_ONCE(sk->sk_sndtimeo), &v,
SO_SNDTIMEO_OLD == optname); break;
case SO_RCVLOWAT:
v.val = READ_ONCE(sk->sk_rcvlowat); break;
case SO_SNDLOWAT:
v.val = 1; break;
case SO_PASSCRED: if (!sk_may_scm_recv(sk)) return -EOPNOTSUPP;
v.val = sk->sk_scm_credentials; break;
case SO_PASSPIDFD: if (!sk_is_unix(sk)) return -EOPNOTSUPP;
v.val = sk->sk_scm_pidfd; break;
case SO_PASSRIGHTS: if (!sk_is_unix(sk)) return -EOPNOTSUPP;
v.val = sk->sk_scm_rights; break;
case SO_PEERCRED:
{ struct ucred peercred; if (len > sizeof(peercred))
len = sizeof(peercred);
/* The use of PIDFD_STALE requires stashing of struct pid *onpidfswithpidfs_register_pid()andonlyAF_UNIX *werepreparedforthis.
*/ if (sk->sk_family == AF_UNIX)
flags = PIDFD_STALE;
case SO_PEERGROUPS:
{ conststruct cred *cred; int ret, n;
cred = sk_get_peer_cred(sk); if (!cred) return -ENODATA;
n = cred->group_info->ngroups; if (len < n * sizeof(gid_t)) {
len = n * sizeof(gid_t);
put_cred(cred); return copy_to_sockptr(optlen, &len, sizeof(int)) ? -EFAULT : -ERANGE;
}
len = n * sizeof(gid_t);
ret = groups_to_user(optval, cred->group_info);
put_cred(cred); if (ret) return ret; goto lenout;
}
case SO_PEERNAME:
{ struct sockaddr_storage address;
lv = READ_ONCE(sock->ops)->getname(sock, (struct sockaddr *)&address, 2); if (lv < 0) return -ENOTCONN; if (lv < len) return -EINVAL; if (copy_to_sockptr(optval, &address, len)) return -EFAULT; goto lenout;
}
/* Dubious BSD thing... Probably nobody even uses it, but *theUNIXstandardwantsitforwhateverreason...-DaveM
*/ case SO_ACCEPTCONN:
v.val = sk->sk_state == TCP_LISTEN; break;
case SO_PASSSEC: if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) || !sk_may_scm_recv(sk)) return -EOPNOTSUPP;
v.val = sk->sk_scm_security; break;
case SO_PEERSEC: return security_socket_getpeersec_stream(sock,
optval, optlen, len);
case SO_MARK:
v.val = READ_ONCE(sk->sk_mark); break;
case SO_RCVMARK:
v.val = sock_flag(sk, SOCK_RCVMARK); break;
case SO_RCVPRIORITY:
v.val = sock_flag(sk, SOCK_RCVPRIORITY); break;
case SO_RXQ_OVFL:
v.val = sock_flag(sk, SOCK_RXQ_OVFL); break;
case SO_WIFI_STATUS:
v.val = sock_flag(sk, SOCK_WIFI_STATUS); break;
case SO_PEEK_OFF: if (!READ_ONCE(sock->ops)->set_peek_off) return -EOPNOTSUPP;
/* Sockets having SOCK_RCU_FREE will call this function after one RCU *graceperiod.ThisisthecaseforUDPsocketsandTCPlisteners.
*/ staticvoid __sk_destruct(struct rcu_head *head)
{ struct sock *sk = container_of(head, struct sock, sk_rcu); struct net *net = sock_net(sk); struct sk_filter *filter;
/* sk->sk_memcg will be populated at accept() time */
newsk->sk_memcg = NULL;
cgroup_sk_clone(&newsk->sk_cgrp_data);
rcu_read_lock();
filter = rcu_dereference(sk->sk_filter); if (filter != NULL) /* though it's an empty new sock, the charging may fail *ifsysctl_optmem_maxwaschangedbetweencreationof *originalsocketandcloning
*/
is_charged = sk_filter_charge(newsk, filter);
RCU_INIT_POINTER(newsk->sk_filter, filter);
rcu_read_unlock();
if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk, sk))) { /* We need to make sure that we don't uncharge the new *socketifwecouldn'tchargeitinthefirstplace *asotherwiseweunchargetheparent'sfilter.
*/ if (!is_charged)
RCU_INIT_POINTER(newsk->sk_filter, NULL);
goto free;
}
RCU_INIT_POINTER(newsk->sk_reuseport_cb, NULL);
if (bpf_sk_storage_clone(sk, newsk)) goto free;
/* Clear sk_user_data if parent had the pointer tagged *asnotsuitableforcopyingwhencloning.
*/ if (sk_user_data_is_nocopy(newsk))
newsk->sk_user_data = NULL;
/* Before updating sk_refcnt, we must commit prior changes to memory *(Documentation/RCU/rculist_nulls.rstfordetails)
*/
smp_wmb();
refcount_set(&newsk->sk_refcnt, 2);
if (newsk->sk_prot->sockets_allocated)
sk_sockets_allocated_inc(newsk);
if (sock_needs_netstamp(sk) && newsk->sk_flags & SK_FLAGS_TIMESTAMP)
net_enable_timestamp();
out: return newsk;
free: /* It is still raw copy of parent, so invalidate *destructorandmakeplainsk_free()
*/
newsk->sk_destruct = NULL;
bh_unlock_sock(newsk);
sk_free(newsk);
newsk = NULL; goto out;
}
EXPORT_SYMBOL_GPL(sk_clone_lock);
/* This variant of sock_wfree() is used by TCP, *sinceitsetsSOCK_USE_WRITE_QUEUE.
*/ void __sock_wfree(struct sk_buff *skb)
{ struct sock *sk = skb->sk;
if (refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc))
__sk_free(sk);
}
/* This helper is used by netem, as it can hold packets in its *delayqueue.Wewanttoallowtheownersockettosendmore *packets,asiftheywerealreadyTXcompletedbyatypicaldriver. *Butwealsowanttokeepskb->sksetbecausesomepacketschedulers *relyonit(sch_fqforexample).
*/ void skb_orphan_partial(struct sk_buff *skb)
{ if (skb_is_tcp_pure_ack(skb)) return;
if (can_skb_orphan_partial(skb) && skb_set_owner_sk_safe(skb, skb->sk)) return;
/* small safe race: SKB_TRUESIZE may differ from final skb->truesize */ if (atomic_read(&sk->sk_omem_alloc) + SKB_TRUESIZE(size) >
READ_ONCE(sock_net(sk)->core.sysctl_optmem_max)) return NULL;
skb = alloc_skb(size, priority); if (!skb) return NULL;
/* *Allocateamemoryblockfromthesocket'soptionmemorybuffer.
*/ void *sock_kmalloc(struct sock *sk, int size, gfp_t priority)
{ int optmem_max = READ_ONCE(sock_net(sk)->core.sysctl_optmem_max);
if ((unsignedint)size <= optmem_max &&
atomic_read(&sk->sk_omem_alloc) + size < optmem_max) { void *mem; /* First do the add, to avoid the race if kmalloc *mightsleep.
*/
atomic_add(size, &sk->sk_omem_alloc);
mem = kmalloc(size, priority); if (mem) return mem;
atomic_sub(size, &sk->sk_omem_alloc);
} return NULL;
}
EXPORT_SYMBOL(sock_kmalloc);
/* It is almost wait_for_tcp_memory minus release_sock/lock_sock. Ithink,theselocksshouldberemovedfordatagramsockets.
*/ staticlong sock_wait_for_wmem(struct sock *sk, long timeo)
{
DEFINE_WAIT(wait);
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); for (;;) { if (!timeo) break; if (signal_pending(current)) break;
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); if (refcount_read(&sk->sk_wmem_alloc) < READ_ONCE(sk->sk_sndbuf)) break; if (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) break; if (READ_ONCE(sk->sk_err)) break;
timeo = schedule_timeout(timeo);
}
finish_wait(sk_sleep(sk), &wait); return timeo;
}
/* *Genericsend/receivebufferhandlers
*/
struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsignedlong header_len, unsignedlong data_len, int noblock, int *errcode, int max_page_order)
{ struct sk_buff *skb; long timeo; int err;
timeo = sock_sndtimeo(sk, noblock); for (;;) {
err = sock_error(sk); if (err != 0) goto failure;
err = -EPIPE; if (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) goto failure;
if (sk_wmem_alloc_get(sk) < READ_ONCE(sk->sk_sndbuf)) break;
if (sk->sk_type == SOCK_STREAM) { if (sk->sk_wmem_queued < wmem0) return1;
} elseif (refcount_read(&sk->sk_wmem_alloc) < wmem0) { return1;
}
}
if (sk_has_memory_pressure(sk)) {
u64 alloc;
/* The following 'average' heuristic is within the *scopeofglobalaccounting,soitonlymakes *senseforglobalmemorypressure.
*/ if (!sk_under_global_memory_pressure(sk)) return1;
/* Try to be fair among all the sockets under global *pressurebyallowingtheonesthatbelowaverage *usagetoraise.
*/
alloc = sk_sockets_allocated_read_positive(sk); if (sk_prot_mem_limits(sk, 2) > alloc *
sk_mem_pages(sk->sk_wmem_queued +
atomic_read(&sk->sk_rmem_alloc) +
sk->sk_forward_alloc)) return1;
}
suppress_allocation:
if (kind == SK_MEM_SEND && sk->sk_type == SOCK_STREAM) {
sk_stream_moderate_sndbuf(sk);
/* Fail only if socket is _under_ its sndbuf. *Inthiscasewecannotblock,sothatwehavetofail.
*/ if (sk->sk_wmem_queued + size >= sk->sk_sndbuf) { /* Force charge with __GFP_NOFAIL */ if (memcg && !charged) {
mem_cgroup_charge_skmem(memcg, amt,
gfp_memcg_charge() | __GFP_NOFAIL);
} return1;
}
}
if (memcg && charged)
mem_cgroup_uncharge_skmem(memcg, amt);
return0;
}
/** *__sk_mem_schedule-increasesk_forward_allocandmemory_allocated *@sk:socket *@size:memorysizetoallocate *@kind:allocationtype * *IfkindisSK_MEM_SEND,itmeanswmemallocation.Otherwiseitmeans *rmemallocation.Thisfunctionassumesthatprotocolswhichhave *memory_pressureusesk_wmem_queuedaswritebufferaccounting.
*/ int __sk_mem_schedule(struct sock *sk, int size, int kind)
{ int ret, amt = sk_mem_pages(size);
sk_forward_alloc_add(sk, amt << PAGE_SHIFT);
ret = __sk_mem_raise_allocated(sk, size, amt, kind); if (!ret)
sk_forward_alloc_add(sk, -(amt << PAGE_SHIFT)); return ret;
}
EXPORT_SYMBOL(__sk_mem_schedule);
/* Do not wake up a writer until he can make "significant" *progress.--DaveM
*/ if (sock_writeable(sk)) {
wq = rcu_dereference(sk->sk_wq); if (skwq_has_sleeper(wq))
wake_up_interruptible_sync_poll(&wq->wait, EPOLLOUT |
EPOLLWRNORM | EPOLLWRBAND);
/* Should agree with poll, otherwise some programs break */
sk_wake_async_rcu(sk, SOCK_WAKE_SPACE, POLL_OUT);
}
rcu_read_unlock();
}
/* An optimised version of sock_def_write_space(), should only be called *forSOCK_RCU_FREEsocketsunderRCUreadsectionandafterputting *->sk_wmem_alloc.
*/ staticvoid sock_def_write_space_wfree(struct sock *sk)
{ /* Do not wake up a writer until he can make "significant" *progress.--DaveM
*/ if (sock_writeable(sk)) { struct socket_wq *wq = rcu_dereference(sk->sk_wq);
/* rely on refcount_sub from sock_wfree() */
smp_mb__after_atomic(); if (wq && waitqueue_active(&wq->wait))
wake_up_interruptible_sync_poll(&wq->wait, EPOLLOUT |
EPOLLWRNORM | EPOLLWRBAND);
/* Should agree with poll, otherwise some programs break */
sk_wake_async_rcu(sk, SOCK_WAKE_SPACE, POLL_OUT);
}
}
staticvoid sock_def_destruct(struct sock *sk)
{
}
void sk_send_sigurg(struct sock *sk)
{ if (sk->sk_socket && sk->sk_socket->file) if (send_sigurg(sk->sk_socket->file))
sk_wake_async(sk, SOCK_WAKE_URG, POLL_PRI);
}
EXPORT_SYMBOL(sk_send_sigurg);
int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, int level, int type)
{ struct sock_exterr_skb *serr; struct sk_buff *skb; int copied, err;
if (req_prot_init(prot)) goto out_free_request_sock_slab;
if (tw_prot_init(prot)) goto out_free_timewait_sock_slab;
}
mutex_lock(&proto_list_mutex);
ret = assign_proto_idx(prot); if (ret) {
mutex_unlock(&proto_list_mutex); goto out_free_timewait_sock_slab;
}
list_add(&prot->node, &proto_list);
mutex_unlock(&proto_list_mutex); return ret;
out_free_timewait_sock_slab: if (alloc_slab)
tw_prot_cleanup(prot->twsk_prot);
out_free_request_sock_slab: if (alloc_slab) {
req_prot_cleanup(prot->rsk_prot);
staticint proto_seq_show(struct seq_file *seq, void *v)
{ if (v == &proto_list)
seq_printf(seq, "%-9s %-4s %-8s %-6s %-5s %-7s %-4s %-10s %s", "protocol", "size", "sockets", "memory", "press", "maxhdr", "slab", "module", "cl co di ac io in de sh ss gs se re bi br ha uh gp em\n"); else
proto_seq_printf(seq, list_entry(v, struct proto, node)); return0;
}
int sock_bind_add(struct sock *sk, struct sockaddr *addr, int addr_len)
{ if (!sk->sk_prot->bind_add) return -EOPNOTSUPP; return sk->sk_prot->bind_add(sk, addr, addr_len);
}
EXPORT_SYMBOL(sock_bind_add);
/* Copy 'size' bytes from userspace and return `size` back to userspace */ int sock_ioctl_inout(struct sock *sk, unsignedint cmd, void __user *arg, void *karg, size_t size)
{ int ret;
if (copy_from_user(karg, arg, size)) return -EFAULT;
ret = READ_ONCE(sk->sk_prot)->ioctl(sk, cmd, karg); if (ret) return ret;
if (copy_to_user(arg, karg, size)) return -EFAULT;
return0;
}
EXPORT_SYMBOL(sock_ioctl_inout);
/* This is the most common ioctl prep function, where the result (4 bytes) is *copiedbacktouserspaceiftheioctl()returnssuccessfully.Noinputis *copiedfromuserspaceasinputargument.
*/ staticint sock_ioctl_out(struct sock *sk, unsignedint cmd, void __user *arg)
{ int ret, karg = 0;
ret = READ_ONCE(sk->sk_prot)->ioctl(sk, cmd, &karg); if (ret) return ret;
return put_user(karg, (int __user *)arg);
}
/* A wrapper around sock ioctls, which copies the data from userspace *(dependingontheprotocol/ioctl),andcopiesbacktheresulttouserspace. *Themainmotivationforthisfunctionistopasskernelmemorytothe *protocolioctlcallbacks,insteadofuserspacememory.
*/ int sk_ioctl(struct sock *sk, unsignedint cmd, void __user *arg)
{ int rc = 1;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.148Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤
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.