Commit 822c8685 authored by Deepa Dinamani's avatar Deepa Dinamani Committed by David S. Miller

net: ipv4: Convert IP network timestamps to be y2038 safe

ICMP timestamp messages and IP source route options require
timestamps to be in milliseconds modulo 24 hours from
midnight UT format.

Add inet_current_timestamp() function to support this. The function
returns the required timestamp in network byte order.

Timestamp calculation is also changed to call ktime_get_real_ts64()
which uses struct timespec64. struct timespec64 is y2038 safe.
Previously it called getnstimeofday() which uses struct timespec.
struct timespec is not y2038 safe.
Signed-off-by: default avatarDeepa Dinamani <deepa.kernel@gmail.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: James Morris <jmorris@namei.org>
Cc: Patrick McHardy <kaber@trash.net>
Acked-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Acked-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e9c0d61d
...@@ -240,6 +240,8 @@ static inline int inet_is_local_reserved_port(struct net *net, int port) ...@@ -240,6 +240,8 @@ static inline int inet_is_local_reserved_port(struct net *net, int port)
} }
#endif #endif
__be32 inet_current_timestamp(void);
/* From inetpeer.c */ /* From inetpeer.c */
extern int inet_peer_threshold; extern int inet_peer_threshold;
extern int inet_peer_minttl; extern int inet_peer_minttl;
......
...@@ -1380,6 +1380,32 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, ...@@ -1380,6 +1380,32 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
return pp; return pp;
} }
#define SECONDS_PER_DAY 86400
/* inet_current_timestamp - Return IP network timestamp
*
* Return milliseconds since midnight in network byte order.
*/
__be32 inet_current_timestamp(void)
{
u32 secs;
u32 msecs;
struct timespec64 ts;
ktime_get_real_ts64(&ts);
/* Get secs since midnight. */
(void)div_u64_rem(ts.tv_sec, SECONDS_PER_DAY, &secs);
/* Convert to msecs. */
msecs = secs * MSEC_PER_SEC;
/* Convert nsec to msec. */
msecs += (u32)ts.tv_nsec / NSEC_PER_MSEC;
/* Convert to network byte order. */
return htons(msecs);
}
EXPORT_SYMBOL(inet_current_timestamp);
int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
{ {
if (sk->sk_family == AF_INET) if (sk->sk_family == AF_INET)
......
...@@ -931,7 +931,6 @@ static bool icmp_echo(struct sk_buff *skb) ...@@ -931,7 +931,6 @@ static bool icmp_echo(struct sk_buff *skb)
*/ */
static bool icmp_timestamp(struct sk_buff *skb) static bool icmp_timestamp(struct sk_buff *skb)
{ {
struct timespec tv;
struct icmp_bxm icmp_param; struct icmp_bxm icmp_param;
/* /*
* Too short. * Too short.
...@@ -942,9 +941,7 @@ static bool icmp_timestamp(struct sk_buff *skb) ...@@ -942,9 +941,7 @@ static bool icmp_timestamp(struct sk_buff *skb)
/* /*
* Fill in the current time as ms since midnight UT: * Fill in the current time as ms since midnight UT:
*/ */
getnstimeofday(&tv); icmp_param.data.times[1] = inet_current_timestamp();
icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC +
tv.tv_nsec / NSEC_PER_MSEC);
icmp_param.data.times[2] = icmp_param.data.times[1]; icmp_param.data.times[2] = icmp_param.data.times[1];
if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4)) if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
BUG(); BUG();
......
...@@ -58,10 +58,9 @@ void ip_options_build(struct sk_buff *skb, struct ip_options *opt, ...@@ -58,10 +58,9 @@ void ip_options_build(struct sk_buff *skb, struct ip_options *opt,
if (opt->ts_needaddr) if (opt->ts_needaddr)
ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, skb, rt); ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, skb, rt);
if (opt->ts_needtime) { if (opt->ts_needtime) {
struct timespec tv;
__be32 midtime; __be32 midtime;
getnstimeofday(&tv);
midtime = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC); midtime = inet_current_timestamp();
memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4); memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);
} }
return; return;
...@@ -415,11 +414,10 @@ int ip_options_compile(struct net *net, ...@@ -415,11 +414,10 @@ int ip_options_compile(struct net *net,
break; break;
} }
if (timeptr) { if (timeptr) {
struct timespec tv; __be32 midtime;
u32 midtime;
getnstimeofday(&tv); midtime = inet_current_timestamp();
midtime = (tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC; memcpy(timeptr, &midtime, 4);
put_unaligned_be32(midtime, timeptr);
opt->is_changed = 1; opt->is_changed = 1;
} }
} else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) { } else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment