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