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

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