]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv4/inet_diag.c
[PATCH] lockdep: annotate the sysfs i_mutex to be a separate class
[linux-2.6-omap-h63xx.git] / net / ipv4 / inet_diag.c
index 4c4ae4aaf8f6ae7262deaa4a44a43274f6c6aa22..8e7e41b66c799177f9b9d05691936e9beb83a08f 100644 (file)
@@ -11,7 +11,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -50,9 +49,10 @@ static struct sock *idiagnl;
 #define INET_DIAG_PUT(skb, attrtype, attrlen) \
        RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
 
-static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
-                         int ext, u32 pid, u32 seq, u16 nlmsg_flags,
-                         const struct nlmsghdr *unlh)
+static int inet_csk_diag_fill(struct sock *sk,
+                             struct sk_buff *skb,
+                             int ext, u32 pid, u32 seq, u16 nlmsg_flags,
+                             const struct nlmsghdr *unlh)
 {
        const struct inet_sock *inet = inet_sk(sk);
        const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -70,20 +70,22 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
        nlh->nlmsg_flags = nlmsg_flags;
 
        r = NLMSG_DATA(nlh);
-       if (sk->sk_state != TCP_TIME_WAIT) {
-               if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
-                       minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO,
-                                             sizeof(*minfo));
-               if (ext & (1 << (INET_DIAG_INFO - 1)))
-                       info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
-                                          handler->idiag_info_size);
-
-               if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
-                       size_t len = strlen(icsk->icsk_ca_ops->name);
-                       strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
-                              icsk->icsk_ca_ops->name);
-               }
+       BUG_ON(sk->sk_state == TCP_TIME_WAIT);
+
+       if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
+               minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO, sizeof(*minfo));
+
+       if (ext & (1 << (INET_DIAG_INFO - 1)))
+               info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
+                                    handler->idiag_info_size);
+
+       if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
+               const size_t len = strlen(icsk->icsk_ca_ops->name);
+
+               strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
+                      icsk->icsk_ca_ops->name);
        }
+
        r->idiag_family = sk->sk_family;
        r->idiag_state = sk->sk_state;
        r->idiag_timer = 0;
@@ -93,37 +95,6 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
        r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
        r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
 
-       if (r->idiag_state == TCP_TIME_WAIT) {
-               const struct inet_timewait_sock *tw = inet_twsk(sk);
-               long tmo = tw->tw_ttd - jiffies;
-               if (tmo < 0)
-                       tmo = 0;
-
-               r->id.idiag_sport = tw->tw_sport;
-               r->id.idiag_dport = tw->tw_dport;
-               r->id.idiag_src[0] = tw->tw_rcv_saddr;
-               r->id.idiag_dst[0] = tw->tw_daddr;
-               r->idiag_state = tw->tw_substate;
-               r->idiag_timer = 3;
-               r->idiag_expires = (tmo * 1000 + HZ - 1) / HZ;
-               r->idiag_rqueue = 0;
-               r->idiag_wqueue = 0;
-               r->idiag_uid = 0;
-               r->idiag_inode = 0;
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-               if (r->idiag_family == AF_INET6) {
-                       const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
-
-                       ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
-                                      &tw6->tw_v6_rcv_saddr);
-                       ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
-                                      &tw6->tw_v6_daddr);
-               }
-#endif
-               nlh->nlmsg_len = skb->tail - b;
-               return skb->len;
-       }
-
        r->id.idiag_sport = inet->sport;
        r->id.idiag_dport = inet->dport;
        r->id.idiag_src[0] = inet->rcv_saddr;
@@ -185,6 +156,73 @@ nlmsg_failure:
        return -1;
 }
 
