1 #include <linux/module.h> 2 3 #include <net/sock.h> 4 #include <linux/netlink.h> 5 #include <linux/sock_diag.h> 6 #include <linux/netlink_diag.h> 7 #include <linux/rhashtable.h> 8 9 #include "af_netlink.h" 10 11 static int sk_diag_dump_groups(struct sock *sk, struct sk_buff *nlskb) 12 { 13 struct netlink_sock *nlk = nlk_sk(sk); 14 15 if (nlk->groups == NULL) 16 return 0; 17 18 return nla_put(nlskb, NETLINK_DIAG_GROUPS, NLGRPSZ(nlk->ngroups), 19 nlk->groups); 20 } 21 22 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, 23 struct netlink_diag_req *req, 24 u32 portid, u32 seq, u32 flags, int sk_ino) 25 { 26 struct nlmsghdr *nlh; 27 struct netlink_diag_msg *rep; 28 struct netlink_sock *nlk = nlk_sk(sk); 29 30 nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep), 31 flags); 32 if (!nlh) 33 return -EMSGSIZE; 34 35 rep = nlmsg_data(nlh); 36 rep->ndiag_family = AF_NETLINK; 37 rep->ndiag_type = sk->sk_type; 38 rep->ndiag_protocol = sk->sk_protocol; 39 rep->ndiag_state = sk->sk_state; 40 41 rep->ndiag_ino = sk_ino; 42 rep->ndiag_portid = nlk->portid; 43 rep->ndiag_dst_portid = nlk->dst_portid; 44 rep->ndiag_dst_group = nlk->dst_group; 45 sock_diag_save_cookie(sk, rep->ndiag_cookie); 46 47 if ((req->ndiag_show & NDIAG_SHOW_GROUPS) && 48 sk_diag_dump_groups(sk, skb)) 49 goto out_nlmsg_trim; 50 51 if ((req->ndiag_show & NDIAG_SHOW_MEMINFO) && 52 sock_diag_put_meminfo(sk, skb, NETLINK_DIAG_MEMINFO)) 53 goto out_nlmsg_trim; 54 55 nlmsg_end(skb, nlh); 56 return 0; 57 58 out_nlmsg_trim: 59 nlmsg_cancel(skb, nlh); 60 return -EMSGSIZE; 61 } 62 63 static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, 64 int protocol, int s_num) 65 { 66 struct netlink_table *tbl = &nl_table[protocol]; 67 struct rhashtable *ht = &tbl->hash; 68 const struct bucket_table *htbl = rht_dereference_rcu(ht->tbl, ht); 69 struct net *net = sock_net(skb->sk); 70 struct netlink_diag_req *req; 71 struct netlink_sock *nlsk; 72 struct sock *sk; 73 int ret = 0, num = 0, i; 74 75 req = nlmsg_data(cb->nlh); 76 77 for (i = 0; i < htbl->size; i++) { 78 struct rhash_head *pos; 79 80 rht_for_each_entry_rcu(nlsk, pos, htbl, i, node) { 81 sk = (struct sock *)nlsk; 82 83 if (!net_eq(sock_net(sk), net)) 84 continue; 85 if (num < s_num) { 86 num++; 87 continue; 88 } 89 90 if (sk_diag_fill(sk, skb, req, 91 NETLINK_CB(cb->skb).portid, 92 cb->nlh->nlmsg_seq, 93 NLM_F_MULTI, 94 sock_i_ino(sk)) < 0) { 95 ret = 1; 96 goto done; 97 } 98 99 num++; 100 } 101 } 102 103 sk_for_each_bound(sk, &tbl->mc_list) { 104 if (sk_hashed(sk)) 105 continue; 106 if (!net_eq(sock_net(sk), net)) 107 continue; 108 if (num < s_num) { 109 num++; 110 continue; 111 } 112 113 if (sk_diag_fill(sk, skb, req, 114 NETLINK_CB(cb->skb).portid, 115 cb->nlh->nlmsg_seq, 116 NLM_F_MULTI, 117 sock_i_ino(sk)) < 0) { 118 ret = 1; 119 goto done; 120 } 121 num++; 122 } 123 done: 124 cb->args[0] = num; 125 cb->args[1] = protocol; 126 127 return ret; 128 } 129 130 static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) 131 { 132 struct netlink_diag_req *req; 133 int s_num = cb->args[0]; 134 135 req = nlmsg_data(cb->nlh); 136 137 rcu_read_lock(); 138 read_lock(&nl_table_lock); 139 140 if (req->sdiag_protocol == NDIAG_PROTO_ALL) { 141 int i; 142 143 for (i = cb->args[1]; i < MAX_LINKS; i++) { 144 if (__netlink_diag_dump(skb, cb, i, s_num)) 145 break; 146 s_num = 0; 147 } 148 } else { 149 if (req->sdiag_protocol >= MAX_LINKS) { 150 read_unlock(&nl_table_lock); 151 rcu_read_unlock(); 152 return -ENOENT; 153 } 154 155 __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num); 156 } 157 158 read_unlock(&nl_table_lock); 159 rcu_read_unlock(); 160 161 return skb->len; 162 } 163 164 static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) 165 { 166 int hdrlen = sizeof(struct netlink_diag_req); 167 struct net *net = sock_net(skb->sk); 168 169 if (nlmsg_len(h) < hdrlen) 170 return -EINVAL; 171 172 if (h->nlmsg_flags & NLM_F_DUMP) { 173 struct netlink_dump_control c = { 174 .dump = netlink_diag_dump, 175 }; 176 return netlink_dump_start(net->diag_nlsk, skb, h, &c); 177 } else 178 return -EOPNOTSUPP; 179 } 180 181 static const struct sock_diag_handler netlink_diag_handler = { 182 .family = AF_NETLINK, 183 .dump = netlink_diag_handler_dump, 184 }; 185 186 static int __init netlink_diag_init(void) 187 { 188 return sock_diag_register(&netlink_diag_handler); 189 } 190 191 static void __exit netlink_diag_exit(void) 192 { 193 sock_diag_unregister(&netlink_diag_handler); 194 } 195 196 module_init(netlink_diag_init); 197 module_exit(netlink_diag_exit); 198 MODULE_LICENSE("GPL"); 199 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 16 /* AF_NETLINK */); 200