]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - net/ipv4/tcp_diag.c
2 * tcp_diag.c Module for monitoring TCP sockets.
4 * Version: $Id: tcp_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
6 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
14 #include <linux/config.h>
15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <linux/fcntl.h>
18 #include <linux/random.h>
19 #include <linux/cache.h>
20 #include <linux/init.h>
21 #include <linux/time.h>
26 #include <net/inet_common.h>
28 #include <linux/inet.h>
29 #include <linux/stddef.h>
31 #include <linux/tcp_diag.h>
43 static struct sock
*tcpnl
;
46 #define TCPDIAG_PUT(skb, attrtype, attrlen) \
47 ({ int rtalen = RTA_LENGTH(attrlen); \
49 if (skb_tailroom(skb) < RTA_ALIGN(rtalen)) goto nlmsg_failure; \
50 rta = (void*)__skb_put(skb, RTA_ALIGN(rtalen)); \
51 rta->rta_type = attrtype; \
52 rta->rta_len = rtalen; \
55 static int tcpdiag_fill(struct sk_buff
*skb
, struct sock
*sk
,
56 int ext
, u32 pid
, u32 seq
, u16 nlmsg_flags
)
58 struct inet_sock
*inet
= inet_sk(sk
);
59 struct tcp_sock
*tp
= tcp_sk(sk
);
62 struct tcp_info
*info
= NULL
;
63 struct tcpdiag_meminfo
*minfo
= NULL
;
64 struct tcpvegas_info
*vinfo
= NULL
;
65 unsigned char *b
= skb
->tail
;
67 nlh
= NLMSG_PUT(skb
, pid
, seq
, TCPDIAG_GETSOCK
, sizeof(*r
));
68 nlh
->nlmsg_flags
= nlmsg_flags
;
70 if (sk
->sk_state
!= TCP_TIME_WAIT
) {
71 if (ext
& (1<<(TCPDIAG_MEMINFO
-1)))
72 minfo
= TCPDIAG_PUT(skb
, TCPDIAG_MEMINFO
, sizeof(*minfo
));
73 if (ext
& (1<<(TCPDIAG_INFO
-1)))
74 info
= TCPDIAG_PUT(skb
, TCPDIAG_INFO
, sizeof(*info
));
76 if ((tcp_is_westwood(tp
) || tcp_is_vegas(tp
))
77 && (ext
& (1<<(TCPDIAG_VEGASINFO
-1))))
78 vinfo
= TCPDIAG_PUT(skb
, TCPDIAG_VEGASINFO
, sizeof(*vinfo
));
80 r
->tcpdiag_family
= sk
->sk_family
;
81 r
->tcpdiag_state
= sk
->sk_state
;
83 r
->tcpdiag_retrans
= 0;
85 r
->id
.tcpdiag_if
= sk
->sk_bound_dev_if
;
86 r
->id
.tcpdiag_cookie
[0] = (u32
)(unsigned long)sk
;
87 r
->id
.tcpdiag_cookie
[1] = (u32
)(((unsigned long)sk
>> 31) >> 1);
89 if (r
->tcpdiag_state
== TCP_TIME_WAIT
) {
90 struct tcp_tw_bucket
*tw
= (struct tcp_tw_bucket
*)sk
;
91 long tmo
= tw
->tw_ttd
- jiffies
;
95 r
->id
.tcpdiag_sport
= tw
->tw_sport
;
96 r
->id
.tcpdiag_dport
= tw
->tw_dport
;
97 r
->id
.tcpdiag_src
[0] = tw
->tw_rcv_saddr
;
98 r
->id
.tcpdiag_dst
[0] = tw
->tw_daddr
;
99 r
->tcpdiag_state
= tw
->tw_substate
;
100 r
->tcpdiag_timer
= 3;
101 r
->tcpdiag_expires
= (tmo
*1000+HZ
-1)/HZ
;
102 r
->tcpdiag_rqueue
= 0;
103 r
->tcpdiag_wqueue
= 0;
105 r
->tcpdiag_inode
= 0;
106 #ifdef CONFIG_IP_TCPDIAG_IPV6
107 if (r
->tcpdiag_family
== AF_INET6
) {
108 ipv6_addr_copy((struct in6_addr
*)r
->id
.tcpdiag_src
,
109 &tw
->tw_v6_rcv_saddr
);
110 ipv6_addr_copy((struct in6_addr
*)r
->id
.tcpdiag_dst
,
114 nlh
->nlmsg_len
= skb
->tail
- b
;
118 r
->id
.tcpdiag_sport
= inet
->sport
;
119 r
->id
.tcpdiag_dport
= inet
->dport
;
120 r
->id
.tcpdiag_src
[0] = inet
->rcv_saddr
;
121 r
->id
.tcpdiag_dst
[0] = inet
->daddr
;
123 #ifdef CONFIG_IP_TCPDIAG_IPV6
124 if (r
->tcpdiag_family
== AF_INET6
) {
125 struct ipv6_pinfo
*np
= inet6_sk(sk
);
127 ipv6_addr_copy((struct in6_addr
*)r
->id
.tcpdiag_src
,
129 ipv6_addr_copy((struct in6_addr
*)r
->id
.tcpdiag_dst
,
134 #define EXPIRES_IN_MS(tmo) ((tmo-jiffies)*1000+HZ-1)/HZ
136 if (tp
->pending
== TCP_TIME_RETRANS
) {
137 r
->tcpdiag_timer
= 1;
138 r
->tcpdiag_retrans
= tp
->retransmits
;
139 r
->tcpdiag_expires
= EXPIRES_IN_MS(tp
->timeout
);
140 } else if (tp
->pending
== TCP_TIME_PROBE0
) {
141 r
->tcpdiag_timer
= 4;
142 r
->tcpdiag_retrans
= tp
->probes_out
;
143 r
->tcpdiag_expires
= EXPIRES_IN_MS(tp
->timeout
);
144 } else if (timer_pending(&sk
->sk_timer
)) {
145 r
->tcpdiag_timer
= 2;
146 r
->tcpdiag_retrans
= tp
->probes_out
;
147 r
->tcpdiag_expires
= EXPIRES_IN_MS(sk
->sk_timer
.expires
);
149 r
->tcpdiag_timer
= 0;
150 r
->tcpdiag_expires
= 0;
154 r
->tcpdiag_rqueue
= tp
->rcv_nxt
- tp
->copied_seq
;
155 r
->tcpdiag_wqueue
= tp
->write_seq
- tp
->snd_una
;
156 r
->tcpdiag_uid
= sock_i_uid(sk
);
157 r
->tcpdiag_inode
= sock_i_ino(sk
);
160 minfo
->tcpdiag_rmem
= atomic_read(&sk
->sk_rmem_alloc
);
161 minfo
->tcpdiag_wmem
= sk
->sk_wmem_queued
;
162 minfo
->tcpdiag_fmem
= sk
->sk_forward_alloc
;
163 minfo
->tcpdiag_tmem
= atomic_read(&sk
->sk_wmem_alloc
);
167 tcp_get_info(sk
, info
);
170 if (tcp_is_vegas(tp
)) {
171 vinfo
->tcpv_enabled
= tp
->vegas
.doing_vegas_now
;
172 vinfo
->tcpv_rttcnt
= tp
->vegas
.cntRTT
;
173 vinfo
->tcpv_rtt
= jiffies_to_usecs(tp
->vegas
.baseRTT
);
174 vinfo
->tcpv_minrtt
= jiffies_to_usecs(tp
->vegas
.minRTT
);
176 vinfo
->tcpv_enabled
= 0;
177 vinfo
->tcpv_rttcnt
= 0;
178 vinfo
->tcpv_rtt
= jiffies_to_usecs(tp
->westwood
.rtt
);
179 vinfo
->tcpv_minrtt
= jiffies_to_usecs(tp
->westwood
.rtt_min
);
183 nlh
->nlmsg_len
= skb
->tail
- b
;
187 skb_trim(skb
, b
- skb
->data
);
191 extern struct sock
*tcp_v4_lookup(u32 saddr
, u16 sport
, u32 daddr
, u16 dport
,
193 #ifdef CONFIG_IP_TCPDIAG_IPV6
194 extern struct sock
*tcp_v6_lookup(struct in6_addr
*saddr
, u16 sport
,
195 struct in6_addr
*daddr
, u16 dport
,
198 static inline struct sock
*tcp_v6_lookup(struct in6_addr
*saddr
, u16 sport
,
199 struct in6_addr
*daddr
, u16 dport
,
206 static int tcpdiag_get_exact(struct sk_buff
*in_skb
, const struct nlmsghdr
*nlh
)
210 struct tcpdiagreq
*req
= NLMSG_DATA(nlh
);
213 if (req
->tcpdiag_family
== AF_INET
) {
214 sk
= tcp_v4_lookup(req
->id
.tcpdiag_dst
[0], req
->id
.tcpdiag_dport
,
215 req
->id
.tcpdiag_src
[0], req
->id
.tcpdiag_sport
,
218 #ifdef CONFIG_IP_TCPDIAG_IPV6
219 else if (req
->tcpdiag_family
== AF_INET6
) {
220 sk
= tcp_v6_lookup((struct in6_addr
*)req
->id
.tcpdiag_dst
, req
->id
.tcpdiag_dport
,
221 (struct in6_addr
*)req
->id
.tcpdiag_src
, req
->id
.tcpdiag_sport
,
233 if ((req
->id
.tcpdiag_cookie
[0] != TCPDIAG_NOCOOKIE
||
234 req
->id
.tcpdiag_cookie
[1] != TCPDIAG_NOCOOKIE
) &&
235 ((u32
)(unsigned long)sk
!= req
->id
.tcpdiag_cookie
[0] ||
236 (u32
)((((unsigned long)sk
) >> 31) >> 1) != req
->id
.tcpdiag_cookie
[1]))
240 rep
= alloc_skb(NLMSG_SPACE(sizeof(struct tcpdiagmsg
)+
241 sizeof(struct tcpdiag_meminfo
)+
242 sizeof(struct tcp_info
)+64), GFP_KERNEL
);
246 if (tcpdiag_fill(rep
, sk
, req
->tcpdiag_ext
,
247 NETLINK_CB(in_skb
).pid
,
248 nlh
->nlmsg_seq
, 0) <= 0)
251 err
= netlink_unicast(tcpnl
, rep
, NETLINK_CB(in_skb
).pid
, MSG_DONTWAIT
);
257 if (sk
->sk_state
== TCP_TIME_WAIT
)
258 tcp_tw_put((struct tcp_tw_bucket
*)sk
);
265 static int bitstring_match(const u32
*a1
, const u32
*a2
, int bits
)
267 int words
= bits
>> 5;
272 if (memcmp(a1
, a2
, words
<< 2))
282 mask
= htonl((0xffffffff) << (32 - bits
));
284 if ((w1
^ w2
) & mask
)
292 static int tcpdiag_bc_run(const void *bc
, int len
,
293 const struct tcpdiag_entry
*entry
)
297 const struct tcpdiag_bc_op
*op
= bc
;
305 case TCPDIAG_BC_S_GE
:
306 yes
= entry
->sport
>= op
[1].no
;
308 case TCPDIAG_BC_S_LE
:
309 yes
= entry
->dport
<= op
[1].no
;
311 case TCPDIAG_BC_D_GE
:
312 yes
= entry
->dport
>= op
[1].no
;
314 case TCPDIAG_BC_D_LE
:
315 yes
= entry
->dport
<= op
[1].no
;
317 case TCPDIAG_BC_AUTO
:
318 yes
= !(entry
->userlocks
& SOCK_BINDPORT_LOCK
);
320 case TCPDIAG_BC_S_COND
:
321 case TCPDIAG_BC_D_COND
:
323 struct tcpdiag_hostcond
*cond
= (struct tcpdiag_hostcond
*)(op
+1);
326 if (cond
->port
!= -1 &&
327 cond
->port
!= (op
->code
== TCPDIAG_BC_S_COND
?
328 entry
->sport
: entry
->dport
)) {
333 if (cond
->prefix_len
== 0)
336 if (op
->code
== TCPDIAG_BC_S_COND
)
341 if (bitstring_match(addr
, cond
->addr
, cond
->prefix_len
))
343 if (entry
->family
== AF_INET6
&&
344 cond
->family
== AF_INET
) {
345 if (addr
[0] == 0 && addr
[1] == 0 &&
346 addr
[2] == htonl(0xffff) &&
347 bitstring_match(addr
+3, cond
->addr
, cond
->prefix_len
))
366 static int valid_cc(const void *bc
, int len
, int cc
)
369 const struct tcpdiag_bc_op
*op
= bc
;
383 static int tcpdiag_bc_audit(const void *bytecode
, int bytecode_len
)
385 const unsigned char *bc
= bytecode
;
386 int len
= bytecode_len
;
389 struct tcpdiag_bc_op
*op
= (struct tcpdiag_bc_op
*)bc
;
391 //printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
393 case TCPDIAG_BC_AUTO
:
394 case TCPDIAG_BC_S_COND
:
395 case TCPDIAG_BC_D_COND
:
396 case TCPDIAG_BC_S_GE
:
397 case TCPDIAG_BC_S_LE
:
398 case TCPDIAG_BC_D_GE
:
399 case TCPDIAG_BC_D_LE
:
400 if (op
->yes
< 4 || op
->yes
> len
+4)
403 if (op
->no
< 4 || op
->no
> len
+4)
406 !valid_cc(bytecode
, bytecode_len
, len
-op
->no
))
410 if (op
->yes
< 4 || op
->yes
> len
+4)
419 return len
== 0 ? 0 : -EINVAL
;
422 static int tcpdiag_dump_sock(struct sk_buff
*skb
, struct sock
*sk
,
423 struct netlink_callback
*cb
)
425 struct tcpdiagreq
*r
= NLMSG_DATA(cb
->nlh
);
427 if (cb
->nlh
->nlmsg_len
> 4 + NLMSG_SPACE(sizeof(*r
))) {
428 struct tcpdiag_entry entry
;
429 struct rtattr
*bc
= (struct rtattr
*)(r
+ 1);
430 struct inet_sock
*inet
= inet_sk(sk
);
432 entry
.family
= sk
->sk_family
;
433 #ifdef CONFIG_IP_TCPDIAG_IPV6
434 if (entry
.family
== AF_INET6
) {
435 struct ipv6_pinfo
*np
= inet6_sk(sk
);
437 entry
.saddr
= np
->rcv_saddr
.s6_addr32
;
438 entry
.daddr
= np
->daddr
.s6_addr32
;
442 entry
.saddr
= &inet
->rcv_saddr
;
443 entry
.daddr
= &inet
->daddr
;
445 entry
.sport
= inet
->num
;
446 entry
.dport
= ntohs(inet
->dport
);
447 entry
.userlocks
= sk
->sk_userlocks
;
449 if (!tcpdiag_bc_run(RTA_DATA(bc
), RTA_PAYLOAD(bc
), &entry
))
453 return tcpdiag_fill(skb
, sk
, r
->tcpdiag_ext
, NETLINK_CB(cb
->skb
).pid
,
454 cb
->nlh
->nlmsg_seq
, NLM_F_MULTI
);
457 static int tcpdiag_fill_req(struct sk_buff
*skb
, struct sock
*sk
,
458 struct request_sock
*req
,
461 const struct inet_request_sock
*ireq
= inet_rsk(req
);
462 struct inet_sock
*inet
= inet_sk(sk
);
463 unsigned char *b
= skb
->tail
;
464 struct tcpdiagmsg
*r
;
465 struct nlmsghdr
*nlh
;
468 nlh
= NLMSG_PUT(skb
, pid
, seq
, TCPDIAG_GETSOCK
, sizeof(*r
));
469 nlh
->nlmsg_flags
= NLM_F_MULTI
;
472 r
->tcpdiag_family
= sk
->sk_family
;
473 r
->tcpdiag_state
= TCP_SYN_RECV
;
474 r
->tcpdiag_timer
= 1;
475 r
->tcpdiag_retrans
= req
->retrans
;
477 r
->id
.tcpdiag_if
= sk
->sk_bound_dev_if
;
478 r
->id
.tcpdiag_cookie
[0] = (u32
)(unsigned long)req
;
479 r
->id
.tcpdiag_cookie
[1] = (u32
)(((unsigned long)req
>> 31) >> 1);
481 tmo
= req
->expires
- jiffies
;
485 r
->id
.tcpdiag_sport
= inet
->sport
;
486 r
->id
.tcpdiag_dport
= ireq
->rmt_port
;
487 r
->id
.tcpdiag_src
[0] = ireq
->loc_addr
;
488 r
->id
.tcpdiag_dst
[0] = ireq
->rmt_addr
;
489 r
->tcpdiag_expires
= jiffies_to_msecs(tmo
),
490 r
->tcpdiag_rqueue
= 0;
491 r
->tcpdiag_wqueue
= 0;
492 r
->tcpdiag_uid
= sock_i_uid(sk
);
493 r
->tcpdiag_inode
= 0;
494 #ifdef CONFIG_IP_TCPDIAG_IPV6
495 if (r
->tcpdiag_family
== AF_INET6
) {
496 ipv6_addr_copy((struct in6_addr
*)r
->id
.tcpdiag_src
,
497 &tcp6_rsk(req
)->loc_addr
);
498 ipv6_addr_copy((struct in6_addr
*)r
->id
.tcpdiag_dst
,
499 &tcp6_rsk(req
)->rmt_addr
);
502 nlh
->nlmsg_len
= skb
->tail
- b
;
507 skb_trim(skb
, b
- skb
->data
);
511 static int tcpdiag_dump_reqs(struct sk_buff
*skb
, struct sock
*sk
,
512 struct netlink_callback
*cb
)
514 struct tcpdiag_entry entry
;
515 struct tcpdiagreq
*r
= NLMSG_DATA(cb
->nlh
);
516 struct tcp_sock
*tp
= tcp_sk(sk
);
517 struct listen_sock
*lopt
;
518 struct rtattr
*bc
= NULL
;
519 struct inet_sock
*inet
= inet_sk(sk
);
521 int reqnum
, s_reqnum
;
525 s_reqnum
= cb
->args
[4];
530 entry
.family
= sk
->sk_family
;
532 read_lock_bh(&tp
->accept_queue
.syn_wait_lock
);
534 lopt
= tp
->accept_queue
.listen_opt
;
535 if (!lopt
|| !lopt
->qlen
)
538 if (cb
->nlh
->nlmsg_len
> 4 + NLMSG_SPACE(sizeof(*r
))) {
539 bc
= (struct rtattr
*)(r
+ 1);
540 entry
.sport
= inet
->num
;
541 entry
.userlocks
= sk
->sk_userlocks
;
544 for (j
= s_j
; j
< TCP_SYNQ_HSIZE
; j
++) {
545 struct request_sock
*req
, *head
= lopt
->syn_table
[j
];
548 for (req
= head
; req
; reqnum
++, req
= req
->dl_next
) {
549 struct inet_request_sock
*ireq
= inet_rsk(req
);
551 if (reqnum
< s_reqnum
)
553 if (r
->id
.tcpdiag_dport
!= ireq
->rmt_port
&&
559 #ifdef CONFIG_IP_TCPDIAG_IPV6
560 (entry
.family
== AF_INET6
) ?
561 tcp6_rsk(req
)->loc_addr
.s6_addr32
:
565 #ifdef CONFIG_IP_TCPDIAG_IPV6
566 (entry
.family
== AF_INET6
) ?
567 tcp6_rsk(req
)->rmt_addr
.s6_addr32
:
570 entry
.dport
= ntohs(ireq
->rmt_port
);
572 if (!tcpdiag_bc_run(RTA_DATA(bc
),
573 RTA_PAYLOAD(bc
), &entry
))
577 err
= tcpdiag_fill_req(skb
, sk
, req
,
578 NETLINK_CB(cb
->skb
).pid
,
582 cb
->args
[4] = reqnum
;
591 read_unlock_bh(&tp
->accept_queue
.syn_wait_lock
);
596 static int tcpdiag_dump(struct sk_buff
*skb
, struct netlink_callback
*cb
)
600 struct tcpdiagreq
*r
= NLMSG_DATA(cb
->nlh
);
603 s_num
= num
= cb
->args
[2];
605 if (cb
->args
[0] == 0) {
606 if (!(r
->tcpdiag_states
&(TCPF_LISTEN
|TCPF_SYN_RECV
)))
609 for (i
= s_i
; i
< TCP_LHTABLE_SIZE
; i
++) {
611 struct hlist_node
*node
;
614 sk_for_each(sk
, node
, &tcp_listening_hash
[i
]) {
615 struct inet_sock
*inet
= inet_sk(sk
);
622 if (r
->id
.tcpdiag_sport
!= inet
->sport
&&
626 if (!(r
->tcpdiag_states
&TCPF_LISTEN
) ||
627 r
->id
.tcpdiag_dport
||
631 if (tcpdiag_dump_sock(skb
, sk
, cb
) < 0) {
637 if (!(r
->tcpdiag_states
&TCPF_SYN_RECV
))
640 if (tcpdiag_dump_reqs(skb
, sk
, cb
) < 0) {
658 s_i
= num
= s_num
= 0;
661 if (!(r
->tcpdiag_states
&~(TCPF_LISTEN
|TCPF_SYN_RECV
)))
664 for (i
= s_i
; i
< tcp_ehash_size
; i
++) {
665 struct tcp_ehash_bucket
*head
= &tcp_ehash
[i
];
667 struct hlist_node
*node
;
672 read_lock_bh(&head
->lock
);
675 sk_for_each(sk
, node
, &head
->chain
) {
676 struct inet_sock
*inet
= inet_sk(sk
);
680 if (!(r
->tcpdiag_states
& (1 << sk
->sk_state
)))
682 if (r
->id
.tcpdiag_sport
!= inet
->sport
&&
685 if (r
->id
.tcpdiag_dport
!= inet
->dport
&& r
->id
.tcpdiag_dport
)
687 if (tcpdiag_dump_sock(skb
, sk
, cb
) < 0) {
688 read_unlock_bh(&head
->lock
);
695 if (r
->tcpdiag_states
&TCPF_TIME_WAIT
) {
696 sk_for_each(sk
, node
,
697 &tcp_ehash
[i
+ tcp_ehash_size
].chain
) {
698 struct inet_sock
*inet
= inet_sk(sk
);
702 if (r
->id
.tcpdiag_sport
!= inet
->sport
&&
705 if (r
->id
.tcpdiag_dport
!= inet
->dport
&&
708 if (tcpdiag_dump_sock(skb
, sk
, cb
) < 0) {
709 read_unlock_bh(&head
->lock
);
716 read_unlock_bh(&head
->lock
);
725 static int tcpdiag_dump_done(struct netlink_callback
*cb
)
731 static __inline__
int
732 tcpdiag_rcv_msg(struct sk_buff
*skb
, struct nlmsghdr
*nlh
)
734 if (!(nlh
->nlmsg_flags
&NLM_F_REQUEST
))
737 if (nlh
->nlmsg_type
!= TCPDIAG_GETSOCK
)
740 if (NLMSG_LENGTH(sizeof(struct tcpdiagreq
)) > skb
->len
)
743 if (nlh
->nlmsg_flags
&NLM_F_DUMP
) {
744 if (nlh
->nlmsg_len
> 4 + NLMSG_SPACE(sizeof(struct tcpdiagreq
))) {
745 struct rtattr
*rta
= (struct rtattr
*)(NLMSG_DATA(nlh
) + sizeof(struct tcpdiagreq
));
746 if (rta
->rta_type
!= TCPDIAG_REQ_BYTECODE
||
748 rta
->rta_len
> nlh
->nlmsg_len
- NLMSG_SPACE(sizeof(struct tcpdiagreq
)))
750 if (tcpdiag_bc_audit(RTA_DATA(rta
), RTA_PAYLOAD(rta
)))
753 return netlink_dump_start(tcpnl
, skb
, nlh
,
757 return tcpdiag_get_exact(skb
, nlh
);
765 static inline void tcpdiag_rcv_skb(struct sk_buff
*skb
)
768 struct nlmsghdr
* nlh
;
770 if (skb
->len
>= NLMSG_SPACE(0)) {
771 nlh
= (struct nlmsghdr
*)skb
->data
;
772 if (nlh
->nlmsg_len
< sizeof(*nlh
) || skb
->len
< nlh
->nlmsg_len
)
774 err
= tcpdiag_rcv_msg(skb
, nlh
);
775 if (err
|| nlh
->nlmsg_flags
& NLM_F_ACK
)
776 netlink_ack(skb
, nlh
, err
);
780 static void tcpdiag_rcv(struct sock
*sk
, int len
)
783 unsigned int qlen
= skb_queue_len(&sk
->sk_receive_queue
);
785 while (qlen
-- && (skb
= skb_dequeue(&sk
->sk_receive_queue
))) {
786 tcpdiag_rcv_skb(skb
);
791 static int __init
tcpdiag_init(void)
793 tcpnl
= netlink_kernel_create(NETLINK_TCPDIAG
, tcpdiag_rcv
);
799 static void __exit
tcpdiag_exit(void)
801 sock_release(tcpnl
->sk_socket
);
804 module_init(tcpdiag_init
);
805 module_exit(tcpdiag_exit
);
806 MODULE_LICENSE("GPL");