Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  *      Linux NET3:     Multicast List maintenance.
  3  *
  4  *      Authors:
  5  *              Tim Kordas <tjk@nostromo.eeap.cwru.edu>
  6  *              Richard Underwood <richard@wuzz.demon.co.uk>
  7  *
  8  *      Stir fried together from the IP multicast and CAP patches above
  9  *              Alan Cox <Alan.Cox@linux.org>
 10  *
 11  *      Fixes:
 12  *              Alan Cox        :       Update the device on a real delete
 13  *                                      rather than any time but...
 14  *              Alan Cox        :       IFF_ALLMULTI support.
 15  *              Alan Cox        :       New format set_multicast_list() calls.
 16  *              Gleb Natapov    :       Remove dev_mc_lock.
 17  *
 18  *      This program is free software; you can redistribute it and/or
 19  *      modify it under the terms of the GNU General Public License
 20  *      as published by the Free Software Foundation; either version
 21  *      2 of the License, or (at your option) any later version.
 22  */
 23 
 24 #include <linux/module.h>
 25 #include <asm/uaccess.h>
 26 #include <asm/system.h>
 27 #include <linux/bitops.h>
 28 #include <linux/types.h>
 29 #include <linux/kernel.h>
 30 #include <linux/string.h>
 31 #include <linux/mm.h>
 32 #include <linux/socket.h>
 33 #include <linux/sockios.h>
 34 #include <linux/in.h>
 35 #include <linux/errno.h>
 36 #include <linux/interrupt.h>
 37 #include <linux/if_ether.h>
 38 #include <linux/inet.h>
 39 #include <linux/netdevice.h>
 40 #include <linux/etherdevice.h>
 41 #include <linux/proc_fs.h>
 42 #include <linux/seq_file.h>
 43 #include <linux/init.h>
 44 #include <net/net_namespace.h>
 45 #include <net/ip.h>
 46 #include <net/route.h>
 47 #include <linux/skbuff.h>
 48 #include <net/sock.h>
 49 #include <net/arp.h>
 50 
 51 
 52 /*
 53  *      Device multicast list maintenance.
 54  *
 55  *      This is used both by IP and by the user level maintenance functions.
 56  *      Unlike BSD we maintain a usage count on a given multicast address so
 57  *      that a casual user application can add/delete multicasts used by
 58  *      protocols without doing damage to the protocols when it deletes the
 59  *      entries. It also helps IP as it tracks overlapping maps.
 60  *
 61  *      Device mc lists are changed by bh at least if IPv6 is enabled,
 62  *      so that it must be bh protected.
 63  *
 64  *      We block accesses to device mc filters with netif_tx_lock.
 65  */
 66 
 67 /*
 68  *      Delete a device level multicast
 69  */
 70 
 71 int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl)
 72 {
 73         int err;
 74 
 75         netif_tx_lock_bh(dev);
 76         err = __dev_addr_delete(&dev->mc_list, &dev->mc_count,
 77                                 addr, alen, glbl);
 78         if (!err) {
 79                 /*
 80                  *      We have altered the list, so the card
 81                  *      loaded filter is now wrong. Fix it
 82                  */
 83 
 84                 __dev_set_rx_mode(dev);
 85         }
 86         netif_tx_unlock_bh(dev);
 87         return err;
 88 }
 89 
 90 /*
 91  *      Add a device level multicast
 92  */
 93 
 94 int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
 95 {
 96         int err;
 97 
 98         netif_tx_lock_bh(dev);
 99         err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl);
100         if (!err)
101                 __dev_set_rx_mode(dev);
102         netif_tx_unlock_bh(dev);
103         return err;
104 }
105 
106 /**
107  *      dev_mc_sync     - Synchronize device's multicast list to another device
108  *      @to: destination device
109  *      @from: source device
110  *
111  *      Add newly added addresses to the destination device and release
112  *      addresses that have no users left. The source device must be
113  *      locked by netif_tx_lock_bh.
114  *
115  *      This function is intended to be called from the dev->set_multicast_list
116  *      or dev->set_rx_mode function of layered software devices.
117  */
118 int dev_mc_sync(struct net_device *to, struct net_device *from)
119 {
120         int err = 0;
121 
122         netif_tx_lock_bh(to);
123         err = __dev_addr_sync(&to->mc_list, &to->mc_count,
124                               &from->mc_list, &from->mc_count);
125         if (!err)
126                 __dev_set_rx_mode(to);
127         netif_tx_unlock_bh(to);
128 
129         return err;
130 }
131 EXPORT_SYMBOL(dev_mc_sync);
132 
133 
134 /**
135  *      dev_mc_unsync   - Remove synchronized addresses from the destination
136  *                        device
137  *      @to: destination device
138  *      @from: source device
139  *
140  *      Remove all addresses that were added to the destination device by
141  *      dev_mc_sync(). This function is intended to be called from the
142  *      dev->stop function of layered software devices.
143  */
144 void dev_mc_unsync(struct net_device *to, struct net_device *from)
145 {
146         netif_tx_lock_bh(from);
147         netif_tx_lock_bh(to);
148 
149         __dev_addr_unsync(&to->mc_list, &to->mc_count,
150                           &from->mc_list, &from->mc_count);
151         __dev_set_rx_mode(to);
152 
153         netif_tx_unlock_bh(to);
154         netif_tx_unlock_bh(from);
155 }
156 EXPORT_SYMBOL(dev_mc_unsync);
157 
158 #ifdef CONFIG_PROC_FS
159 static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
160         __acquires(dev_base_lock)
161 {
162         struct net *net = seq_file_net(seq);
163         struct net_device *dev;
164         loff_t off = 0;
165 
166         read_lock(&dev_base_lock);
167         for_each_netdev(net, dev) {
168                 if (off++ == *pos)
169                         return dev;
170         }
171         return NULL;
172 }
173 
174 static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
175 {
176         ++*pos;
177         return next_net_device((struct net_device *)v);
178 }
179 
180 static void dev_mc_seq_stop(struct seq_file *seq, void *v)
181         __releases(dev_base_lock)
182 {
183         read_unlock(&dev_base_lock);
184 }
185 
186 
187 static int dev_mc_seq_show(struct seq_file *seq, void *v)
188 {
189         struct dev_addr_list *m;
190         struct net_device *dev = v;
191 
192         netif_tx_lock_bh(dev);
193         for (m = dev->mc_list; m; m = m->next) {
194                 int i;
195 
196                 seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex,
197                            dev->name, m->dmi_users, m->dmi_gusers);
198 
199                 for (i = 0; i < m->dmi_addrlen; i++)
200                         seq_printf(seq, "%02x", m->dmi_addr[i]);
201 
202                 seq_putc(seq, '\n');
203         }
204         netif_tx_unlock_bh(dev);
205         return 0;
206 }
207 
208 static const struct seq_operations dev_mc_seq_ops = {
209         .start = dev_mc_seq_start,
210         .next  = dev_mc_seq_next,
211         .stop  = dev_mc_seq_stop,
212         .show  = dev_mc_seq_show,
213 };
214 
215 static int dev_mc_seq_open(struct inode *inode, struct file *file)
216 {
217         return seq_open_net(inode, file, &dev_mc_seq_ops,
218                             sizeof(struct seq_net_private));
219 }
220 
221 static const struct file_operations dev_mc_seq_fops = {
222         .owner   = THIS_MODULE,
223         .open    = dev_mc_seq_open,
224         .read    = seq_read,
225         .llseek  = seq_lseek,
226         .release = seq_release_net,
227 };
228 
229 #endif
230 
231 static int __net_init dev_mc_net_init(struct net *net)
232 {
233         if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops))
234                 return -ENOMEM;
235         return 0;
236 }
237 
238 static void __net_exit dev_mc_net_exit(struct net *net)
239 {
240         proc_net_remove(net, "dev_mcast");
241 }
242 
243 static struct pernet_operations __net_initdata dev_mc_net_ops = {
244         .init = dev_mc_net_init,
245         .exit = dev_mc_net_exit,
246 };
247 
248 void __init dev_mcast_init(void)
249 {
250         register_pernet_subsys(&dev_mc_net_ops);
251 }
252 
253 EXPORT_SYMBOL(dev_mc_add);
254 EXPORT_SYMBOL(dev_mc_delete);
255 
  This page was automatically generated by the LXR engine.