dev_mcast.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  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. #include <linux/config.h> 
  24. #include <asm/uaccess.h>
  25. #include <asm/system.h>
  26. #include <asm/bitops.h>
  27. #include <linux/types.h>
  28. #include <linux/kernel.h>
  29. #include <linux/sched.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/init.h>
  43. #include <net/ip.h>
  44. #include <net/route.h>
  45. #include <linux/skbuff.h>
  46. #include <net/sock.h>
  47. #include <net/arp.h>
  48. /*
  49.  * Device multicast list maintenance. 
  50.  *
  51.  * This is used both by IP and by the user level maintenance functions. 
  52.  * Unlike BSD we maintain a usage count on a given multicast address so 
  53.  * that a casual user application can add/delete multicasts used by 
  54.  * protocols without doing damage to the protocols when it deletes the
  55.  * entries. It also helps IP as it tracks overlapping maps.
  56.  *
  57.  * Device mc lists are changed by bh at least if IPv6 is enabled,
  58.  * so that it must be bh protected.
  59.  *
  60.  * We block accesses to device mc filters with dev->xmit_lock.
  61.  */
  62. /*
  63.  * Update the multicast list into the physical NIC controller.
  64.  */
  65.  
  66. static void __dev_mc_upload(struct net_device *dev)
  67. {
  68. /* Don't do anything till we up the interface
  69.  * [dev_open will call this function so the list will
  70.  * stay sane]
  71.  */
  72. if (!(dev->flags&IFF_UP))
  73. return;
  74. /*
  75.  * Devices with no set multicast or which have been
  76.  * detached don't get set.
  77.  */
  78. if (dev->set_multicast_list == NULL ||
  79.     !netif_device_present(dev))
  80. return;
  81. dev->set_multicast_list(dev);
  82. }
  83. void dev_mc_upload(struct net_device *dev)
  84. {
  85. spin_lock_bh(&dev->xmit_lock);
  86. __dev_mc_upload(dev);
  87. spin_unlock_bh(&dev->xmit_lock);
  88. }
  89. /*
  90.  * Delete a device level multicast
  91.  */
  92.  
  93. int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl)
  94. {
  95. int err = 0;
  96. struct dev_mc_list *dmi, **dmip;
  97. spin_lock_bh(&dev->xmit_lock);
  98. for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) {
  99. /*
  100.  * Find the entry we want to delete. The device could
  101.  * have variable length entries so check these too.
  102.  */
  103. if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
  104.     alen == dmi->dmi_addrlen) {
  105. if (glbl) {
  106. int old_glbl = dmi->dmi_gusers;
  107. dmi->dmi_gusers = 0;
  108. if (old_glbl == 0)
  109. break;
  110. }
  111. if (--dmi->dmi_users)
  112. goto done;
  113. /*
  114.  * Last user. So delete the entry.
  115.  */
  116. *dmip = dmi->next;
  117. dev->mc_count--;
  118. kfree(dmi);
  119. /*
  120.  * We have altered the list, so the card
  121.  * loaded filter is now wrong. Fix it
  122.  */
  123. __dev_mc_upload(dev);
  124. spin_unlock_bh(&dev->xmit_lock);
  125. return 0;
  126. }
  127. }
  128. err = -ENOENT;
  129. done:
  130. spin_unlock_bh(&dev->xmit_lock);
  131. return err;
  132. }
  133. /*
  134.  * Add a device level multicast
  135.  */
  136.  
  137. int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
  138. {
  139. int err = 0;
  140. struct dev_mc_list *dmi, *dmi1;
  141. dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), GFP_ATOMIC);
  142. spin_lock_bh(&dev->xmit_lock);
  143. for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
  144. if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
  145.     dmi->dmi_addrlen == alen) {
  146. if (glbl) {
  147. int old_glbl = dmi->dmi_gusers;
  148. dmi->dmi_gusers = 1;
  149. if (old_glbl)
  150. goto done;
  151. }
  152. dmi->dmi_users++;
  153. goto done;
  154. }
  155. }
  156. if ((dmi = dmi1) == NULL) {
  157. spin_unlock_bh(&dev->xmit_lock);
  158. return -ENOMEM;
  159. }
  160. memcpy(dmi->dmi_addr, addr, alen);
  161. dmi->dmi_addrlen = alen;
  162. dmi->next = dev->mc_list;
  163. dmi->dmi_users = 1;
  164. dmi->dmi_gusers = glbl ? 1 : 0;
  165. dev->mc_list = dmi;
  166. dev->mc_count++;
  167. __dev_mc_upload(dev);
  168. spin_unlock_bh(&dev->xmit_lock);
  169. return 0;
  170. done:
  171. spin_unlock_bh(&dev->xmit_lock);
  172. if (dmi1)
  173. kfree(dmi1);
  174. return err;
  175. }
  176. /*
  177.  * Discard multicast list when a device is downed
  178.  */
  179. void dev_mc_discard(struct net_device *dev)
  180. {
  181. spin_lock_bh(&dev->xmit_lock);
  182. while (dev->mc_list != NULL) {
  183. struct dev_mc_list *tmp = dev->mc_list;
  184. dev->mc_list = tmp->next;
  185. if (tmp->dmi_users > tmp->dmi_gusers)
  186. printk("dev_mc_discard: multicast leakage! dmi_users=%dn", tmp->dmi_users);
  187. kfree(tmp);
  188. }
  189. dev->mc_count = 0;
  190. spin_unlock_bh(&dev->xmit_lock);
  191. }
  192. #ifdef CONFIG_PROC_FS
  193. static int dev_mc_read_proc(char *buffer, char **start, off_t offset,
  194.     int length, int *eof, void *data)
  195. {
  196. off_t pos = 0, begin = 0;
  197. struct dev_mc_list *m;
  198. int len = 0;
  199. struct net_device *dev;
  200. read_lock(&dev_base_lock);
  201. for (dev = dev_base; dev; dev = dev->next) {
  202. spin_lock_bh(&dev->xmit_lock);
  203. for (m = dev->mc_list; m; m = m->next) {
  204. int i;
  205. len += sprintf(buffer+len,"%-4d %-15s %-5d %-5d ", dev->ifindex,
  206.        dev->name, m->dmi_users, m->dmi_gusers);
  207. for (i = 0; i < m->dmi_addrlen; i++)
  208. len += sprintf(buffer+len, "%02x", m->dmi_addr[i]);
  209. len += sprintf(buffer+len, "n");
  210. pos = begin + len;
  211. if (pos < offset) {
  212. len = 0;
  213. begin = pos;
  214. }
  215. if (pos > offset + length) {
  216. spin_unlock_bh(&dev->xmit_lock);
  217. goto done;
  218. }
  219. }
  220. spin_unlock_bh(&dev->xmit_lock);
  221. }
  222. *eof = 1;
  223. done:
  224. read_unlock(&dev_base_lock);
  225. *start = buffer + (offset - begin);
  226. len -= (offset - begin);
  227. if (len > length)
  228. len = length;
  229. if (len < 0)
  230. len = 0;
  231. return len;
  232. }
  233. #endif
  234. void __init dev_mcast_init(void)
  235. {
  236. #ifdef CONFIG_PROC_FS
  237. create_proc_read_entry("net/dev_mcast", 0, 0, dev_mc_read_proc, NULL);
  238. #endif
  239. }