diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/net/socket.c b/net/socket.c index 985ef06792d6..c2564eb25c6b 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -3356,3 +3356,49 @@ int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how) | |||
3356 | return sock->ops->shutdown(sock, how); | 3356 | return sock->ops->shutdown(sock, how); |
3357 | } | 3357 | } |
3358 | EXPORT_SYMBOL(kernel_sock_shutdown); | 3358 | EXPORT_SYMBOL(kernel_sock_shutdown); |
3359 | |||
3360 | /* This routine returns the IP overhead imposed by a socket i.e. | ||
3361 | * the length of the underlying IP header, depending on whether | ||
3362 | * this is an IPv4 or IPv6 socket and the length from IP options turned | ||
3363 | * on at the socket. Assumes that the caller has a lock on the socket. | ||
3364 | */ | ||
3365 | u32 kernel_sock_ip_overhead(struct sock *sk) | ||
3366 | { | ||
3367 | struct inet_sock *inet; | ||
3368 | struct ip_options_rcu *opt; | ||
3369 | u32 overhead = 0; | ||
3370 | bool owned_by_user; | ||
3371 | #if IS_ENABLED(CONFIG_IPV6) | ||
3372 | struct ipv6_pinfo *np; | ||
3373 | struct ipv6_txoptions *optv6 = NULL; | ||
3374 | #endif /* IS_ENABLED(CONFIG_IPV6) */ | ||
3375 | |||
3376 | if (!sk) | ||
3377 | return overhead; | ||
3378 | |||
3379 | owned_by_user = sock_owned_by_user(sk); | ||
3380 | switch (sk->sk_family) { | ||
3381 | case AF_INET: | ||
3382 | inet = inet_sk(sk); | ||
3383 | overhead += sizeof(struct iphdr); | ||
3384 | opt = rcu_dereference_protected(inet->inet_opt, | ||
3385 | owned_by_user); | ||
3386 | if (opt) | ||
3387 | overhead += opt->opt.optlen; | ||
3388 | return overhead; | ||
3389 | #if IS_ENABLED(CONFIG_IPV6) | ||
3390 | case AF_INET6: | ||
3391 | np = inet6_sk(sk); | ||
3392 | overhead += sizeof(struct ipv6hdr); | ||
3393 | if (np) | ||
3394 | optv6 = rcu_dereference_protected(np->opt, | ||
3395 | owned_by_user); | ||
3396 | if (optv6) | ||
3397 | overhead += (optv6->opt_flen + optv6->opt_nflen); | ||
3398 | return overhead; | ||
3399 | #endif /* IS_ENABLED(CONFIG_IPV6) */ | ||
3400 | default: /* Returns 0 overhead if the socket is not ipv4 or ipv6 */ | ||
3401 | return overhead; | ||
3402 | } | ||
3403 | } | ||
3404 | EXPORT_SYMBOL(kernel_sock_ip_overhead); | ||