2005-04-17 02:20:36 +04:00
/*
2007-02-09 17:24:36 +03:00
* Linux NET3 : Multicast List maintenance .
2005-04-17 02:20:36 +04:00
*
* Authors :
2007-02-09 17:24:36 +03:00
* Tim Kordas < tjk @ nostromo . eeap . cwru . edu >
2005-04-17 02:20:36 +04:00
* Richard Underwood < richard @ wuzz . demon . co . uk >
*
* Stir fried together from the IP multicast and CAP patches above
2008-10-14 06:01:08 +04:00
* Alan Cox < alan @ lxorguk . ukuu . org . uk >
2005-04-17 02:20:36 +04:00
*
* Fixes :
* Alan Cox : Update the device on a real delete
* rather than any time but . . .
* Alan Cox : IFF_ALLMULTI support .
* Alan Cox : New format set_multicast_list ( ) calls .
* Gleb Natapov : Remove dev_mc_lock .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
2006-09-23 01:00:29 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <asm/system.h>
# include <linux/bitops.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/socket.h>
# include <linux/sockios.h>
# include <linux/in.h>
# include <linux/errno.h>
# include <linux/interrupt.h>
# include <linux/if_ether.h>
# include <linux/inet.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <linux/init.h>
2007-09-12 14:01:34 +04:00
# include <net/net_namespace.h>
2005-04-17 02:20:36 +04:00
# include <net/ip.h>
# include <net/route.h>
# include <linux/skbuff.h>
# include <net/sock.h>
# include <net/arp.h>
/*
2007-02-09 17:24:36 +03:00
* Device multicast list maintenance .
2005-04-17 02:20:36 +04:00
*
2007-02-09 17:24:36 +03:00
* This is used both by IP and by the user level maintenance functions .
* Unlike BSD we maintain a usage count on a given multicast address so
* that a casual user application can add / delete multicasts used by
2005-04-17 02:20:36 +04:00
* protocols without doing damage to the protocols when it deletes the
* entries . It also helps IP as it tracks overlapping maps .
*
* Device mc lists are changed by bh at least if IPv6 is enabled ,
* so that it must be bh protected .
*
2006-06-09 23:20:56 +04:00
* We block accesses to device mc filters with netif_tx_lock .
2005-04-17 02:20:36 +04:00
*/
/*
* Delete a device level multicast
*/
2007-02-09 17:24:36 +03:00
2005-04-17 02:20:36 +04:00
int dev_mc_delete ( struct net_device * dev , void * addr , int alen , int glbl )
{
2007-06-27 12:26:58 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2008-07-15 11:15:08 +04:00
netif_addr_lock_bh ( dev ) ;
2007-07-01 00:35:52 +04:00
err = __dev_addr_delete ( & dev - > mc_list , & dev - > mc_count ,
addr , alen , glbl ) ;
2007-06-27 12:26:58 +04:00
if ( ! err ) {
2005-04-17 02:20:36 +04:00
/*
2007-06-27 12:26:58 +04:00
* We have altered the list , so the card
* loaded filter is now wrong . Fix it
2005-04-17 02:20:36 +04:00
*/
2007-06-27 12:26:58 +04:00
2007-06-27 12:28:10 +04:00
__dev_set_rx_mode ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-15 11:15:08 +04:00
netif_addr_unlock_bh ( dev ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
/*
* Add a device level multicast
*/
2007-02-09 17:24:36 +03:00
2005-04-17 02:20:36 +04:00
int dev_mc_add ( struct net_device * dev , void * addr , int alen , int glbl )
{
2007-06-27 12:26:58 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2008-07-15 11:15:08 +04:00
netif_addr_lock_bh ( dev ) ;
2007-07-01 00:35:52 +04:00
err = __dev_addr_add ( & dev - > mc_list , & dev - > mc_count , addr , alen , glbl ) ;
if ( ! err )
2007-06-27 12:28:10 +04:00
__dev_set_rx_mode ( dev ) ;
2008-07-15 11:15:08 +04:00
netif_addr_unlock_bh ( dev ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
2007-07-15 05:52:02 +04:00
/**
* dev_mc_sync - Synchronize device ' s multicast list to another device
* @ to : destination device
* @ from : source device
*
* Add newly added addresses to the destination device and release
* addresses that have no users left . The source device must be
* locked by netif_tx_lock_bh .
*
* This function is intended to be called from the dev - > set_multicast_list
2008-02-01 03:53:23 +03:00
* or dev - > set_rx_mode function of layered software devices .
2007-07-15 05:52:02 +04:00
*/
int dev_mc_sync ( struct net_device * to , struct net_device * from )
{
int err = 0 ;
2008-07-15 11:15:08 +04:00
netif_addr_lock_bh ( to ) ;
2008-02-01 03:53:23 +03:00
err = __dev_addr_sync ( & to - > mc_list , & to - > mc_count ,
& from - > mc_list , & from - > mc_count ) ;
2007-07-15 05:52:02 +04:00
if ( ! err )
__dev_set_rx_mode ( to ) ;
2008-07-15 11:15:08 +04:00
netif_addr_unlock_bh ( to ) ;
2007-07-15 05:52:02 +04:00
return err ;
}
EXPORT_SYMBOL ( dev_mc_sync ) ;
/**
* dev_mc_unsync - Remove synchronized addresses from the destination
* device
* @ to : destination device
* @ from : source device
*
* Remove all addresses that were added to the destination device by
* dev_mc_sync ( ) . This function is intended to be called from the
* dev - > stop function of layered software devices .
*/
void dev_mc_unsync ( struct net_device * to , struct net_device * from )
{
2008-07-15 11:15:08 +04:00
netif_addr_lock_bh ( from ) ;
2008-07-15 11:13:44 +04:00
netif_addr_lock ( to ) ;
2007-07-15 05:52:02 +04:00
2008-02-01 03:53:23 +03:00
__dev_addr_unsync ( & to - > mc_list , & to - > mc_count ,
& from - > mc_list , & from - > mc_count ) ;
2007-07-15 05:52:02 +04:00
__dev_set_rx_mode ( to ) ;
2008-07-15 11:13:44 +04:00
netif_addr_unlock ( to ) ;
2008-07-15 11:15:08 +04:00
netif_addr_unlock_bh ( from ) ;
2007-07-15 05:52:02 +04:00
}
EXPORT_SYMBOL ( dev_mc_unsync ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PROC_FS
static int dev_mc_seq_show ( struct seq_file * seq , void * v )
{
2007-06-27 12:26:58 +04:00
struct dev_addr_list * m ;
2005-04-17 02:20:36 +04:00
struct net_device * dev = v ;
2008-02-29 22:44:14 +03:00
if ( v = = SEQ_START_TOKEN )
return 0 ;
2008-07-15 11:15:08 +04:00
netif_addr_lock_bh ( dev ) ;
2005-04-17 02:20:36 +04:00
for ( m = dev - > mc_list ; m ; m = m - > next ) {
int i ;
seq_printf ( seq , " %-4d %-15s %-5d %-5d " , dev - > ifindex ,
dev - > name , m - > dmi_users , m - > dmi_gusers ) ;
for ( i = 0 ; i < m - > dmi_addrlen ; i + + )
seq_printf ( seq , " %02x " , m - > dmi_addr [ i ] ) ;
seq_putc ( seq , ' \n ' ) ;
}
2008-07-15 11:15:08 +04:00
netif_addr_unlock_bh ( dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-03-13 00:34:29 +03:00
static const struct seq_operations dev_mc_seq_ops = {
2008-02-29 22:44:14 +03:00
. start = dev_seq_start ,
. next = dev_seq_next ,
. stop = dev_seq_stop ,
2005-04-17 02:20:36 +04:00
. show = dev_mc_seq_show ,
} ;
static int dev_mc_seq_open ( struct inode * inode , struct file * file )
{
2007-11-20 09:31:54 +03:00
return seq_open_net ( inode , file , & dev_mc_seq_ops ,
sizeof ( struct seq_net_private ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:35 +03:00
static const struct file_operations dev_mc_seq_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. open = dev_mc_seq_open ,
. read = seq_read ,
. llseek = seq_lseek ,
2007-11-20 09:31:54 +03:00
. release = seq_release_net ,
2005-04-17 02:20:36 +04:00
} ;
# endif
2007-10-09 07:38:39 +04:00
static int __net_init dev_mc_net_init ( struct net * net )
2007-09-17 22:56:21 +04:00
{
if ( ! proc_net_fops_create ( net , " dev_mcast " , 0 , & dev_mc_seq_fops ) )
return - ENOMEM ;
return 0 ;
}
2007-10-09 07:38:39 +04:00
static void __net_exit dev_mc_net_exit ( struct net * net )
2007-09-17 22:56:21 +04:00
{
proc_net_remove ( net , " dev_mcast " ) ;
}
2007-11-13 14:23:50 +03:00
static struct pernet_operations __net_initdata dev_mc_net_ops = {
2007-09-17 22:56:21 +04:00
. init = dev_mc_net_init ,
. exit = dev_mc_net_exit ,
} ;
2005-04-17 02:20:36 +04:00
void __init dev_mcast_init ( void )
{
2007-09-17 22:56:21 +04:00
register_pernet_subsys ( & dev_mc_net_ops ) ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( dev_mc_add ) ;
EXPORT_SYMBOL ( dev_mc_delete ) ;