109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
222931d3bSPavel Emelyanov #include <linux/types.h>
322931d3bSPavel Emelyanov #include <linux/spinlock.h>
422931d3bSPavel Emelyanov #include <linux/sock_diag.h>
522931d3bSPavel Emelyanov #include <linux/unix_diag.h>
622931d3bSPavel Emelyanov #include <linux/skbuff.h>
72ea744a5SCyrill Gorcunov #include <linux/module.h>
8cae9910eSFelipe Gasper #include <linux/uidgid.h>
922931d3bSPavel Emelyanov #include <net/netlink.h>
1022931d3bSPavel Emelyanov #include <net/af_unix.h>
1122931d3bSPavel Emelyanov #include <net/tcp_states.h>
12cae9910eSFelipe Gasper #include <net/sock.h>
1322931d3bSPavel Emelyanov
sk_diag_dump_name(struct sock * sk,struct sk_buff * nlskb)14f5248b48SPavel Emelyanov static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb)
15f5248b48SPavel Emelyanov {
162f7ca90aSKuniyuki Iwashima /* might or might not have a hash table lock */
17ae3b5641SAl Viro struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr);
18f5248b48SPavel Emelyanov
194245375dSThomas Graf if (!addr)
20f5248b48SPavel Emelyanov return 0;
21f5248b48SPavel Emelyanov
22755662ceSKuniyuki Iwashima return nla_put(nlskb, UNIX_DIAG_NAME,
23755662ceSKuniyuki Iwashima addr->len - offsetof(struct sockaddr_un, sun_path),
244245375dSThomas Graf addr->name->sun_path);
25f5248b48SPavel Emelyanov }
26f5248b48SPavel Emelyanov
sk_diag_dump_vfs(struct sock * sk,struct sk_buff * nlskb)275f7b0569SPavel Emelyanov static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb)
285f7b0569SPavel Emelyanov {
2940ffe67dSAl Viro struct dentry *dentry = unix_sk(sk)->path.dentry;
305f7b0569SPavel Emelyanov
315f7b0569SPavel Emelyanov if (dentry) {
324245375dSThomas Graf struct unix_diag_vfs uv = {
33a25b376bSDavid Howells .udiag_vfs_ino = d_backing_inode(dentry)->i_ino,
344245375dSThomas Graf .udiag_vfs_dev = dentry->d_sb->s_dev,
354245375dSThomas Graf };
364245375dSThomas Graf
374245375dSThomas Graf return nla_put(nlskb, UNIX_DIAG_VFS, sizeof(uv), &uv);
385f7b0569SPavel Emelyanov }
395f7b0569SPavel Emelyanov
405f7b0569SPavel Emelyanov return 0;
415f7b0569SPavel Emelyanov }
425f7b0569SPavel Emelyanov
sk_diag_dump_peer(struct sock * sk,struct sk_buff * nlskb)43ac02be8dSPavel Emelyanov static int sk_diag_dump_peer(struct sock *sk, struct sk_buff *nlskb)
44ac02be8dSPavel Emelyanov {
45ac02be8dSPavel Emelyanov struct sock *peer;
46ac02be8dSPavel Emelyanov int ino;
47ac02be8dSPavel Emelyanov
48ac02be8dSPavel Emelyanov peer = unix_peer_get(sk);
49ac02be8dSPavel Emelyanov if (peer) {
50ac02be8dSPavel Emelyanov unix_state_lock(peer);
51ac02be8dSPavel Emelyanov ino = sock_i_ino(peer);
52ac02be8dSPavel Emelyanov unix_state_unlock(peer);
53ac02be8dSPavel Emelyanov sock_put(peer);
54ac02be8dSPavel Emelyanov
554245375dSThomas Graf return nla_put_u32(nlskb, UNIX_DIAG_PEER, ino);
56ac02be8dSPavel Emelyanov }
57ac02be8dSPavel Emelyanov
58ac02be8dSPavel Emelyanov return 0;
59ac02be8dSPavel Emelyanov }
60ac02be8dSPavel Emelyanov
sk_diag_dump_icons(struct sock * sk,struct sk_buff * nlskb)612aac7a2cSPavel Emelyanov static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb)
622aac7a2cSPavel Emelyanov {
632aac7a2cSPavel Emelyanov struct sk_buff *skb;
644245375dSThomas Graf struct nlattr *attr;
652aac7a2cSPavel Emelyanov u32 *buf;
662aac7a2cSPavel Emelyanov int i;
672aac7a2cSPavel Emelyanov
684398f595SKuniyuki Iwashima if (READ_ONCE(sk->sk_state) == TCP_LISTEN) {
692aac7a2cSPavel Emelyanov spin_lock(&sk->sk_receive_queue.lock);
704245375dSThomas Graf
714245375dSThomas Graf attr = nla_reserve(nlskb, UNIX_DIAG_ICONS,
723b0723c1SPavel Emelyanov sk->sk_receive_queue.qlen * sizeof(u32));
734245375dSThomas Graf if (!attr)
744245375dSThomas Graf goto errout;
754245375dSThomas Graf
764245375dSThomas Graf buf = nla_data(attr);
772aac7a2cSPavel Emelyanov i = 0;
782aac7a2cSPavel Emelyanov skb_queue_walk(&sk->sk_receive_queue, skb) {
792aac7a2cSPavel Emelyanov struct sock *req, *peer;
802aac7a2cSPavel Emelyanov
812aac7a2cSPavel Emelyanov req = skb->sk;
822aac7a2cSPavel Emelyanov /*
832aac7a2cSPavel Emelyanov * The state lock is outer for the same sk's
842aac7a2cSPavel Emelyanov * queue lock. With the other's queue locked it's
852aac7a2cSPavel Emelyanov * OK to lock the state.
862aac7a2cSPavel Emelyanov */
875e7f3e03SEric Dumazet unix_state_lock_nested(req, U_LOCK_DIAG);
882aac7a2cSPavel Emelyanov peer = unix_sk(req)->peer;
89e09e9d18SDavid S. Miller buf[i++] = (peer ? sock_i_ino(peer) : 0);
902aac7a2cSPavel Emelyanov unix_state_unlock(req);
912aac7a2cSPavel Emelyanov }
922aac7a2cSPavel Emelyanov spin_unlock(&sk->sk_receive_queue.lock);
932aac7a2cSPavel Emelyanov }
942aac7a2cSPavel Emelyanov
952aac7a2cSPavel Emelyanov return 0;
962aac7a2cSPavel Emelyanov
974245375dSThomas Graf errout:
982aac7a2cSPavel Emelyanov spin_unlock(&sk->sk_receive_queue.lock);
992aac7a2cSPavel Emelyanov return -EMSGSIZE;
1002aac7a2cSPavel Emelyanov }
1012aac7a2cSPavel Emelyanov
sk_diag_show_rqlen(struct sock * sk,struct sk_buff * nlskb)102cbf39195SPavel Emelyanov static int sk_diag_show_rqlen(struct sock *sk, struct sk_buff *nlskb)
103cbf39195SPavel Emelyanov {
1044245375dSThomas Graf struct unix_diag_rqlen rql;
105c9da99e6SPavel Emelyanov
1064398f595SKuniyuki Iwashima if (READ_ONCE(sk->sk_state) == TCP_LISTEN) {
10760db0759SKuniyuki Iwashima rql.udiag_rqueue = skb_queue_len_lockless(&sk->sk_receive_queue);
1084245375dSThomas Graf rql.udiag_wqueue = sk->sk_max_ack_backlog;
109c9da99e6SPavel Emelyanov } else {
1104245375dSThomas Graf rql.udiag_rqueue = (u32) unix_inq_len(sk);
1114245375dSThomas Graf rql.udiag_wqueue = (u32) unix_outq_len(sk);
112c9da99e6SPavel Emelyanov }
113c9da99e6SPavel Emelyanov
1144245375dSThomas Graf return nla_put(nlskb, UNIX_DIAG_RQLEN, sizeof(rql), &rql);
115cbf39195SPavel Emelyanov }
116cbf39195SPavel Emelyanov
sk_diag_dump_uid(struct sock * sk,struct sk_buff * nlskb,struct user_namespace * user_ns)117b3abe42eSKuniyuki Iwashima static int sk_diag_dump_uid(struct sock *sk, struct sk_buff *nlskb,
118b3abe42eSKuniyuki Iwashima struct user_namespace *user_ns)
119cae9910eSFelipe Gasper {
120b3abe42eSKuniyuki Iwashima uid_t uid = from_kuid_munged(user_ns, sock_i_uid(sk));
121cae9910eSFelipe Gasper return nla_put(nlskb, UNIX_DIAG_UID, sizeof(uid_t), &uid);
122cae9910eSFelipe Gasper }
123cae9910eSFelipe Gasper
sk_diag_fill(struct sock * sk,struct sk_buff * skb,struct unix_diag_req * req,struct user_namespace * user_ns,u32 portid,u32 seq,u32 flags,int sk_ino)12445a96b9bSPavel Emelyanov static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
125b3abe42eSKuniyuki Iwashima struct user_namespace *user_ns,
12615e47304SEric W. Biederman u32 portid, u32 seq, u32 flags, int sk_ino)
12745a96b9bSPavel Emelyanov {
12845a96b9bSPavel Emelyanov struct nlmsghdr *nlh;
12945a96b9bSPavel Emelyanov struct unix_diag_msg *rep;
13045a96b9bSPavel Emelyanov
13115e47304SEric W. Biederman nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
1324245375dSThomas Graf flags);
133b61bb019SDavid S. Miller if (!nlh)
1344245375dSThomas Graf return -EMSGSIZE;
13545a96b9bSPavel Emelyanov
136b61bb019SDavid S. Miller rep = nlmsg_data(nlh);
13745a96b9bSPavel Emelyanov rep->udiag_family = AF_UNIX;
13845a96b9bSPavel Emelyanov rep->udiag_type = sk->sk_type;
1394398f595SKuniyuki Iwashima rep->udiag_state = READ_ONCE(sk->sk_state);
1406865d1e8SMathias Krause rep->pad = 0;
14145a96b9bSPavel Emelyanov rep->udiag_ino = sk_ino;
14245a96b9bSPavel Emelyanov sock_diag_save_cookie(sk, rep->udiag_cookie);
14345a96b9bSPavel Emelyanov
144f5248b48SPavel Emelyanov if ((req->udiag_show & UDIAG_SHOW_NAME) &&
145f5248b48SPavel Emelyanov sk_diag_dump_name(sk, skb))
146b61bb019SDavid S. Miller goto out_nlmsg_trim;
147f5248b48SPavel Emelyanov
1485f7b0569SPavel Emelyanov if ((req->udiag_show & UDIAG_SHOW_VFS) &&
1495f7b0569SPavel Emelyanov sk_diag_dump_vfs(sk, skb))
150b61bb019SDavid S. Miller goto out_nlmsg_trim;
1515f7b0569SPavel Emelyanov
152ac02be8dSPavel Emelyanov if ((req->udiag_show & UDIAG_SHOW_PEER) &&
153ac02be8dSPavel Emelyanov sk_diag_dump_peer(sk, skb))
154b61bb019SDavid S. Miller goto out_nlmsg_trim;
155ac02be8dSPavel Emelyanov
1562aac7a2cSPavel Emelyanov if ((req->udiag_show & UDIAG_SHOW_ICONS) &&
1572aac7a2cSPavel Emelyanov sk_diag_dump_icons(sk, skb))
158b61bb019SDavid S. Miller goto out_nlmsg_trim;
1592aac7a2cSPavel Emelyanov
160cbf39195SPavel Emelyanov if ((req->udiag_show & UDIAG_SHOW_RQLEN) &&
161cbf39195SPavel Emelyanov sk_diag_show_rqlen(sk, skb))
162b61bb019SDavid S. Miller goto out_nlmsg_trim;
163cbf39195SPavel Emelyanov
164257b5298SPavel Emelyanov if ((req->udiag_show & UDIAG_SHOW_MEMINFO) &&
165257b5298SPavel Emelyanov sock_diag_put_meminfo(sk, skb, UNIX_DIAG_MEMINFO))
166b61bb019SDavid S. Miller goto out_nlmsg_trim;
167257b5298SPavel Emelyanov
168d8011254SKuniyuki Iwashima if (nla_put_u8(skb, UNIX_DIAG_SHUTDOWN, READ_ONCE(sk->sk_shutdown)))
169e4e541a8SPavel Emelyanov goto out_nlmsg_trim;
170e4e541a8SPavel Emelyanov
171cae9910eSFelipe Gasper if ((req->udiag_show & UDIAG_SHOW_UID) &&
172b3abe42eSKuniyuki Iwashima sk_diag_dump_uid(sk, skb, user_ns))
173cae9910eSFelipe Gasper goto out_nlmsg_trim;
174cae9910eSFelipe Gasper
175053c095aSJohannes Berg nlmsg_end(skb, nlh);
176053c095aSJohannes Berg return 0;
17745a96b9bSPavel Emelyanov
178b61bb019SDavid S. Miller out_nlmsg_trim:
1794245375dSThomas Graf nlmsg_cancel(skb, nlh);
18045a96b9bSPavel Emelyanov return -EMSGSIZE;
18145a96b9bSPavel Emelyanov }
18245a96b9bSPavel Emelyanov
sk_diag_dump(struct sock * sk,struct sk_buff * skb,struct unix_diag_req * req,struct user_namespace * user_ns,u32 portid,u32 seq,u32 flags)18345a96b9bSPavel Emelyanov static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
184b3abe42eSKuniyuki Iwashima struct user_namespace *user_ns,
18515e47304SEric W. Biederman u32 portid, u32 seq, u32 flags)
18645a96b9bSPavel Emelyanov {
18745a96b9bSPavel Emelyanov int sk_ino;
18845a96b9bSPavel Emelyanov
18945a96b9bSPavel Emelyanov unix_state_lock(sk);
19045a96b9bSPavel Emelyanov sk_ino = sock_i_ino(sk);
19145a96b9bSPavel Emelyanov unix_state_unlock(sk);
19245a96b9bSPavel Emelyanov
19345a96b9bSPavel Emelyanov if (!sk_ino)
19445a96b9bSPavel Emelyanov return 0;
19545a96b9bSPavel Emelyanov
196b3abe42eSKuniyuki Iwashima return sk_diag_fill(sk, skb, req, user_ns, portid, seq, flags, sk_ino);
19745a96b9bSPavel Emelyanov }
19845a96b9bSPavel Emelyanov
unix_diag_dump(struct sk_buff * skb,struct netlink_callback * cb)19922931d3bSPavel Emelyanov static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
20022931d3bSPavel Emelyanov {
20151d7cccfSAndrey Vagin struct net *net = sock_net(skb->sk);
20279b05beaSKuniyuki Iwashima int num, s_num, slot, s_slot;
20379b05beaSKuniyuki Iwashima struct unix_diag_req *req;
20445a96b9bSPavel Emelyanov
205b61bb019SDavid S. Miller req = nlmsg_data(cb->nlh);
20645a96b9bSPavel Emelyanov
20745a96b9bSPavel Emelyanov s_slot = cb->args[0];
20845a96b9bSPavel Emelyanov num = s_num = cb->args[1];
20945a96b9bSPavel Emelyanov
210f302d180SKuniyuki Iwashima for (slot = s_slot; slot < UNIX_HASH_SIZE; s_num = 0, slot++) {
21145a96b9bSPavel Emelyanov struct sock *sk;
21245a96b9bSPavel Emelyanov
21345a96b9bSPavel Emelyanov num = 0;
21479b05beaSKuniyuki Iwashima spin_lock(&net->unx.table.locks[slot]);
215cf2f225eSKuniyuki Iwashima sk_for_each(sk, &net->unx.table.buckets[slot]) {
21645a96b9bSPavel Emelyanov if (num < s_num)
21745a96b9bSPavel Emelyanov goto next;
2184398f595SKuniyuki Iwashima if (!(req->udiag_states & (1 << READ_ONCE(sk->sk_state))))
21945a96b9bSPavel Emelyanov goto next;
220b3abe42eSKuniyuki Iwashima if (sk_diag_dump(sk, skb, req, sk_user_ns(skb->sk),
22115e47304SEric W. Biederman NETLINK_CB(cb->skb).portid,
22245a96b9bSPavel Emelyanov cb->nlh->nlmsg_seq,
223afd20b92SKuniyuki Iwashima NLM_F_MULTI) < 0) {
22479b05beaSKuniyuki Iwashima spin_unlock(&net->unx.table.locks[slot]);
22545a96b9bSPavel Emelyanov goto done;
226afd20b92SKuniyuki Iwashima }
22745a96b9bSPavel Emelyanov next:
22845a96b9bSPavel Emelyanov num++;
22945a96b9bSPavel Emelyanov }
23079b05beaSKuniyuki Iwashima spin_unlock(&net->unx.table.locks[slot]);
23145a96b9bSPavel Emelyanov }
23245a96b9bSPavel Emelyanov done:
23345a96b9bSPavel Emelyanov cb->args[0] = slot;
23445a96b9bSPavel Emelyanov cb->args[1] = num;
23545a96b9bSPavel Emelyanov
23645a96b9bSPavel Emelyanov return skb->len;
23722931d3bSPavel Emelyanov }
23822931d3bSPavel Emelyanov
unix_lookup_by_ino(struct net * net,unsigned int ino)23979b05beaSKuniyuki Iwashima static struct sock *unix_lookup_by_ino(struct net *net, unsigned int ino)
2405d3cae8bSPavel Emelyanov {
2415d3cae8bSPavel Emelyanov struct sock *sk;
242afd20b92SKuniyuki Iwashima int i;
2435d3cae8bSPavel Emelyanov
244f302d180SKuniyuki Iwashima for (i = 0; i < UNIX_HASH_SIZE; i++) {
24579b05beaSKuniyuki Iwashima spin_lock(&net->unx.table.locks[i]);
246cf2f225eSKuniyuki Iwashima sk_for_each(sk, &net->unx.table.buckets[i]) {
2475d3cae8bSPavel Emelyanov if (ino == sock_i_ino(sk)) {
2485d3cae8bSPavel Emelyanov sock_hold(sk);
24979b05beaSKuniyuki Iwashima spin_unlock(&net->unx.table.locks[i]);
2505d3cae8bSPavel Emelyanov return sk;
2515d3cae8bSPavel Emelyanov }
252cf2f225eSKuniyuki Iwashima }
25379b05beaSKuniyuki Iwashima spin_unlock(&net->unx.table.locks[i]);
2545d3cae8bSPavel Emelyanov }
2555d3cae8bSPavel Emelyanov return NULL;
2565d3cae8bSPavel Emelyanov }
2575d3cae8bSPavel Emelyanov
unix_diag_get_exact(struct sk_buff * in_skb,const struct nlmsghdr * nlh,struct unix_diag_req * req)25822931d3bSPavel Emelyanov static int unix_diag_get_exact(struct sk_buff *in_skb,
25922931d3bSPavel Emelyanov const struct nlmsghdr *nlh,
26022931d3bSPavel Emelyanov struct unix_diag_req *req)
26122931d3bSPavel Emelyanov {
26251d7cccfSAndrey Vagin struct net *net = sock_net(in_skb->sk);
26379b05beaSKuniyuki Iwashima unsigned int extra_len;
26479b05beaSKuniyuki Iwashima struct sk_buff *rep;
26579b05beaSKuniyuki Iwashima struct sock *sk;
26679b05beaSKuniyuki Iwashima int err;
2675d3cae8bSPavel Emelyanov
26879b05beaSKuniyuki Iwashima err = -EINVAL;
2695d3cae8bSPavel Emelyanov if (req->udiag_ino == 0)
2705d3cae8bSPavel Emelyanov goto out_nosk;
2715d3cae8bSPavel Emelyanov
27279b05beaSKuniyuki Iwashima sk = unix_lookup_by_ino(net, req->udiag_ino);
2735d3cae8bSPavel Emelyanov err = -ENOENT;
2745d3cae8bSPavel Emelyanov if (sk == NULL)
2755d3cae8bSPavel Emelyanov goto out_nosk;
2765d3cae8bSPavel Emelyanov
2775d3cae8bSPavel Emelyanov err = sock_diag_check_cookie(sk, req->udiag_cookie);
2785d3cae8bSPavel Emelyanov if (err)
2795d3cae8bSPavel Emelyanov goto out;
2805d3cae8bSPavel Emelyanov
2815d3cae8bSPavel Emelyanov extra_len = 256;
2825d3cae8bSPavel Emelyanov again:
2835d3cae8bSPavel Emelyanov err = -ENOMEM;
2844245375dSThomas Graf rep = nlmsg_new(sizeof(struct unix_diag_msg) + extra_len, GFP_KERNEL);
2855d3cae8bSPavel Emelyanov if (!rep)
2865d3cae8bSPavel Emelyanov goto out;
2875d3cae8bSPavel Emelyanov
288b3abe42eSKuniyuki Iwashima err = sk_diag_fill(sk, rep, req, sk_user_ns(NETLINK_CB(in_skb).sk),
289b3abe42eSKuniyuki Iwashima NETLINK_CB(in_skb).portid,
2905d3cae8bSPavel Emelyanov nlh->nlmsg_seq, 0, req->udiag_ino);
2915d3cae8bSPavel Emelyanov if (err < 0) {
2924245375dSThomas Graf nlmsg_free(rep);
2935d3cae8bSPavel Emelyanov extra_len += 256;
2945d3cae8bSPavel Emelyanov if (extra_len >= PAGE_SIZE)
2955d3cae8bSPavel Emelyanov goto out;
2965d3cae8bSPavel Emelyanov
2975d3cae8bSPavel Emelyanov goto again;
2985d3cae8bSPavel Emelyanov }
29901757f53SYajun Deng err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid);
30001757f53SYajun Deng
3015d3cae8bSPavel Emelyanov out:
3025d3cae8bSPavel Emelyanov if (sk)
3035d3cae8bSPavel Emelyanov sock_put(sk);
3045d3cae8bSPavel Emelyanov out_nosk:
3055d3cae8bSPavel Emelyanov return err;
30622931d3bSPavel Emelyanov }
30722931d3bSPavel Emelyanov
unix_diag_handler_dump(struct sk_buff * skb,struct nlmsghdr * h)30822931d3bSPavel Emelyanov static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
30922931d3bSPavel Emelyanov {
31022931d3bSPavel Emelyanov int hdrlen = sizeof(struct unix_diag_req);
31122931d3bSPavel Emelyanov
31222931d3bSPavel Emelyanov if (nlmsg_len(h) < hdrlen)
31322931d3bSPavel Emelyanov return -EINVAL;
31422931d3bSPavel Emelyanov
31580d326faSPablo Neira Ayuso if (h->nlmsg_flags & NLM_F_DUMP) {
31680d326faSPablo Neira Ayuso struct netlink_dump_control c = {
31780d326faSPablo Neira Ayuso .dump = unix_diag_dump,
31880d326faSPablo Neira Ayuso };
319340c3d33SKuniyuki Iwashima return netlink_dump_start(sock_net(skb->sk)->diag_nlsk, skb, h, &c);
32080d326faSPablo Neira Ayuso } else
321b61bb019SDavid S. Miller return unix_diag_get_exact(skb, h, nlmsg_data(h));
32222931d3bSPavel Emelyanov }
32322931d3bSPavel Emelyanov
3248dcf01fcSShan Wei static const struct sock_diag_handler unix_diag_handler = {
325*37103a9dSEric Dumazet .owner = THIS_MODULE,
32622931d3bSPavel Emelyanov .family = AF_UNIX,
32722931d3bSPavel Emelyanov .dump = unix_diag_handler_dump,
32822931d3bSPavel Emelyanov };
32922931d3bSPavel Emelyanov
unix_diag_init(void)33022931d3bSPavel Emelyanov static int __init unix_diag_init(void)
33122931d3bSPavel Emelyanov {
33222931d3bSPavel Emelyanov return sock_diag_register(&unix_diag_handler);
33322931d3bSPavel Emelyanov }
33422931d3bSPavel Emelyanov
unix_diag_exit(void)33522931d3bSPavel Emelyanov static void __exit unix_diag_exit(void)
33622931d3bSPavel Emelyanov {
33722931d3bSPavel Emelyanov sock_diag_unregister(&unix_diag_handler);
33822931d3bSPavel Emelyanov }
33922931d3bSPavel Emelyanov
34022931d3bSPavel Emelyanov module_init(unix_diag_init);
34122931d3bSPavel Emelyanov module_exit(unix_diag_exit);
34222931d3bSPavel Emelyanov MODULE_LICENSE("GPL");
34322931d3bSPavel Emelyanov MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 1 /* AF_LOCAL */);
344