@@ -1676,7 +1676,7 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
16761676 return nla_put (skb , IFA_CACHEINFO , sizeof (ci ), & ci );
16771677}
16781678
1679- static int inet_fill_ifaddr (struct sk_buff * skb , struct in_ifaddr * ifa ,
1679+ static int inet_fill_ifaddr (struct sk_buff * skb , const struct in_ifaddr * ifa ,
16801680 struct inet_fill_args * args )
16811681{
16821682 struct ifaddrmsg * ifm ;
@@ -1805,15 +1805,15 @@ static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh,
18051805}
18061806
18071807static int in_dev_dump_addr (struct in_device * in_dev , struct sk_buff * skb ,
1808- struct netlink_callback * cb , int s_ip_idx ,
1808+ struct netlink_callback * cb , int * s_ip_idx ,
18091809 struct inet_fill_args * fillargs )
18101810{
18111811 struct in_ifaddr * ifa ;
18121812 int ip_idx = 0 ;
18131813 int err ;
18141814
1815- in_dev_for_each_ifa_rtnl (ifa , in_dev ) {
1816- if (ip_idx < s_ip_idx ) {
1815+ in_dev_for_each_ifa_rcu (ifa , in_dev ) {
1816+ if (ip_idx < * s_ip_idx ) {
18171817 ip_idx ++ ;
18181818 continue ;
18191819 }
@@ -1825,9 +1825,9 @@ static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb,
18251825 ip_idx ++ ;
18261826 }
18271827 err = 0 ;
1828-
1828+ ip_idx = 0 ;
18291829done :
1830- cb -> args [ 2 ] = ip_idx ;
1830+ * s_ip_idx = ip_idx ;
18311831
18321832 return err ;
18331833}
@@ -1859,75 +1859,53 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
18591859 };
18601860 struct net * net = sock_net (skb -> sk );
18611861 struct net * tgt_net = net ;
1862- int h , s_h ;
1863- int idx , s_idx ;
1864- int s_ip_idx ;
1865- struct net_device * dev ;
1862+ struct {
1863+ unsigned long ifindex ;
1864+ int ip_idx ;
1865+ } * ctx = ( void * ) cb -> ctx ;
18661866 struct in_device * in_dev ;
1867- struct hlist_head * head ;
1867+ struct net_device * dev ;
18681868 int err = 0 ;
18691869
1870- s_h = cb -> args [0 ];
1871- s_idx = idx = cb -> args [1 ];
1872- s_ip_idx = cb -> args [2 ];
1873-
1870+ rcu_read_lock ();
18741871 if (cb -> strict_check ) {
18751872 err = inet_valid_dump_ifaddr_req (nlh , & fillargs , & tgt_net ,
18761873 skb -> sk , cb );
18771874 if (err < 0 )
1878- goto put_tgt_net ;
1875+ goto done ;
18791876
1880- err = 0 ;
18811877 if (fillargs .ifindex ) {
1882- dev = __dev_get_by_index (tgt_net , fillargs .ifindex );
1883- if (!dev ) {
1884- err = - ENODEV ;
1885- goto put_tgt_net ;
1886- }
1887-
1888- in_dev = __in_dev_get_rtnl (dev );
1889- if (in_dev ) {
1890- err = in_dev_dump_addr (in_dev , skb , cb , s_ip_idx ,
1891- & fillargs );
1892- }
1893- goto put_tgt_net ;
1894- }
1895- }
1896-
1897- for (h = s_h ; h < NETDEV_HASHENTRIES ; h ++ , s_idx = 0 ) {
1898- idx = 0 ;
1899- head = & tgt_net -> dev_index_head [h ];
1900- rcu_read_lock ();
1901- cb -> seq = inet_base_seq (tgt_net );
1902- hlist_for_each_entry_rcu (dev , head , index_hlist ) {
1903- if (idx < s_idx )
1904- goto cont ;
1905- if (h > s_h || idx > s_idx )
1906- s_ip_idx = 0 ;
1878+ err = - ENODEV ;
1879+ dev = dev_get_by_index_rcu (tgt_net , fillargs .ifindex );
1880+ if (!dev )
1881+ goto done ;
19071882 in_dev = __in_dev_get_rcu (dev );
19081883 if (!in_dev )
1909- goto cont ;
1910-
1911- err = in_dev_dump_addr (in_dev , skb , cb , s_ip_idx ,
1912- & fillargs );
1913- if (err < 0 ) {
1914- rcu_read_unlock ();
19151884 goto done ;
1916- }
1917- cont :
1918- idx ++ ;
1885+ err = in_dev_dump_addr ( in_dev , skb , cb , & ctx -> ip_idx ,
1886+ & fillargs );
1887+ goto done ;
19191888 }
1920- rcu_read_unlock ();
19211889 }
19221890
1891+ cb -> seq = inet_base_seq (tgt_net );
1892+
1893+ for_each_netdev_dump (net , dev , ctx -> ifindex ) {
1894+ in_dev = __in_dev_get_rcu (dev );
1895+ if (!in_dev )
1896+ continue ;
1897+ err = in_dev_dump_addr (in_dev , skb , cb , & ctx -> ip_idx ,
1898+ & fillargs );
1899+ if (err < 0 )
1900+ goto done ;
1901+ }
19231902done :
1924- cb -> args [0 ] = h ;
1925- cb -> args [1 ] = idx ;
1926- put_tgt_net :
1903+ if (err < 0 && likely (skb -> len ))
1904+ err = skb -> len ;
19271905 if (fillargs .netnsid >= 0 )
19281906 put_net (tgt_net );
1929-
1930- return skb -> len ? : err ;
1907+ rcu_read_unlock ();
1908+ return err ;
19311909}
19321910
19331911static void rtmsg_ifa (int event , struct in_ifaddr * ifa , struct nlmsghdr * nlh ,
@@ -2818,7 +2796,8 @@ void __init devinet_init(void)
28182796
28192797 rtnl_register (PF_INET , RTM_NEWADDR , inet_rtm_newaddr , NULL , 0 );
28202798 rtnl_register (PF_INET , RTM_DELADDR , inet_rtm_deladdr , NULL , 0 );
2821- rtnl_register (PF_INET , RTM_GETADDR , NULL , inet_dump_ifaddr , 0 );
2799+ rtnl_register (PF_INET , RTM_GETADDR , NULL , inet_dump_ifaddr ,
2800+ RTNL_FLAG_DUMP_UNLOCKED );
28222801 rtnl_register (PF_INET , RTM_GETNETCONF , inet_netconf_get_devconf ,
28232802 inet_netconf_dump_devconf ,
28242803 RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED );
0 commit comments