return neigh_create(tbl, pkey, dev);
}
+#define LOCALLY_ENQUEUED -2
+
#endif
#endif
SOCK_LINGER,
SOCK_DESTROY,
SOCK_BROADCAST,
+ SOCK_TIMESTAMP,
};
static inline void sock_set_flag(struct sock *sk, enum sock_flags flag)
static __inline__ void
sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
{
- if (sk->sk_rcvtstamp)
- put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(skb->stamp), &skb->stamp);
- else
- sk->sk_stamp = skb->stamp;
+ struct timeval *stamp = &skb->stamp;
+ if (sk->sk_rcvtstamp) {
+ /* Race occurred between timestamp enabling and packet
+ receiving. Fill in the current time for now. */
+ if (stamp->tv_sec == 0)
+ do_gettimeofday(stamp);
+ put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(struct timeval),
+ stamp);
+ } else
+ sk->sk_stamp = *stamp;
}
+extern atomic_t netstamp_needed;
+extern void sock_enable_timestamp(struct sock *sk);
+extern void sock_disable_timestamp(struct sock *sk);
+
+static inline void net_timestamp(struct timeval *stamp)
+{
+ if (atomic_read(&netstamp_needed))
+ do_gettimeofday(stamp);
+ else {
+ stamp->tv_sec = 0;
+ stamp->tv_usec = 0;
+ }
+}
+
+extern int sock_get_timestamp(struct sock *, struct timeval *);
+
/*
* Enable debug/info messages
*/
break;
}
case SIOCGSTAMP:
- if (!sk)
- break;
- rc = -ENOENT;
- if (!sk->sk_stamp.tv_sec)
- break;
- rc = copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)) ? -EFAULT : 0;
+ rc = sock_get_timestamp(sk, (struct timeval *)arg);
break;
/* Routing */
case SIOCADDRT:
goto done;
}
case SIOCGSTAMP: /* borrowed from IP */
- if (!vcc->sk->sk_stamp.tv_sec) {
- error = -ENOENT;
- goto done;
- }
- error = copy_to_user((void *)arg, &vcc->sk->sk_stamp,
- sizeof(struct timeval)) ? -EFAULT : 0;
+ error = sock_get_timestamp(vcc->sk, (struct timeval *)
+ arg);
goto done;
case ATM_SETSC:
printk(KERN_WARNING "ATM_SETSC is obsolete\n");
case SIOCGSTAMP:
if (sk != NULL) {
- if (!sk->sk_stamp.tv_sec) {
- res = -ENOENT;
- break;
- }
- res = copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)) ? -EFAULT : 0;
+ res = sock_get_timestamp(sk, (struct timeval *)arg);
break;
}
res = -EINVAL;
void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
{
struct packet_type *ptype;
- do_gettimeofday(&skb->stamp);
+ net_timestamp(&skb->stamp);
rcu_read_lock();
list_for_each_entry_rcu(ptype, &ptype_all, list) {
return NET_RX_DROP;
}
#endif
-
+
if (!skb->stamp.tv_sec)
- do_gettimeofday(&skb->stamp);
+ net_timestamp(&skb->stamp);
/*
* The code is rearranged so that the path is the most
#endif
if (!skb->stamp.tv_sec)
- do_gettimeofday(&skb->stamp);
+ net_timestamp(&skb->stamp);
skb_bond(skb);
kfree_skb(skb);
return;
}
- skb->stamp.tv_sec = 0;
+ skb->stamp.tv_sec = LOCALLY_ENQUEUED;
skb->stamp.tv_usec = now + sched_next;
spin_lock(&tbl->proxy_queue.lock);
case SO_TIMESTAMP:
sk->sk_rcvtstamp = valbool;
+ if (valbool)
+ sock_enable_timestamp(sk);
break;
case SO_RCVLOWAT:
sk->sk_filter = NULL;
}
+ sock_disable_timestamp(sk);
+
if (atomic_read(&sk->sk_omem_alloc))
printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
__FUNCTION__, atomic_read(&sk->sk_omem_alloc));
sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
sk->sk_owner = NULL;
+ sk->sk_stamp.tv_sec = -1L;
+ sk->sk_stamp.tv_usec = -1L;
+
atomic_set(&sk->sk_refcnt, 1);
}
wake_up(&(sk->sk_lock.wq));
spin_unlock_bh(&(sk->sk_lock.slock));
}
-
EXPORT_SYMBOL(release_sock);
+/* When > 0 there are consumers of rx skb time stamps */
+atomic_t netstamp_needed = ATOMIC_INIT(0);
+
+int sock_get_timestamp(struct sock *sk, struct timeval *userstamp)
+{
+ if (!sock_flag(sk, SOCK_TIMESTAMP))
+ sock_enable_timestamp(sk);
+ if (sk->sk_stamp.tv_sec == -1)
+ return -ENOENT;
+ if (sk->sk_stamp.tv_sec == 0)
+ do_gettimeofday(&sk->sk_stamp);
+ return copy_to_user(userstamp, &sk->sk_stamp, sizeof(struct timeval)) ?
+ -EFAULT : 0;
+}
+EXPORT_SYMBOL(sock_get_timestamp);
+
+void sock_enable_timestamp(struct sock *sk)
+{
+ if (!sock_flag(sk, SOCK_TIMESTAMP)) {
+ sock_set_flag(sk, SOCK_TIMESTAMP);
+ atomic_inc(&netstamp_needed);
+ }
+}
+EXPORT_SYMBOL(sock_enable_timestamp);
+
+void sock_disable_timestamp(struct sock *sk)
+{
+ if (sock_flag(sk, SOCK_TIMESTAMP)) {
+ sock_reset_flag(sk, SOCK_TIMESTAMP);
+ atomic_dec(&netstamp_needed);
+ }
+}
+EXPORT_SYMBOL(sock_disable_timestamp);
+
EXPORT_SYMBOL(__lock_sock);
EXPORT_SYMBOL(__release_sock);
EXPORT_SYMBOL(sk_alloc);
switch(cmd) {
case SIOCGSTAMP:
- if (!sk->sk_stamp.tv_sec)
- return -ENOENT;
- return copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)) ? -EFAULT : 0;
+ return sock_get_timestamp(sk,(struct timeval *)arg);
+
case SIOCSIFADDR:
case SIOCGIFADDR:
return ec_dev_ioctl(sock, cmd, (void *)arg);
switch (cmd) {
case SIOCGSTAMP:
- if (!sk->sk_stamp.tv_sec)
- err = -ENOENT;
- else if (copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)))
- err = -EFAULT;
+ err = sock_get_timestamp(sk, (struct timeval *)arg);
break;
case SIOCADDRT:
case SIOCDELRT:
if (n)
neigh_release(n);
- if (skb->stamp.tv_sec == 0 ||
+ if (skb->stamp.tv_sec == LOCALLY_ENQUEUED ||
skb->pkt_type == PACKET_HOST ||
in_dev->arp_parms->proxy_delay == 0) {
arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
switch(cmd)
{
case SIOCGSTAMP:
- if (!sk->sk_stamp.tv_sec)
- return -ENOENT;
- err = copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval));
- if (err)
- return -EFAULT;
- return 0;
+ return sock_get_timestamp(sk, (struct timeval *)arg);
case SIOCADDRT:
case SIOCDELRT:
if (ipv6_chk_acast_addr(dev, &msg->target) ||
(idev->cnf.forwarding &&
pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) {
- if (skb->stamp.tv_sec != 0 &&
+ if (skb->stamp.tv_sec != LOCALLY_ENQUEUED &&
skb->pkt_type != PACKET_HOST &&
inc != 0 &&
idev->nd_parms->proxy_delay != 0) {
copied);
if (rc)
goto out_free;
- sk->sk_stamp = skb->stamp;
+ if (skb->stamp.tv_sec)
+ sk->sk_stamp = skb->stamp;
msg->msg_namelen = sizeof(*sipx);
break;
case SIOCGSTAMP:
rc = -EINVAL;
- if (sk) {
- rc = -ENOENT;
- if (!sk->sk_stamp.tv_sec)
- break;
- rc = -EFAULT;
- if (!copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)))
- rc = 0;
- }
+ if (sk)
+ rc = sock_get_timestamp(sk, (struct timeval *)arg);
break;
case SIOCGIFDSTADDR:
case SIOCSIFDSTADDR:
}
case SIOCGSTAMP:
- if (sk != NULL) {
- if (!sk->sk_stamp.tv_sec)
- return -ENOENT;
- if (copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)))
- return -EFAULT;
- return 0;
- }
+ if (sk != NULL)
+ return sock_get_timestamp(sk, (struct timeval *)arg);
return -EINVAL;
case SIOCGIFADDR:
}
case SIOCGSTAMP:
- if (sk != NULL) {
- if (!sk->sk_stamp.tv_sec) {
- release_sock(sk);
- return -ENOENT;
- }
- ret = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0;
- release_sock(sk);
- return ret;
- }
+ ret = -EINVAL;
+ if (sk != NULL)
+ ret = sock_get_timestamp(sk, (struct timeval *)arg);
release_sock(sk);
- return -EINVAL;
+ return ret;
case SIOCGIFADDR:
case SIOCSIFADDR:
h->tp_snaplen = snaplen;
h->tp_mac = macoff;
h->tp_net = netoff;
+ if (skb->stamp.tv_sec == 0) {
+ do_gettimeofday(&skb->stamp);
+ sock_enable_timestamp(sk);
+ }
h->tp_sec = skb->stamp.tv_sec;
h->tp_usec = skb->stamp.tv_usec;
return put_user(amount, (int *)arg);
}
case SIOCGSTAMP:
- if (!sk->sk_stamp.tv_sec)
- return -ENOENT;
- if (copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)))
- return -EFAULT;
- break;
-
+ return sock_get_timestamp(sk, (struct timeval *)arg);
+
#ifdef CONFIG_INET
case SIOCADDRT:
case SIOCDELRT:
}
case SIOCGSTAMP:
- if (sk != NULL) {
- if (!sk->sk_stamp.tv_sec)
- return -ENOENT;
- return copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)) ? -EFAULT : 0;
- }
+ if (sk != NULL)
+ return sock_get_timestamp(sk, (struct timeval *)arg);
return -EINVAL;
case SIOCGIFADDR:
msg->trans = trans;
msg->state = RXRPC_MSG_RECEIVED;
msg->stamp = pkt->stamp;
+ if (msg->stamp.tv_sec == 0) {
+ do_gettimeofday(&msg->stamp);
+ if (pkt->sk)
+ sock_enable_timestamp(pkt->sk);
+ }
msg->seq = ntohl(msg->hdr.seq);
/* attach the packet */
rcvr = asoc ? &asoc->base : &ep->base;
sk = rcvr->sk;
+ /* SCTP seems to always need a timestamp right now (FIXME) */
+ if (skb->stamp.tv_sec == 0) {
+ do_gettimeofday(&skb->stamp);
+ sock_enable_timestamp(sk);
+ }
+
if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family))
goto discard_release;
/* possibly an icmp error */
dprintk("svc: recvfrom returned error %d\n", -err);
}
+ if (skb->stamp.tv_sec == 0) {
+ skb->stamp.tv_sec = xtime.tv_sec;
+ skb->stamp.tv_usec = xtime.tv_nsec * 1000;
+ /* Don't enable netstamp, sunrpc doesn't
+ need that much accuracy */
+ }
svsk->sk_sk->sk_stamp = skb->stamp;
set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
switch(cmd)
{
case SIOCGSTAMP:
- if (!sk->sk_stamp.tv_sec)
- return -ENOENT;
- err = -EFAULT;
- if (!copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)))
- err = 0;
- return err;
+ return sock_get_timestamp(sk, (struct timeval *)arg);
case SIOC_WANPIPE_CHECK_TX:
}
case SIOCGSTAMP:
- if (sk) {
- rc = -ENOENT;
- if (!sk->sk_stamp.tv_sec)
- break;
- rc = copy_to_user((void *)arg, &sk->sk_stamp,
- sizeof(struct timeval)) ? -EFAULT : 0;
- }
rc = -EINVAL;
+ if (sk)
+ rc = sock_get_timestamp(sk,
+ (struct timeval *)arg);
break;
case SIOCGIFADDR:
case SIOCSIFADDR: