root/net/inet/dev_mcast.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dev_mc_upload
  2. dev_mc_delete
  3. dev_mc_add
  4. dev_mc_discard

   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  *      This program is free software; you can redistribute it and/or
  12  *      modify it under the terms of the GNU General Public License
  13  *      as published by the Free Software Foundation; either version
  14  *      2 of the License, or (at your option) any later version.
  15  */
  16  
  17 #include <asm/segment.h>
  18 #include <asm/system.h>
  19 #include <asm/bitops.h>
  20 #include <linux/config.h>
  21 #include <linux/types.h>
  22 #include <linux/kernel.h>
  23 #include <linux/sched.h>
  24 #include <linux/string.h>
  25 #include <linux/mm.h>
  26 #include <linux/socket.h>
  27 #include <linux/sockios.h>
  28 #include <linux/in.h>
  29 #include <linux/errno.h>
  30 #include <linux/interrupt.h>
  31 #include <linux/if_ether.h>
  32 #include <linux/inet.h>
  33 #include <linux/netdevice.h>
  34 #include <linux/etherdevice.h>
  35 #include "ip.h"
  36 #include "route.h"
  37 #include <linux/skbuff.h>
  38 #include "sock.h"
  39 #include "arp.h"
  40 
  41 
  42 /*
  43  *      Device multicast list maintenance. This knows about such little matters as promiscuous mode and
  44  *      converting from the list to the array the drivers use. At least until I fix the drivers up.
  45  *
  46  *      This is used both by IP and by the user level maintenance functions. Unlike BSD we maintain a usage count
  47  *      on a given multicast address so that a casual user application can add/delete multicasts used by protocols
  48  *      without doing damage to the protocols when it deletes the entries. It also helps IP as it tracks overlapping
  49  *      maps.
  50  */
  51  
  52 
  53 /*
  54  *      Update the multicast list into the physical NIC controller.
  55  */
  56  
  57 void dev_mc_upload(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59         struct dev_mc_list *dmi;
  60         char *data, *tmp;
  61 
  62         /* Don't do anything till we up the interface
  63            [dev_open will call this function so the list will
  64             stay sane] */
  65             
  66         if(!(dev->flags&IFF_UP))
  67                 return;
  68                 
  69                 
  70         /* Devices with no set multicast don't get set */
  71         if(dev->set_multicast_list==NULL)
  72                 return;
  73         /* Promiscuous is promiscuous - so no filter needed */
  74         if(dev->flags&IFF_PROMISC)
  75         {
  76                 dev->set_multicast_list(dev, -1, NULL);
  77                 return;
  78         }
  79         
  80         if(dev->mc_count==0)
  81         {
  82                 dev->set_multicast_list(dev,0,NULL);
  83                 return;
  84         }
  85         
  86         data=kmalloc(dev->mc_count*dev->addr_len, GFP_KERNEL);
  87         if(data==NULL)
  88         {
  89                 printk("Unable to get memory to set multicast list on %s\n",dev->name);
  90                 return;
  91         }
  92         for(tmp = data, dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
  93         {
  94                 memcpy(tmp,dmi->dmi_addr, dmi->dmi_addrlen);
  95                 tmp+=dev->addr_len;
  96         }
  97         dev->set_multicast_list(dev,dev->mc_count,data);
  98         kfree(data);
  99 }
 100   
 101 /*
 102  *      Delete a device level multicast
 103  */
 104  
 105 void dev_mc_delete(struct device *dev, void *addr, int alen, int all)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107         struct dev_mc_list **dmi;
 108         for(dmi=&dev->mc_list;*dmi!=NULL;dmi=&(*dmi)->next)
 109         {
 110                 if(memcmp((*dmi)->dmi_addr,addr,(*dmi)->dmi_addrlen)==0 && alen==(*dmi)->dmi_addrlen)
 111                 {
 112                         struct dev_mc_list *tmp= *dmi;
 113                         if((*dmi)->dmi_users-- && !all)
 114                                 return;
 115                         *dmi=(*dmi)->next;
 116                         dev->mc_count--;
 117                         kfree_s(tmp,sizeof(*tmp));
 118                         return;
 119                 }
 120         }
 121         dev_mc_upload(dev);
 122 }
 123 
 124 /*
 125  *      Add a device level multicast
 126  */
 127  
 128 void dev_mc_add(struct device *dev, void *addr, int alen, int newonly)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130         struct dev_mc_list *dmi;
 131         for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
 132         {
 133                 if(memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen)
 134                 {
 135                         if(!newonly)
 136                                 dmi->dmi_users++;
 137                         return;
 138                 }
 139         }
 140         dmi=(struct dev_mc_list *)kmalloc(sizeof(*dmi),GFP_KERNEL);
 141         if(dmi==NULL)
 142                 return; /* GFP_KERNEL so can't happen anyway */
 143         memcpy(dmi->dmi_addr, addr, alen);
 144         dmi->dmi_addrlen=alen;
 145         dmi->next=dev->mc_list;
 146         dmi->dmi_users=1;
 147         dev->mc_list=dmi;
 148         dev->mc_count++;
 149         dev_mc_upload(dev);
 150 }
 151 
 152 /*
 153  *      Discard multicast list when a device is downed
 154  */
 155 
 156 void dev_mc_discard(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158         while(dev->mc_list!=NULL)
 159         {
 160                 struct dev_mc_list *tmp=dev->mc_list;
 161                 dev->mc_list=dev->mc_list->next;
 162                 kfree_s(tmp,sizeof(*tmp));
 163         }
 164         dev->mc_count=0;
 165 }
 166 

/* [previous][next][first][last][top][bottom][index][help] */