+static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
+                              struct sk_buff *skb, int ext, u32 pid,
+                              u32 seq, u16 nlmsg_flags,
+                              const struct nlmsghdr *unlh)
+{
+       long tmo;
+       struct inet_diag_msg *r;
+       const unsigned char *previous_tail = skb->tail;
+       struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq,
+                                        unlh->nlmsg_type, sizeof(*r));
+
+       r = NLMSG_DATA(nlh);
+       BUG_ON(tw->tw_state != TCP_TIME_WAIT);
+
+       nlh->nlmsg_flags = nlmsg_flags;
+
+       tmo = tw->tw_ttd - jiffies;
+       if (tmo < 0)
+               tmo = 0;
+
+       r->idiag_family       = tw->tw_family;
+       r->idiag_state        = tw->tw_state;
+       r->idiag_timer        = 0;
+       r->idiag_retrans      = 0;
+       r->id.idiag_if        = tw->tw_bound_dev_if;
+       r->id.idiag_cookie[0] = (u32)(unsigned long)tw;
+       r->id.idiag_cookie[1] = (u32)(((unsigned long)tw >> 31) >> 1);
+       r->id.idiag_sport     = tw->tw_sport;
+       r->id.idiag_dport     = tw->tw_dport;
+       r->id.idiag_src[0]    = tw->tw_rcv_saddr;
+       r->id.idiag_dst[0]    = tw->tw_daddr;
+       r->idiag_state        = tw->tw_substate;
+       r->idiag_timer        = 3;
+       r->idiag_expires      = (tmo * 1000 + HZ - 1) / HZ;
+       r->idiag_rqueue       = 0;
+       r->idiag_wqueue       = 0;
+       r->idiag_uid          = 0;
+       r->idiag_inode        = 0;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+       if (tw->tw_family == AF_INET6) {
+               const struct inet6_timewait_sock *tw6 =
+                                               inet6_twsk((struct sock *)tw);
+
+               ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
+                              &tw6->tw_v6_rcv_saddr);
+               ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
+                              &tw6->tw_v6_daddr);
+       }
+#endif
+       nlh->nlmsg_len = skb->tail - previous_tail;
+       return skb->len;
+nlmsg_failure:
+       skb_trim(skb, previous_tail - skb->data);
+       return -1;
+}
+
+static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
+                       int ext, u32 pid, u32 seq, u16 nlmsg_flags,
+                       const struct nlmsghdr *unlh)
+{
+       if (sk->sk_state == TCP_TIME_WAIT)
+               return inet_twsk_diag_fill((struct inet_timewait_sock *)sk,
+                                          skb, ext, pid, seq, nlmsg_flags,
+                                          unlh);
+       return inet_csk_diag_fill(sk, skb, ext, pid, seq, nlmsg_flags, unlh);
+}
+
 static int inet_diag_get_exact(struct sk_buff *in_skb,
                               const struct nlmsghdr *nlh)
 {
@@ -236,7 +274,7 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
        if (!rep)
                goto out;
 
-       if (inet_diag_fill(rep, sk, req->idiag_ext,
+       if (sk_diag_fill(sk, rep, req->idiag_ext,
                         NETLINK_CB(in_skb).pid,
                         nlh->nlmsg_seq, 0, nlh) <= 0)
                BUG();
@@ -415,8 +453,9 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
        return len == 0 ? 0 : -EINVAL;
 }
 
-static int inet_diag_dump_sock(struct sk_buff *skb, struct sock *sk,
-                              struct netlink_callback *cb)
+static int inet_csk_diag_dump(struct sock *sk,
+                             struct sk_buff *skb,
+                             struct netlink_callback *cb)
 {
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
@@ -446,8 +485,45 @@ static int inet_diag_dump_sock(struct sk_buff *skb, struct sock *sk,
                        return 0;
        }
 
-       return inet_diag_fill(skb, sk, r->idiag_ext, NETLINK_CB(cb->skb).pid,
-                             cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
+       return inet_csk_diag_fill(sk, skb, r->idiag_ext,
+                                 NETLINK_CB(cb->skb).pid,
+                                 cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
+}
+
+static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
+                              struct sk_buff *skb,
+                              struct netlink_callback *cb)
+{
+       struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
+
+       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+               struct inet_diag_entry entry;
+               struct rtattr *bc = (struct rtattr *)(r + 1);
+
+               entry.family = tw->tw_family;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+               if (tw->tw_family == AF_INET6) {
+                       struct inet6_timewait_sock *tw6 =
+                                               inet6_twsk((struct sock *)tw);
+                       entry.saddr = tw6->tw_v6_rcv_saddr.s6_addr32;
+                       entry.daddr = tw6->tw_v6_daddr.s6_addr32;
+               } else
+#endif
+               {
+                       entry.saddr = &tw->tw_rcv_saddr;
+                       entry.daddr = &tw->tw_daddr;
+               }
+               entry.sport = tw->tw_num;
+               entry.dport = ntohs(tw->tw_dport);
+               entry.userlocks = 0; 
+
+               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+                       return 0;
+       }
+
+       return inet_twsk_diag_fill(tw, skb, r->idiag_ext,
+                                  NETLINK_CB(cb->skb).pid,
+                                  cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
 }
 
 static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
@@ -631,7 +707,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
                                    cb->args[3] > 0)
                                        goto syn_recv;
 
-                               if (inet_diag_dump_sock(skb, sk, cb) < 0) {
+                               if (inet_csk_diag_dump(sk, skb, cb) < 0) {
                                        inet_listen_unlock(hashinfo);
                                        goto done;
                                }
@@ -687,7 +763,7 @@ skip_listen_ht:
                        if (r->id.idiag_dport != inet->dport &&
                            r->id.idiag_dport)
                                goto next_normal;
-                       if (inet_diag_dump_sock(skb, sk, cb) < 0) {
+                       if (inet_csk_diag_dump(sk, skb, cb) < 0) {
                                read_unlock_bh(&head->lock);
                                goto done;
                        }
@@ -696,9 +772,10 @@ next_normal:
                }
 
                if (r->idiag_states & TCPF_TIME_WAIT) {
-                       sk_for_each(sk, node,
+                       struct inet_timewait_sock *tw;
+
+                       inet_twsk_for_each(tw, node,
                                    &hashinfo->ehash[i + hashinfo->ehash_size].chain) {
-                               const struct inet_timewait_sock *tw = inet_twsk(sk);
 
                                if (num < s_num)
                                        goto next_dying;
@@ -708,7 +785,7 @@ next_normal:
                                if (r->id.idiag_dport != tw->tw_dport &&
                                    r->id.idiag_dport)
                                        goto next_dying;
-                               if (inet_diag_dump_sock(skb, sk, cb) < 0) {
+                               if (inet_twsk_diag_dump(tw, skb, cb) < 0) {
                                        read_unlock_bh(&head->lock);
                                        goto done;
                                }