@@ -640,21 +640,65 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
640640 RTM_NEWTFILTER );
641641}
642642
643+ static void tcf_chain_dump (struct tcf_chain * chain , struct sk_buff * skb ,
644+ struct netlink_callback * cb ,
645+ long index_start , long * p_index )
646+ {
647+ struct net * net = sock_net (skb -> sk );
648+ struct tcmsg * tcm = nlmsg_data (cb -> nlh );
649+ struct tcf_dump_args arg ;
650+ struct tcf_proto * tp ;
651+
652+ for (tp = rtnl_dereference (chain -> filter_chain );
653+ tp ; tp = rtnl_dereference (tp -> next ), (* p_index )++ ) {
654+ if (* p_index < index_start )
655+ continue ;
656+ if (TC_H_MAJ (tcm -> tcm_info ) &&
657+ TC_H_MAJ (tcm -> tcm_info ) != tp -> prio )
658+ continue ;
659+ if (TC_H_MIN (tcm -> tcm_info ) &&
660+ TC_H_MIN (tcm -> tcm_info ) != tp -> protocol )
661+ continue ;
662+ if (* p_index > index_start )
663+ memset (& cb -> args [1 ], 0 ,
664+ sizeof (cb -> args ) - sizeof (cb -> args [0 ]));
665+ if (cb -> args [1 ] == 0 ) {
666+ if (tcf_fill_node (net , skb , tp , 0 ,
667+ NETLINK_CB (cb -> skb ).portid ,
668+ cb -> nlh -> nlmsg_seq , NLM_F_MULTI ,
669+ RTM_NEWTFILTER ) <= 0 )
670+ break ;
671+
672+ cb -> args [1 ] = 1 ;
673+ }
674+ if (!tp -> ops -> walk )
675+ continue ;
676+ arg .w .fn = tcf_node_dump ;
677+ arg .skb = skb ;
678+ arg .cb = cb ;
679+ arg .w .stop = 0 ;
680+ arg .w .skip = cb -> args [1 ] - 1 ;
681+ arg .w .count = 0 ;
682+ tp -> ops -> walk (tp , & arg .w );
683+ cb -> args [1 ] = arg .w .count + 1 ;
684+ if (arg .w .stop )
685+ break ;
686+ }
687+ }
688+
643689/* called with RTNL */
644690static int tc_dump_tfilter (struct sk_buff * skb , struct netlink_callback * cb )
645691{
646692 struct net * net = sock_net (skb -> sk );
647- int t ;
648- int s_t ;
649693 struct net_device * dev ;
650694 struct Qdisc * q ;
651695 struct tcf_block * block ;
652- struct tcf_proto * tp ;
653696 struct tcf_chain * chain ;
654697 struct tcmsg * tcm = nlmsg_data (cb -> nlh );
655698 unsigned long cl = 0 ;
656699 const struct Qdisc_class_ops * cops ;
657- struct tcf_dump_args arg ;
700+ long index_start ;
701+ long index ;
658702
659703 if (nlmsg_len (cb -> nlh ) < sizeof (* tcm ))
660704 return skb -> len ;
@@ -683,45 +727,10 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
683727 goto errout ;
684728 chain = block -> chain ;
685729
686- s_t = cb -> args [0 ];
687-
688- for (tp = rtnl_dereference (chain -> filter_chain ), t = 0 ;
689- tp ; tp = rtnl_dereference (tp -> next ), t ++ ) {
690- if (t < s_t )
691- continue ;
692- if (TC_H_MAJ (tcm -> tcm_info ) &&
693- TC_H_MAJ (tcm -> tcm_info ) != tp -> prio )
694- continue ;
695- if (TC_H_MIN (tcm -> tcm_info ) &&
696- TC_H_MIN (tcm -> tcm_info ) != tp -> protocol )
697- continue ;
698- if (t > s_t )
699- memset (& cb -> args [1 ], 0 ,
700- sizeof (cb -> args )- sizeof (cb -> args [0 ]));
701- if (cb -> args [1 ] == 0 ) {
702- if (tcf_fill_node (net , skb , tp , 0 ,
703- NETLINK_CB (cb -> skb ).portid ,
704- cb -> nlh -> nlmsg_seq , NLM_F_MULTI ,
705- RTM_NEWTFILTER ) <= 0 )
706- break ;
707-
708- cb -> args [1 ] = 1 ;
709- }
710- if (tp -> ops -> walk == NULL )
711- continue ;
712- arg .w .fn = tcf_node_dump ;
713- arg .skb = skb ;
714- arg .cb = cb ;
715- arg .w .stop = 0 ;
716- arg .w .skip = cb -> args [1 ] - 1 ;
717- arg .w .count = 0 ;
718- tp -> ops -> walk (tp , & arg .w );
719- cb -> args [1 ] = arg .w .count + 1 ;
720- if (arg .w .stop )
721- break ;
722- }
723-
724- cb -> args [0 ] = t ;
730+ index_start = cb -> args [0 ];
731+ index = 0 ;
732+ tcf_chain_dump (chain , skb , cb , index_start , & index );
733+ cb -> args [0 ] = index ;
725734
726735errout :
727736 if (cl )
0 commit comments